From 37dadc219da7f34c243c5c76c2eff2d3fa1f1051 Mon Sep 17 00:00:00 2001 From: "Jay Freeman (saurik)" Date: Fri, 8 Jan 2016 02:14:54 -0800 Subject: [PATCH 1/1] Fix multi-line template strings, removing ?expand. --- Complete.cpp | 2 +- Console.cpp | 36 ++------------ Execute.cpp | 8 ++-- ObjectiveC/Library.mm | 2 +- Output.cpp | 108 ++++++++++++++++++++++++++++++++++-------- Replace.cpp | 7 +++ Scanner.lpp.in | 4 +- Syntax.hpp | 11 ++++- cycript.hpp | 2 - 9 files changed, 119 insertions(+), 61 deletions(-) diff --git a/Complete.cpp b/Complete.cpp index 1d715d7..fcf8f5d 100644 --- a/Complete.cpp +++ b/Complete.cpp @@ -175,7 +175,7 @@ _visible char **CYComplete(const char *word, const std::string &line, CYUTF8Stri element = value->next_; _assert(value->value_ != NULL); - CYString *string(dynamic_cast(value->value_)); + CYString *string(value->value_->String(context)); if (string == NULL) CYThrow("string was actually %s", typeid(*value->value_).name()); diff --git a/Console.cpp b/Console.cpp index db86eb8..8a8277e 100644 --- a/Console.cpp +++ b/Console.cpp @@ -292,7 +292,7 @@ static CYUTF8String Run(CYPool &pool, int client, const std::string &code) { static std::ostream *out_; -static void Output(CYUTF8String json, std::ostream *out, bool expand = false, bool reparse = false) { +static void Output(CYUTF8String json, std::ostream *out, bool reparse = false) { CYPool pool; if (reparse) do { @@ -317,29 +317,7 @@ static void Output(CYUTF8String json, std::ostream *out, bool expand = false, bo if (data == NULL || out == NULL) return; - if (!expand || - data[0] != '@' && data[0] != '"' && data[0] != '\'' || - data[0] == '@' && data[1] != '"' && data[1] != '\'' - ) - CYLexerHighlight(data, size, *out); - else for (size_t i(0); i != size; ++i) - if (data[i] != '\\') - *out << data[i]; - else switch(data[++i]) { - case '\0': goto done; - case '\\': *out << '\\'; break; - case '\'': *out << '\''; break; - case '"': *out << '"'; break; - case 'b': *out << '\b'; break; - case 'f': *out << '\f'; break; - case 'n': *out << '\n'; break; - case 'r': *out << '\r'; break; - case 't': *out << '\t'; break; - case 'v': *out << '\v'; break; - default: *out << '\\'; --i; break; - } - - done: + CYLexerHighlight(data, size, *out); *out << std::endl; } @@ -629,9 +607,9 @@ static void CYConsolePrepTerm(int meta) { CYConsoleRemapKeys(vi_movement_keymap); } -static void CYOutputRun(const std::string &code, bool expand = false, bool reparse = false) { +static void CYOutputRun(const std::string &code, bool reparse = false) { CYPool pool; - Output(Run(pool, client_, code), &std::cout, expand, reparse); + Output(Run(pool, client_, code), &std::cout, reparse); } static void Console(CYOptions &options) { @@ -661,7 +639,6 @@ static void Console(CYOptions &options) { bool bypass(false); bool debug(false); - bool expand(false); bool lower(true); bool reparse(false); @@ -729,9 +706,6 @@ static void Console(CYOptions &options) { *out_ << "done." << std::endl; } else if (data == "exit") { return; - } else if (data == "expand") { - expand = !expand; - *out_ << "expand == " << (expand ? "true" : "false") << std::endl; } else if (data == "lower") { lower = !lower; *out_ << "lower == " << (lower ? "true" : "false") << std::endl; @@ -801,7 +775,7 @@ static void Console(CYOptions &options) { std::cout << std::endl; } - CYOutputRun(code, expand, reparse); + CYOutputRun(code, reparse); } } diff --git a/Execute.cpp b/Execute.cpp index 78aa32c..ac2fac1 100644 --- a/Execute.cpp +++ b/Execute.cpp @@ -483,7 +483,7 @@ const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, st case kJSTypeString: { std::ostringstream str; CYUTF8String string(CYPoolUTF8String(pool, context, CYJSString(context, value))); - CYStringify(str, string.data, string.size); + CYStringify(str, string.data, string.size, CYStringifyModeCycript); std::string value(str.str()); return pool.strmemdup(value.c_str(), value.size()); } break; @@ -573,7 +573,7 @@ const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object, if (CYIsKey(string)) str << string.data; else - CYStringify(str, string.data, string.size); + CYStringify(str, string.data, string.size, CYStringifyModeLegacy); str << ':'; @@ -644,7 +644,7 @@ static JSValueRef String_callAsFunction_toCYON(JSContextRef context, JSObjectRef std::ostringstream str; CYUTF8String string(CYPoolUTF8String(pool, context, CYJSString(context, _this))); - CYStringify(str, string.data, string.size); + CYStringify(str, string.data, string.size, CYStringifyModeCycript); std::string value(str.str()); return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size()))); @@ -1851,7 +1851,7 @@ static JSValueRef CString_callAsFunction_toCYON(JSContextRef context, JSObjectRe str << "NULL"; else { str << "&"; - CYStringify(str, string, strlen(string), true); + CYStringify(str, string, strlen(string), CYStringifyModeNative); } std::string value(str.str()); return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size()))); diff --git a/ObjectiveC/Library.mm b/ObjectiveC/Library.mm index 051f9b2..ac3a963 100644 --- a/ObjectiveC/Library.mm +++ b/ObjectiveC/Library.mm @@ -1149,7 +1149,7 @@ static bool CYBlockSignature(CYPool &pool, NSBlock *self, sig::Signature &signat if (!objective) str << '@'; CYUTF8String string(CYCastUTF8String(self)); - CYStringify(str, string.data, string.size, true); + CYStringify(str, string.data, string.size, CYStringifyModeNative); std::string value(str.str()); return CYCastNSString(NULL, CYUTF8String(value.c_str(), value.size())); } diff --git a/Output.cpp b/Output.cpp index 2c2ef36..a2e3213 100644 --- a/Output.cpp +++ b/Output.cpp @@ -25,41 +25,106 @@ #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; + } + + 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 << (single ? '\'' : '"'); + 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 '\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; @@ -93,9 +158,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 << border; - str << (single ? '\'' : '"'); + if (parens) + str << ')'; } void CYNumerify(std::ostringstream &str, double value) { @@ -948,7 +1016,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(); } diff --git a/Replace.cpp b/Replace.cpp index c268182..bfcacf4 100644 --- a/Replace.cpp +++ b/Replace.cpp @@ -1173,6 +1173,13 @@ CYTarget *CYTemplate::Replace(CYContext &context) { return $C2($M($M($M($V("String"), $S("prototype")), $S("concat")), $S("apply")), $S(""), $ CYArray($ CYElementValue(string_, spans_->Replace(context)))); } +CYString *CYTemplate::String(CYContext &context) { + // XXX: implement this over local concat + if (spans_ != NULL) + return NULL; + return string_; +} + CYTarget *CYThis::Replace(CYContext &context) { if (context.this_ != NULL) return $V(context.this_->Identifier(context)); diff --git a/Scanner.lpp.in b/Scanner.lpp.in index 58cfd7d..d9614df 100644 --- a/Scanner.lpp.in +++ b/Scanner.lpp.in @@ -606,8 +606,10 @@ XMLName {XMLNameStart}{XMLNamePart}* "$" R CYLexBufferUnit('$'); {PlateCharacter}+ R CYLexBufferUnits(yytext, yyleng); - {PlateCharacter}*{LineTerminatorSequence} R E("invalid newline"); {PlateCharacter}*{UnicodeScrap} R E("invalid character"); + + {PlateCharacter}*{LineTerminatorSequence} yylloc->end.Lines(); CYLexBufferUnits(yytext, yyleng); + \\{LineTerminatorSequence} yylloc->end.Lines(); } /* }}} */ /* Escapes {{{ */ diff --git a/Syntax.hpp b/Syntax.hpp index ea55a3f..a3dad90 100644 --- a/Syntax.hpp +++ b/Syntax.hpp @@ -40,7 +40,14 @@ double CYCastDouble(const char *value); double CYCastDouble(CYUTF8String value); void CYNumerify(std::ostringstream &str, double value); -void CYStringify(std::ostringstream &str, const char *data, size_t size, bool c = false); + +enum CYStringifyMode { + CYStringifyModeLegacy, + CYStringifyModeCycript, + CYStringifyModeNative, +}; + +void CYStringify(std::ostringstream &str, const char *data, size_t size, CYStringifyMode mode); // XXX: this really should not be here ... :/ void *CYPoolFile(CYPool &pool, const char *path, size_t *psize); @@ -839,6 +846,8 @@ struct CYTemplate : CYPrecedence(0) + virtual CYString *String(CYContext &context); + virtual CYTarget *Replace(CYContext &context); virtual void Output(CYOutput &out, CYFlags flags) const; }; diff --git a/cycript.hpp b/cycript.hpp index 56ad5d1..44958f8 100644 --- a/cycript.hpp +++ b/cycript.hpp @@ -51,8 +51,6 @@ CYPool &CYGetGlobalPool(); char **CYComplete(const char *word, const std::string &line, CYUTF8String (*run)(CYPool &pool, const std::string &)); -void CYStringify(std::ostringstream &str, const char *data, size_t size, bool c); - const char *CYPoolLibraryPath(CYPool &pool); #endif/*CYCRIPT_HPP*/ -- 2.47.2