text: /*
   * Copyright 2016 Google Inc.
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #ifndef SKSL_METALCODEGENERATOR
  #define SKSL_METALCODEGENERATOR
  
  #include "include/private/SkTHash.h"
  #include "src/sksl/SkSLOperators.h"
  #include "src/sksl/SkSLStringStream.h"
  #include "src/sksl/codegen/SkSLCodeGenerator.h"
  
  namespace SkSL {
  
  class BinaryExpression;
  class Block;
  class ConstructorArrayCast;
  class ConstructorCompound;
  class ConstructorMatrixResize;
  class DoStatement;
  class ExpressionStatement;
  class Extension;
  class FieldAccess;
  class ForStatement;
  class FunctionCall;
  class FunctionDeclaration;
  class FunctionDefinition;
  class FunctionPrototype;
  class IfStatement;
  struct IndexExpression;
  class InterfaceBlock;
  enum IntrinsicKind : int8_t;
  class Literal;
  class PostfixExpression;
  class PrefixExpression;
  class ReturnStatement;
  class Setting;
  class StructDefinition;
  class SwitchStatement;
  struct Swizzle;
  class TernaryExpression;
  class VarDeclaration;
  class VariableReference;
  
  /**
   * Converts a Program into Metal code.
   */
  class MetalCodeGenerator : public CodeGenerator {
  public:
      inline static constexpr const char* SAMPLER_SUFFIX = "Smplr";
      inline static constexpr const char* PACKED_PREFIX = "packed_";
  
      MetalCodeGenerator(const Context* context, const Program* program, OutputStream* out)
      : INHERITED(context, program, out)
      , fReservedWords({"atan2", "rsqrt", "rint", "dfdx", "dfdy", "vertex", "fragment"})
      , fLineEnding("\n") {}
  
      bool generateCode() override;
  
  protected:
      using Precedence = Operator::Precedence;
  
      typedef int Requirements;
      inline static constexpr Requirements kNo_Requirements       = 0;
      inline static constexpr Requirements kInputs_Requirement    = 1 << 0;
      inline static constexpr Requirements kOutputs_Requirement   = 1 << 1;
      inline static constexpr Requirements kUniforms_Requirement  = 1 << 2;
      inline static constexpr Requirements kGlobals_Requirement   = 1 << 3;
      inline static constexpr Requirements kFragCoord_Requirement = 1 << 4;
  
      class GlobalStructVisitor;
      void visitGlobalStruct(GlobalStructVisitor* visitor);
  
      void write(std::string_view s);
  
      void writeLine(std::string_view s = std::string_view());
  
      void finishLine();
  
      void writeHeader();
  
      void writeUniformStruct();
  
      void writeInputStruct();
  
      void writeOutputStruct();
  
      void writeInterfaceBlocks();
  
      void writeStructDefinitions();
  
      void writeFields(const std::vector<Type::Field>& fields, Position pos,
                       const InterfaceBlock* parentIntf = nullptr);
  
      int size(const Type* type, bool isPacked) const;
  
      int alignment(const Type* type, bool isPacked) const;
  
      void writeGlobalStruct();
  
      void writeGlobalInit();
  
      void writePrecisionModifier();
  
      std::string typeName(const Type& type);
  
      void writeStructDefinition(const StructDefinition& s);
  
      void writeType(const Type& type);
  
      void writeExtension(const Extension& ext);
  
      void writeInterfaceBlock(const InterfaceBlock& intf);
  
      void writeFunctionStart(const FunctionDeclaration& f);
  
      void writeFunctionRequirementParams(const FunctionDeclaration& f,
                                          const char*& separator);
  
      void writeFunctionRequirementArgs(const FunctionDeclaration& f, const char*& separator);
  
      bool writeFunctionDeclaration(const FunctionDeclaration& f);
  
      void writeFunction(const FunctionDefinition& f);
  
      void writeFunctionPrototype(const FunctionPrototype& f);
  
      void writeLayout(const Layout& layout);
  
      void writeModifiers(const Modifiers& modifiers);
  
      void writeVarInitializer(const Variable& var, const Expression& value);
  
      void writeName(std::string_view name);
  
      void writeVarDeclaration(const VarDeclaration& decl);
  
      void writeFragCoord();
  
      void writeVariableReference(const VariableReference& ref);
  
      void writeExpression(const Expression& expr, Precedence parentPrecedence);
  
      void writeMinAbsHack(Expression& absExpr, Expression& otherExpr);
  
      std::string getOutParamHelper(const FunctionCall& c,
                               const ExpressionArray& arguments,
                               const SkTArray<VariableReference*>& outVars);
  
      std::string getInversePolyfill(const ExpressionArray& arguments);
  
      std::string getBitcastIntrinsic(const Type& outType);
  
      std::string getTempVariable(const Type& varType);
  
      void writeFunctionCall(const FunctionCall& c);
  
      bool matrixConstructHelperIsNeeded(const ConstructorCompound& c);
      std::string getMatrixConstructHelper(const AnyConstructor& c);
      void assembleMatrixFromMatrix(const Type& sourceMatrix, int rows, int columns);
      void assembleMatrixFromExpressions(const AnyConstructor& ctor, int rows, int columns);
  
      void writeMatrixCompMult();
  
      void writeOuterProduct();
  
      void writeMatrixTimesEqualHelper(const Type& left, const Type& right, const Type& result);
  
      void writeMatrixDivisionHelpers(const Type& type);
  
      void writeMatrixEqualityHelpers(const Type& left, const Type& right);
  
      std::string getVectorFromMat2x2ConstructorHelper(const Type& matrixType);
  
      void writeArrayEqualityHelpers(const Type& type);
  
      void writeStructEqualityHelpers(const Type& type);
  
      void writeEqualityHelpers(const Type& leftType, const Type& rightType);
  
      void writeArgumentList(const ExpressionArray& arguments);
  
      void writeSimpleIntrinsic(const FunctionCall& c);
  
      bool writeIntrinsicCall(const FunctionCall& c, IntrinsicKind kind);
  
      void writeConstructorCompound(const ConstructorCompound& c, Precedence parentPrecedence);
  
      void writeConstructorCompoundVector(const ConstructorCompound& c, Precedence parentPrecedence);
  
      void writeConstructorCompoundMatrix(const ConstructorCompound& c, Precedence parentPrecedence);
  
      void writeConstructorMatrixResize(const ConstructorMatrixResize& c,
                                        Precedence parentPrecedence);
  
      void writeAnyConstructor(const AnyConstructor& c,
                               const char* leftBracket,
                               const char* rightBracket,
                               Precedence parentPrecedence);
  
      void writeCastConstructor(const AnyConstructor& c,
                                const char* leftBracket,
                                const char* rightBracket,
                                Precedence parentPrecedence);
  
      void writeConstructorArrayCast(const ConstructorArrayCast& c, Precedence parentPrecedence);
  
      void writeFieldAccess(const FieldAccess& f);
  
      void writeSwizzle(const Swizzle& swizzle);
  
      // Splats a scalar expression across a matrix of arbitrary size.
      void writeNumberAsMatrix(const Expression& expr, const Type& matrixType);
  
      void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence);
  
      void writeTernaryExpression(const TernaryExpression& t, Precedence parentPrecedence);
  
      void writeIndexExpression(const IndexExpression& expr);
  
      void writePrefixExpression(const PrefixExpression& p, Precedence parentPrecedence);
  
      void writePostfixExpression(const PostfixExpression& p, Precedence parentPrecedence);
  
      void writeLiteral(const Literal& f);
  
      void writeSetting(const Setting& s);
  
      void writeStatement(const Statement& s);
  
      void writeStatements(const StatementArray& statements);
  
      void writeBlock(const Block& b);
  
      void writeIfStatement(const IfStatement& stmt);
  
      void writeForStatement(const ForStatement& f);
  
      void writeDoStatement(const DoStatement& d);
  
      void writeExpressionStatement(const ExpressionStatement& s);
  
      void writeSwitchStatement(const SwitchStatement& s);
  
      void writeReturnStatementFromMain();
  
      void writeReturnStatement(const ReturnStatement& r);
  
      void writeProgramElement(const ProgramElement& e);
  
      Requirements requirements(const FunctionDeclaration& f);
  
      Requirements requirements(const Expression* e);
  
      Requirements requirements(const Statement* s);
  
      int getUniformBinding(const Modifiers& m);
  
      int getUniformSet(const Modifiers& m);
  
      SkTHashSet<std::string_view> fReservedWords;
      SkTHashMap<const Type::Field*, const InterfaceBlock*> fInterfaceBlockMap;
      SkTHashMap<const InterfaceBlock*, std::string_view> fInterfaceBlockNameMap;
      int fAnonInterfaceCount = 0;
      int fPaddingCount = 0;
      const char* fLineEnding;
      std::string fFunctionHeader;
      StringStream fExtraFunctions;
      StringStream fExtraFunctionPrototypes;
      int fVarCount = 0;
      int fIndentation = 0;
      bool fAtLineStart = false;
      std::set<std::string> fWrittenIntrinsics;
      // true if we have run into usages of dFdx / dFdy
      bool fFoundDerivatives = false;
      SkTHashMap<const FunctionDeclaration*, Requirements> fRequirements;
      bool fSetupFragPositionGlobal = false;
      bool fSetupFragPositionLocal = false;
      SkTHashSet<std::string> fHelpers;
      int fUniformBuffer = -1;
      std::string fRTFlipName;
      const FunctionDeclaration* fCurrentFunction = nullptr;
      int fSwizzleHelperCount = 0;
      bool fIgnoreVariableReferenceModifiers = false;
  
      using INHERITED = CodeGenerator;
  };
  
  }  // namespace SkSL
  
  #endif
  