/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SKSL_SECTIONANDPARAMETERHELPER #define SKSL_SECTIONANDPARAMETERHELPER #include "SkSLErrorReporter.h" #include "ir/SkSLProgram.h" #include "ir/SkSLSection.h" #include "ir/SkSLVarDeclarations.h" #include <unordered_map> #include <vector> namespace SkSL { #define CLASS_SECTION "class" #define CLONE_SECTION "clone" #define CONSTRUCTOR_SECTION "constructor" #define CONSTRUCTOR_CODE_SECTION "constructorCode" #define CONSTRUCTOR_PARAMS_SECTION "constructorParams" #define COORD_TRANSFORM_SECTION "coordTransform" #define CPP_SECTION "cpp" #define CPP_END_SECTION "cppEnd" #define HEADER_SECTION "header" #define HEADER_END_SECTION "headerEnd" #define EMIT_CODE_SECTION "emitCode" #define FIELDS_SECTION "fields" #define INITIALIZERS_SECTION "initializers" #define MAKE_SECTION "make" #define OPTIMIZATION_FLAGS_SECTION "optimizationFlags" #define SAMPLER_PARAMS_SECTION "samplerParams" #define SET_DATA_SECTION "setData" #define TEST_CODE_SECTION "test" class SectionAndParameterHelper { public: SectionAndParameterHelper(const Program& program, ErrorReporter& errors) { for (const auto& p : program) { switch (p.fKind) { case ProgramElement::kVar_Kind: { const VarDeclarations& decls = (const VarDeclarations&) p; for (const auto& raw : decls.fVars) { const VarDeclaration& decl = (VarDeclaration&) *raw; if (IsParameter(*decl.fVar)) { fParameters.push_back(decl.fVar); } } break; } case ProgramElement::kSection_Kind: { const Section& s = (const Section&) p; if (IsSupportedSection(s.fName.c_str())) { if (SectionRequiresArgument(s.fName.c_str()) && !s.fArgument.size()) { errors.error(s.fOffset, ("section '@" + s.fName + "' requires one parameter").c_str()); } if (!SectionAcceptsArgument(s.fName.c_str()) && s.fArgument.size()) { errors.error(s.fOffset, ("section '@" + s.fName + "' has no parameters").c_str()); } } else { errors.error(s.fOffset, ("unsupported section '@" + s.fName + "'").c_str()); } if (!SectionPermitsDuplicates(s.fName.c_str()) && fSections.find(s.fName) != fSections.end()) { errors.error(s.fOffset, ("duplicate section '@" + s.fName + "'").c_str()); } fSections[s.fName].push_back(&s); break; } default: break; } } } const Section* getSection(const char* name) { SkASSERT(!SectionPermitsDuplicates(name)); auto found = fSections.find(name); if (found == fSections.end()) { return nullptr; } SkASSERT(found->second.size() == 1); return found->second[0]; } std::vector<const Section*> getSections(const char* name) { auto found = fSections.find(name); if (found == fSections.end()) { return std::vector<const Section*>(); } return found->second; } const std::vector<const Variable*>& getParameters() { return fParameters; } static bool IsParameter(const Variable& var) { return (var.fModifiers.fFlags & Modifiers::kIn_Flag) && -1 == var.fModifiers.fLayout.fBuiltin; } static bool IsSupportedSection(const char* name) { return !strcmp(name, CLASS_SECTION) || !strcmp(name, CLONE_SECTION) || !strcmp(name, CONSTRUCTOR_SECTION) || !strcmp(name, CONSTRUCTOR_CODE_SECTION) || !strcmp(name, CONSTRUCTOR_PARAMS_SECTION) || !strcmp(name, COORD_TRANSFORM_SECTION) || !strcmp(name, CPP_SECTION) || !strcmp(name, CPP_END_SECTION) || !strcmp(name, EMIT_CODE_SECTION) || !strcmp(name, FIELDS_SECTION) || !strcmp(name, HEADER_SECTION) || !strcmp(name, HEADER_END_SECTION) || !strcmp(name, INITIALIZERS_SECTION) || !strcmp(name, MAKE_SECTION) || !strcmp(name, OPTIMIZATION_FLAGS_SECTION) || !strcmp(name, SAMPLER_PARAMS_SECTION) || !strcmp(name, SET_DATA_SECTION) || !strcmp(name, TEST_CODE_SECTION); } static bool SectionAcceptsArgument(const char* name) { return !strcmp(name, COORD_TRANSFORM_SECTION) || !strcmp(name, SAMPLER_PARAMS_SECTION) || !strcmp(name, SET_DATA_SECTION) || !strcmp(name, TEST_CODE_SECTION); } static bool SectionRequiresArgument(const char* name) { return !strcmp(name, SAMPLER_PARAMS_SECTION) || !strcmp(name, SET_DATA_SECTION) || !strcmp(name, TEST_CODE_SECTION); } static bool SectionPermitsDuplicates(const char* name) { return !strcmp(name, COORD_TRANSFORM_SECTION) || !strcmp(name, SAMPLER_PARAMS_SECTION); } private: std::vector<const Variable*> fParameters; std::unordered_map<String, std::vector<const Section*>> fSections; }; } // namespace SkSL #endif