| // Copyright 2017 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <algorithm> |
| #include <fstream> |
| #include <iostream> |
| #include <string> |
| |
| #include "src/base/logging.h" |
| #include "src/torque/ast.h" |
| #include "src/torque/utils.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace torque { |
| |
| DEFINE_CONTEXTUAL_VARIABLE(TorqueMessages) |
| |
| std::string StringLiteralUnquote(const std::string& s) { |
| DCHECK(('"' == s.front() && '"' == s.back()) || |
| ('\'' == s.front() && '\'' == s.back())); |
| std::stringstream result; |
| for (size_t i = 1; i < s.length() - 1; ++i) { |
| if (s[i] == '\\') { |
| switch (s[++i]) { |
| case 'n': |
| result << '\n'; |
| break; |
| case 'r': |
| result << '\r'; |
| break; |
| case 't': |
| result << '\t'; |
| break; |
| case '\'': |
| case '"': |
| case '\\': |
| result << s[i]; |
| break; |
| default: |
| UNREACHABLE(); |
| } |
| } else { |
| result << s[i]; |
| } |
| } |
| return result.str(); |
| } |
| |
| std::string StringLiteralQuote(const std::string& s) { |
| std::stringstream result; |
| result << '"'; |
| for (size_t i = 0; i < s.length(); ++i) { |
| switch (s[i]) { |
| case '\n': |
| result << "\\n"; |
| break; |
| case '\r': |
| result << "\\r"; |
| break; |
| case '\t': |
| result << "\\t"; |
| break; |
| case '"': |
| case '\\': |
| result << "\\" << s[i]; |
| break; |
| default: |
| result << s[i]; |
| } |
| } |
| result << '"'; |
| return result.str(); |
| } |
| |
| #ifdef V8_OS_WIN |
| static const char kFileUriPrefix[] = "file:///"; |
| #else |
| static const char kFileUriPrefix[] = "file://"; |
| #endif |
| static const int kFileUriPrefixLength = sizeof(kFileUriPrefix) - 1; |
| |
| static int HexCharToInt(unsigned char c) { |
| if (isdigit(c)) return c - '0'; |
| if (isupper(c)) return c - 'A' + 10; |
| DCHECK(islower(c)); |
| return c - 'a' + 10; |
| } |
| |
| base::Optional<std::string> FileUriDecode(const std::string& uri) { |
| // Abort decoding of URIs that don't start with "file://". |
| if (uri.rfind(kFileUriPrefix) != 0) return base::nullopt; |
| |
| const std::string path = uri.substr(kFileUriPrefixLength); |
| std::ostringstream decoded; |
| |
| for (auto iter = path.begin(), end = path.end(); iter != end; ++iter) { |
| std::string::value_type c = (*iter); |
| |
| // Normal characters are appended. |
| if (c != '%') { |
| decoded << c; |
| continue; |
| } |
| |
| // If '%' is not followed by at least two hex digits, we abort. |
| if (std::distance(iter, end) <= 2) return base::nullopt; |
| |
| unsigned char first = (*++iter); |
| unsigned char second = (*++iter); |
| if (!isxdigit(first) || !isxdigit(second)) return base::nullopt; |
| |
| // An escaped hex value needs converting. |
| unsigned char value = HexCharToInt(first) * 16 + HexCharToInt(second); |
| decoded << value; |
| } |
| |
| return decoded.str(); |
| } |
| |
| std::string CurrentPositionAsString() { |
| return PositionAsString(CurrentSourcePosition::Get()); |
| } |
| |
| MessageBuilder::MessageBuilder(const std::string& message, |
| TorqueMessage::Kind kind) { |
| base::Optional<SourcePosition> position; |
| if (CurrentSourcePosition::HasScope()) { |
| position = CurrentSourcePosition::Get(); |
| } |
| message_ = TorqueMessage{message, position, kind}; |
| } |
| |
| void MessageBuilder::Report() const { |
| TorqueMessages::Get().push_back(message_); |
| } |
| |
| [[noreturn]] void MessageBuilder::Throw() const { |
| throw TorqueAbortCompilation{}; |
| } |
| |
| namespace { |
| |
| bool ContainsUnderscore(const std::string& s) { |
| if (s.empty()) return false; |
| return s.find("_") != std::string::npos; |
| } |
| |
| bool ContainsUpperCase(const std::string& s) { |
| if (s.empty()) return false; |
| return std::any_of(s.begin(), s.end(), [](char c) { return isupper(c); }); |
| } |
| |
| // Torque has some namespace constants that are used like language level |
| // keywords, e.g.: 'True', 'Undefined', etc. |
| // These do not need to follow the default naming convention for constants. |
| bool IsKeywordLikeName(const std::string& s) { |
| static const char* const keyword_like_constants[]{"True", "False", "TheHole", |
| "Null", "Undefined"}; |
| |
| return std::find(std::begin(keyword_like_constants), |
| std::end(keyword_like_constants), |
| s) != std::end(keyword_like_constants); |
| } |
| |
| // Untagged/MachineTypes like 'int32', 'intptr' etc. follow a 'all-lowercase' |
| // naming convention and are those exempt from the normal type convention. |
| bool IsMachineType(const std::string& s) { |
| static const char* const machine_types[]{ |
| "void", "never", "int8", "uint8", "int16", "uint16", |
| "int31", "uint31", "int32", "uint32", "int64", "intptr", |
| "uintptr", "float32", "float64", "bool", "string", "bint"}; |
| |
| return std::find(std::begin(machine_types), std::end(machine_types), s) != |
| std::end(machine_types); |
| } |
| |
| } // namespace |
| |
| bool IsLowerCamelCase(const std::string& s) { |
| if (s.empty()) return false; |
| size_t start = 0; |
| if (s[0] == '_') start = 1; |
| return islower(s[start]) && !ContainsUnderscore(s.substr(start)); |
| } |
| |
| bool IsUpperCamelCase(const std::string& s) { |
| if (s.empty()) return false; |
| size_t start = 0; |
| if (s[0] == '_') start = 1; |
| return isupper(s[start]) && !ContainsUnderscore(s.substr(1)); |
| } |
| |
| bool IsSnakeCase(const std::string& s) { |
| if (s.empty()) return false; |
| return !ContainsUpperCase(s); |
| } |
| |
| bool IsValidNamespaceConstName(const std::string& s) { |
| if (s.empty()) return false; |
| if (IsKeywordLikeName(s)) return true; |
| |
| return s[0] == 'k' && IsUpperCamelCase(s.substr(1)); |
| } |
| |
| bool IsValidTypeName(const std::string& s) { |
| if (s.empty()) return false; |
| if (IsMachineType(s)) return true; |
| |
| return IsUpperCamelCase(s); |
| } |
| |
| std::string CapifyStringWithUnderscores(const std::string& camellified_string) { |
| std::string result; |
| bool previousWasLower = false; |
| for (auto current : camellified_string) { |
| if (previousWasLower && isupper(current)) { |
| result += "_"; |
| } |
| if (current == '.' || current == '-') { |
| result += "_"; |
| previousWasLower = false; |
| continue; |
| } |
| result += toupper(current); |
| previousWasLower = (islower(current)); |
| } |
| return result; |
| } |
| |
| std::string CamelifyString(const std::string& underscore_string) { |
| std::string result; |
| bool word_beginning = true; |
| for (auto current : underscore_string) { |
| if (current == '_' || current == '-') { |
| word_beginning = true; |
| continue; |
| } |
| if (word_beginning) { |
| current = toupper(current); |
| } |
| result += current; |
| word_beginning = false; |
| } |
| return result; |
| } |
| |
| std::string SnakeifyString(const std::string& camel_string) { |
| std::string result; |
| bool previousWasLower = false; |
| for (auto current : camel_string) { |
| if (previousWasLower && isupper(current)) { |
| result += "_"; |
| } |
| result += tolower(current); |
| previousWasLower = (islower(current)); |
| } |
| return result; |
| } |
| |
| std::string DashifyString(const std::string& underscore_string) { |
| std::string result = underscore_string; |
| std::replace(result.begin(), result.end(), '_', '-'); |
| return result; |
| } |
| |
| std::string UnderlinifyPath(std::string path) { |
| std::replace(path.begin(), path.end(), '-', '_'); |
| std::replace(path.begin(), path.end(), '/', '_'); |
| std::replace(path.begin(), path.end(), '\\', '_'); |
| std::replace(path.begin(), path.end(), '.', '_'); |
| transform(path.begin(), path.end(), path.begin(), ::toupper); |
| return path; |
| } |
| |
| void ReplaceFileContentsIfDifferent(const std::string& file_path, |
| const std::string& contents) { |
| std::ifstream old_contents_stream(file_path.c_str()); |
| std::string old_contents; |
| if (old_contents_stream.good()) { |
| std::istreambuf_iterator<char> eos; |
| old_contents = |
| std::string(std::istreambuf_iterator<char>(old_contents_stream), eos); |
| old_contents_stream.close(); |
| } |
| if (old_contents.length() == 0 || old_contents != contents) { |
| std::ofstream new_contents_stream; |
| new_contents_stream.open(file_path.c_str()); |
| new_contents_stream << contents; |
| new_contents_stream.close(); |
| } |
| } |
| |
| } // namespace torque |
| } // namespace internal |
| } // namespace v8 |