| /* |
| * Copyright 2019 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/private/SkSLString.h" |
| #include "src/sksl/SkSLASTNode.h" |
| #include "src/sksl/SkSLOperators.h" |
| |
| namespace SkSL { |
| |
| #ifdef SK_DEBUG |
| String ASTNode::description() const { |
| switch (fKind) { |
| case Kind::kNull: return ""; |
| case Kind::kBinary: |
| return "(" + this->begin()->description() + " " + |
| getOperator().operatorName() + " " + |
| (this->begin() + 1)->description() + ")"; |
| case Kind::kBlock: { |
| String result = "{\n"; |
| for (const auto& c : *this) { |
| result += c.description(); |
| result += "\n"; |
| } |
| result += "}"; |
| return result; |
| } |
| case Kind::kBool: |
| return getBool() ? "true" : "false"; |
| case Kind::kBreak: |
| return "break"; |
| case Kind::kCall: { |
| auto iter = this->begin(); |
| String result = (iter++)->description(); |
| result += "("; |
| const char* separator = ""; |
| while (iter != this->end()) { |
| result += separator; |
| result += (iter++)->description(); |
| separator = ","; |
| } |
| result += ")"; |
| return result; |
| } |
| case Kind::kContinue: |
| return "continue"; |
| case Kind::kDiscard: |
| return "discard"; |
| case Kind::kDo: |
| return "do " + this->begin()->description() + " while (" + |
| (this->begin() + 1)->description() + ")"; |
| case Kind::kExtension: |
| return "#extension " + getStringView(); |
| case Kind::kField: |
| return this->begin()->description() + "." + getStringView(); |
| case Kind::kFile: { |
| String result; |
| for (const auto& c : *this) { |
| result += c.description(); |
| result += "\n"; |
| } |
| return result; |
| } |
| case Kind::kFloat: |
| return to_string(getFloat()); |
| case Kind::kFor: |
| return "for (" + this->begin()->description() + "; " + |
| (this->begin() + 1)->description() + "; " + (this->begin() + 2)->description() + |
| ") " + (this->begin() + 3)->description(); |
| case Kind::kFunction: { |
| const FunctionData& fd = getFunctionData(); |
| String result = fd.fModifiers.description(); |
| if (result.size()) { |
| result += " "; |
| } |
| auto iter = this->begin(); |
| result += (iter++)->description() + " " + fd.fName + "("; |
| const char* separator = ""; |
| for (size_t i = 0; i < fd.fParameterCount; ++i) { |
| result += separator; |
| result += (iter++)->description(); |
| separator = ", "; |
| } |
| result += ")"; |
| if (iter != this->end()) { |
| result += " " + (iter++)->description(); |
| SkASSERT(iter == this->end()); |
| } |
| else { |
| result += ";"; |
| } |
| return result; |
| } |
| case Kind::kIdentifier: |
| return String(getStringView()); |
| case Kind::kIndex: |
| return this->begin()->description() + "[" + (this->begin() + 1)->description() + "]"; |
| case Kind::kIf: { |
| String result; |
| if (getBool()) { |
| result = "@"; |
| } |
| auto iter = this->begin(); |
| result += "if (" + (iter++)->description() + ") "; |
| result += (iter++)->description(); |
| if (iter != this->end()) { |
| result += " else " + (iter++)->description(); |
| SkASSERT(iter == this->end()); |
| } |
| return result; |
| } |
| case Kind::kInt: |
| return to_string(getInt()); |
| case Kind::kInterfaceBlock: { |
| const InterfaceBlockData& id = getInterfaceBlockData(); |
| String result = id.fModifiers.description() + " " + id.fTypeName + " {\n"; |
| auto iter = this->begin(); |
| for (size_t i = 0; i < id.fDeclarationCount; ++i) { |
| result += (iter++)->description() + "\n"; |
| } |
| result += "} "; |
| result += id.fInstanceName; |
| if (id.fIsArray) { |
| result += "[" + (iter++)->description() + "]"; |
| } |
| SkASSERT(iter == this->end()); |
| result += ";"; |
| return result; |
| } |
| case Kind::kModifiers: |
| return getModifiers().description(); |
| case Kind::kParameter: { |
| const ParameterData& pd = getParameterData(); |
| auto iter = this->begin(); |
| String result = (iter++)->description() + " " + pd.fName; |
| if (pd.fIsArray) { |
| result += "[" + (iter++)->description() + "]"; |
| } |
| if (iter != this->end()) { |
| result += " = " + (iter++)->description(); |
| SkASSERT(iter == this->end()); |
| } |
| return result; |
| } |
| case Kind::kPostfix: |
| return this->begin()->description() + getOperator().operatorName(); |
| case Kind::kPrefix: |
| return getOperator().operatorName() + this->begin()->description(); |
| case Kind::kReturn: |
| if (this->begin() != this->end()) { |
| return "return " + this->begin()->description() + ";"; |
| } |
| return "return;"; |
| case Kind::kSwitchCase: { |
| auto iter = this->begin(); |
| String result; |
| if (*iter) { |
| result.appendf("case %s:\n", iter->description().c_str()); |
| } else { |
| result = "default:\n"; |
| } |
| for (++iter; iter != this->end(); ++iter) { |
| result += "\n" + iter->description(); |
| } |
| return result; |
| } |
| case Kind::kSwitch: { |
| auto iter = this->begin(); |
| String result; |
| if (getBool()) { |
| result = "@"; |
| } |
| result += "switch (" + (iter++)->description() + ") {"; |
| for (; iter != this->end(); ++iter) { |
| result += iter->description() + "\n"; |
| } |
| result += "}"; |
| return result; |
| } |
| case Kind::kTernary: |
| return "(" + this->begin()->description() + " ? " + (this->begin() + 1)->description() + |
| " : " + (this->begin() + 2)->description() + ")"; |
| case Kind::kType: |
| return String(getStringView()); |
| case Kind::kVarDeclaration: { |
| const VarData& vd = getVarData(); |
| String result(vd.fName); |
| auto iter = this->begin(); |
| if (vd.fIsArray) { |
| result += "[" + (iter++)->description() + "]"; |
| } |
| if (iter != this->end()) { |
| result += " = " + (iter++)->description(); |
| SkASSERT(iter == this->end()); |
| } |
| return result; |
| } |
| case Kind::kVarDeclarations: { |
| auto iter = this->begin(); |
| String result = (iter++)->description(); |
| if (result.size()) { |
| result += " "; |
| } |
| result += (iter++)->description(); |
| const char* separator = " "; |
| for (; iter != this->end(); ++iter) { |
| result += separator + iter->description(); |
| separator = ", "; |
| } |
| return result; |
| } |
| case Kind::kWhile: { |
| return "while (" + this->begin()->description() + ") " + |
| (this->begin() + 1)->description(); |
| |
| } |
| default: |
| SkDEBUGFAIL("unrecognized AST node kind"); |
| return "<error>"; |
| } |
| } |
| #endif |
| |
| } // namespace SkSL |