X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/5b4dabb2071e2e09cd70a156beed03b12bec477a..2c4a8bb6222b88ff96fbf25372179646ce15f706:/Output.cpp diff --git a/Output.cpp b/Output.cpp index 2c2ef36..26e49fe 100644 --- a/Output.cpp +++ b/Output.cpp @@ -25,47 +25,118 @@ #include "Syntax.hpp" -void CYStringify(std::ostringstream &str, const char *data, size_t size, bool c) { - bool single; - if (c) - single = false; +enum CYStringType { + CYStringTypeSingle, + CYStringTypeDouble, + CYStringTypeTemplate, +}; + +void CYStringify(std::ostringstream &str, const char *data, size_t size, CYStringifyMode mode) { + if (size == 0) { + str << "\"\""; + return; + } + + unsigned quot(0), apos(0), tick(0), line(0); + for (const char *value(data), *end(data + size); value != end; ++value) + switch (*value) { + case '"': ++quot; break; + case '\'': ++apos; break; + case '`': ++tick; break; + case '$': ++tick; break; + case '\n': ++line; break; + } + + bool split; + if (mode != CYStringifyModeCycript) + split = false; else { - unsigned quot(0), apos(0); - for (const char *value(data), *end(data + size); value != end; ++value) - if (*value == '"') - ++quot; - else if (*value == '\'') - ++apos; - - single = quot > apos; + double ratio(double(line) / size); + split = size > 10 && line > 2 && ratio > 0.005 && ratio < 0.10; } - str << (single ? '\'' : '"'); + CYStringType type; + if (mode == CYStringifyModeNative) + type = CYStringTypeDouble; + else if (split) + type = CYStringTypeTemplate; + else if (quot > apos) + type = CYStringTypeSingle; + else + type = CYStringTypeDouble; + + bool parens(split && mode != CYStringifyModeNative && type != CYStringTypeTemplate); + if (parens) + str << '('; + + char border; + switch (type) { + case CYStringTypeSingle: border = '\''; break; + case CYStringTypeDouble: border = '"'; break; + case CYStringTypeTemplate: border = '`'; break; + } + + str << border; + + bool space(false); for (const char *value(data), *end(data + size); value != end; ++value) - switch (uint8_t next = *value) { + if (*value == ' ') { + space = true; + str << ' '; + } else { switch (uint8_t next = *value) { case '\\': str << "\\\\"; break; case '\b': str << "\\b"; break; case '\f': str << "\\f"; break; - case '\n': str << "\\n"; break; case '\r': str << "\\r"; break; case '\t': str << "\\t"; break; case '\v': str << "\\v"; break; + case '\a': + if (mode == CYStringifyModeNative) + str << "\\a"; + else goto simple; + break; + + case '\n': + if (!split) + str << "\\n"; + /*else if (mode == CYStringifyModeNative) + str << border << "\\\n" << border;*/ + else if (type != CYStringTypeTemplate) + str << border << '+' << border; + else if (!space) + str << '\n'; + else + str << "\\n\\\n"; + break; + + case '$': + if (type == CYStringTypeTemplate) + str << "\\$"; + else goto simple; + break; + + case '`': + if (type == CYStringTypeTemplate) + str << "\\`"; + else goto simple; + break; + case '"': - if (!single) + if (type == CYStringTypeDouble) str << "\\\""; else goto simple; break; case '\'': - if (single) + if (type == CYStringTypeSingle) str << "\\'"; else goto simple; break; case '\0': - if (value[1] >= '0' && value[1] <= '9') + if (mode != CYStringifyModeNative && value[1] >= '0' && value[1] <= '9') str << "\\x00"; else str << "\\0"; @@ -74,6 +145,8 @@ void CYStringify(std::ostringstream &str, const char *data, size_t size, bool c) default: if (next >= 0x20 && next < 0x7f) simple: str << *value; + else if (mode == CYStringifyModeNative) + str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << unsigned(*value & 0xff); else { unsigned levels(1); if ((next & 0x80) != 0) @@ -93,9 +166,12 @@ void CYStringify(std::ostringstream &str, const char *data, size_t size, bool c) str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xdc00 | point & 0x3ff); } } - } + } space = false; } - str << (single ? '\'' : '"'); + str << border; + + if (parens) + str << ')'; } void CYNumerify(std::ostringstream &str, double value) { @@ -226,6 +302,14 @@ void CYAssignment::Output(CYOutput &out, CYFlags flags) const { rhs_->Output(out, Precedence(), CYRight(flags)); } +void CYAttemptMember::Output(CYOutput &out, CYFlags flags) const { + object_->Output(out, Precedence(), CYLeft(flags) | CYNoInteger); + if (const char *word = property_->Word()) + out << "?." << word; + else + _assert(false); +} + void CYBlock::Output(CYOutput &out, CYFlags flags) const { out << '{' << '\n'; ++out.indent_; @@ -948,7 +1032,7 @@ void CYStatement::Single(CYOutput &out, CYFlags flags, CYCompactType request) co void CYString::Output(CYOutput &out, CYFlags flags) const { std::ostringstream str; - CYStringify(str, value_, size_); + CYStringify(str, value_, size_, CYStringifyModeLegacy); out << str.str().c_str(); } @@ -1109,6 +1193,15 @@ void CYTypeError::Output(CYOutput &out) const { out << "@error"; } +void CYTypeFloating::Output(CYOutput &out) const { + switch (length_) { + case 0: out << "float"; break; + case 1: out << "double"; break; + case 2: out << "long" << ' ' << "double"; break; + default: _assert(false); + } +} + void CYTypeInt128::Output(CYOutput &out) const { switch (signing_) { case CYTypeNeutral: break;