X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/2fad14e52c8cde8c45003a2ebb6907a57ca380e4..217f652fdefefc86d562d49f9815001653f99075:/Output.cpp diff --git a/Output.cpp b/Output.cpp index c436b3c..50cc836 100644 --- a/Output.cpp +++ b/Output.cpp @@ -1,5 +1,5 @@ -/* Cycript - Optimizing JavaScript Compiler/Runtime - * Copyright (C) 2009-2015 Jay Freeman (saurik) +/* Cycript - The Truly Universal Scripting Language + * Copyright (C) 2009-2016 Jay Freeman (saurik) */ /* GNU Affero General Public License, Version 3 {{{ */ @@ -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; + } + + 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 '\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) { @@ -452,11 +528,23 @@ void CYExpression::Output(CYOutput &out, int precedence, CYFlags flags) const { Output(out, flags); } -void CYExternal::Output(CYOutput &out, CYFlags flags) const { - out << "extern" << abi_ << typed_; +void CYExtend::Output(CYOutput &out, CYFlags flags) const { + lhs_->Output(out, CYLeft(flags)); + out << ' ' << object_; +} + +void CYExternalDefinition::Output(CYOutput &out, CYFlags flags) const { + out << "extern" << ' ' << abi_ << ' '; + type_->Output(out, name_); out.Terminate(); } +void CYExternalExpression::Output(CYOutput &out, CYFlags flags) const { + out << '(' << "extern" << ' ' << abi_ << ' '; + type_->Output(out, name_); + out << ')'; +} + void CYFatArrow::Output(CYOutput &out, CYFlags flags) const { out << '(' << parameters_ << ')' << ' ' << "=>" << ' ' << '{' << code_ << '}'; } @@ -659,26 +747,26 @@ void CYTemplate::Output(CYOutput &out, CYFlags flags) const { _assert(false); } -void CYTypeArrayOf::Output(CYOutput &out, CYIdentifier *identifier) const { - next_->Output(out, Precedence(), identifier); +void CYTypeArrayOf::Output(CYOutput &out, CYPropertyName *name) const { + next_->Output(out, Precedence(), name, false); out << '['; out << size_; out << ']'; } -void CYTypeBlockWith::Output(CYOutput &out, CYIdentifier *identifier) const { +void CYTypeBlockWith::Output(CYOutput &out, CYPropertyName *name) const { out << '(' << '^'; - next_->Output(out, Precedence(), identifier); + next_->Output(out, Precedence(), name, false); out << ')' << '(' << parameters_ << ')'; } -void CYTypeConstant::Output(CYOutput &out, CYIdentifier *identifier) const { - out << "const" << ' '; - next_->Output(out, Precedence(), identifier); +void CYTypeConstant::Output(CYOutput &out, CYPropertyName *name) const { + out << "const"; + next_->Output(out, Precedence(), name, false); } -void CYTypeFunctionWith::Output(CYOutput &out, CYIdentifier *identifier) const { - next_->Output(out, Precedence(), identifier); +void CYTypeFunctionWith::Output(CYOutput &out, CYPropertyName *name) const { + next_->Output(out, Precedence(), name, false); out << '(' << parameters_; if (variadic_) { if (parameters_ != NULL) @@ -688,19 +776,24 @@ void CYTypeFunctionWith::Output(CYOutput &out, CYIdentifier *identifier) const { out << ')'; } -void CYTypePointerTo::Output(CYOutput &out, CYIdentifier *identifier) const { +void CYTypePointerTo::Output(CYOutput &out, CYPropertyName *name) const { out << '*'; - next_->Output(out, Precedence(), identifier); + next_->Output(out, Precedence(), name, false); } -void CYTypeVolatile::Output(CYOutput &out, CYIdentifier *identifier) const { +void CYTypeVolatile::Output(CYOutput &out, CYPropertyName *name) const { out << "volatile"; - next_->Output(out, Precedence(), identifier); + next_->Output(out, Precedence(), name, true); } -void CYTypeModifier::Output(CYOutput &out, int precedence, CYIdentifier *identifier) const { +void CYTypeModifier::Output(CYOutput &out, int precedence, CYPropertyName *name, bool space) const { + if (this == NULL && name == NULL) + return; + else if (space) + out << ' '; + if (this == NULL) { - out << identifier; + name->PropertyName(out); return; } @@ -708,14 +801,18 @@ void CYTypeModifier::Output(CYOutput &out, int precedence, CYIdentifier *identif if (protect) out << '('; - Output(out, identifier); + Output(out, name); if (protect) out << ')'; } -void CYTypedIdentifier::Output(CYOutput &out) const { - specifier_->Output(out); - modifier_->Output(out, 0, identifier_); +void CYType::Output(CYOutput &out, CYPropertyName *name) const { + out << *specifier_; + modifier_->Output(out, 0, name, true); +} + +void CYType::Output(CYOutput &out) const { + Output(out, NULL); } void CYEncodedType::Output(CYOutput &out, CYFlags flags) const { @@ -723,7 +820,7 @@ void CYEncodedType::Output(CYOutput &out, CYFlags flags) const { } void CYTypedParameter::Output(CYOutput &out) const { - out << typed_; + type_->Output(out, name_); if (next_ != NULL) out << ',' << ' ' << next_; } @@ -737,7 +834,8 @@ void CYLambda::Output(CYOutput &out, CYFlags flags) const { } void CYTypeDefinition::Output(CYOutput &out, CYFlags flags) const { - out << "typedef" << ' ' << *typed_; + out << "typedef" << ' '; + type_->Output(out, name_); out.Terminate(); } @@ -872,7 +970,7 @@ void CYReturn::Output(CYOutput &out, CYFlags flags) const { } void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const { - call_->Output(out, CYLeft(flags)); + lhs_->Output(out, CYLeft(flags)); out << ' '; proc_->Output(out, CYRight(flags)); } @@ -885,6 +983,11 @@ void CYRubyProc::Output(CYOutput &out, CYFlags flags) const { out << '\t' << '}'; } +void CYSubscriptMember::Output(CYOutput &out, CYFlags flags) const { + object_->Output(out, Precedence(), CYLeft(flags)); + out << "." << '[' << *property_ << ']'; +} + void CYStatement::Multiple(CYOutput &out, CYFlags flags) const { bool first(true); CYForEach (next, this) { @@ -921,7 +1024,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(); } @@ -975,12 +1078,13 @@ void CYStructTail::Output(CYOutput &out) const { out << ' ' << '{' << '\n'; ++out.indent_; CYForEach (field, fields_) { - out << '\t' << *field->typed_; + out << '\t'; + field->type_->Output(out, field->name_); out.Terminate(); out << '\n'; } --out.indent_; - out << '}'; + out << '\t' << '}'; } void CYSuperAccess::Output(CYOutput &out, CYFlags flags) const { @@ -1048,10 +1152,58 @@ void CYTypeCharacter::Output(CYOutput &out) const { out << "char"; } +void CYTypeEnum::Output(CYOutput &out) const { + out << "enum" << ' '; + if (name_ != NULL) + out << *name_; + else { + if (specifier_ != NULL) + out << ':' << ' ' << *specifier_ << ' '; + + out << '{' << '\n'; + ++out.indent_; + bool comma(false); + + CYForEach (constant, constants_) { + if (comma) + out << ',' << '\n'; + else + comma = true; + out << '\t' << constant->name_; + out << ' ' << '=' << ' ' << constant->value_; + } + + if (out.pretty_) + out << ','; + out << '\n'; + --out.indent_; + out << '\t' << '}'; + } +} + 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; + case CYTypeSigned: out << "signed" << ' '; break; + case CYTypeUnsigned: out << "unsigned" << ' '; break; + } + + out << "__int128"; +} + void CYTypeIntegral::Output(CYOutput &out) const { if (signing_ == CYTypeUnsigned) out << "unsigned" << ' '; @@ -1073,7 +1225,13 @@ void CYTypeStruct::Output(CYOutput &out) const { } void CYTypeReference::Output(CYOutput &out) const { - out << "struct" << ' ' << *name_; + switch (kind_) { + case CYTypeReferenceStruct: out << "struct"; break; + case CYTypeReferenceEnum: out << "enum"; break; + default: _assert(false); + } + + out << ' ' << *name_; } void CYTypeVariable::Output(CYOutput &out) const {