1/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SKSL_SECTIONANDPARAMETERHELPER
9#define SKSL_SECTIONANDPARAMETERHELPER
10
11#include "SkSLErrorReporter.h"
12#include "ir/SkSLProgram.h"
13#include "ir/SkSLSection.h"
14#include "ir/SkSLVarDeclarations.h"
15#include <unordered_map>
16#include <vector>
17
18namespace SkSL {
19
20#define CLASS_SECTION              "class"
21#define CLONE_SECTION              "clone"
22#define CONSTRUCTOR_SECTION        "constructor"
23#define CONSTRUCTOR_CODE_SECTION   "constructorCode"
24#define CONSTRUCTOR_PARAMS_SECTION "constructorParams"
25#define COORD_TRANSFORM_SECTION    "coordTransform"
26#define CPP_SECTION                "cpp"
27#define CPP_END_SECTION            "cppEnd"
28#define HEADER_SECTION             "header"
29#define HEADER_END_SECTION         "headerEnd"
30#define EMIT_CODE_SECTION          "emitCode"
31#define FIELDS_SECTION             "fields"
32#define INITIALIZERS_SECTION       "initializers"
33#define MAKE_SECTION               "make"
34#define OPTIMIZATION_FLAGS_SECTION "optimizationFlags"
35#define SAMPLER_PARAMS_SECTION     "samplerParams"
36#define SET_DATA_SECTION           "setData"
37#define TEST_CODE_SECTION          "test"
38
39class SectionAndParameterHelper {
40public:
41    SectionAndParameterHelper(const Program& program, ErrorReporter& errors) {
42        for (const auto& p : program.fElements) {
43            switch (p->fKind) {
44                case ProgramElement::kVar_Kind: {
45                    const VarDeclarations* decls = (const VarDeclarations*) p.get();
46                    for (const auto& raw : decls->fVars) {
47                        const VarDeclaration& decl = (VarDeclaration&) *raw;
48                        if (IsParameter(*decl.fVar)) {
49                            fParameters.push_back(decl.fVar);
50                        }
51                    }
52                    break;
53                }
54                case ProgramElement::kSection_Kind: {
55                    const Section* s = (const Section*) p.get();
56                    if (IsSupportedSection(s->fName.c_str())) {
57                        if (SectionAcceptsArgument(s->fName.c_str())) {
58                            if (!s->fArgument.size()) {
59                                errors.error(s->fOffset,
60                                             ("section '@" + s->fName +
61                                              "' requires one parameter").c_str());
62                            }
63                        } else if (s->fArgument.size()) {
64                            errors.error(s->fOffset,
65                                         ("section '@" + s->fName + "' has no parameters").c_str());
66                        }
67                    } else {
68                        errors.error(s->fOffset,
69                                     ("unsupported section '@" + s->fName + "'").c_str());
70                    }
71                    if (!SectionPermitsDuplicates(s->fName.c_str()) &&
72                            fSections.find(s->fName) != fSections.end()) {
73                        errors.error(s->fOffset,
74                                     ("duplicate section '@" + s->fName + "'").c_str());
75                    }
76                    fSections[s->fName].push_back(s);
77                    break;
78                }
79                default:
80                    break;
81            }
82        }
83    }
84
85    const Section* getSection(const char* name) {
86        ASSERT(!SectionPermitsDuplicates(name));
87        auto found = fSections.find(name);
88        if (found == fSections.end()) {
89            return nullptr;
90        }
91        ASSERT(found->second.size() == 1);
92        return found->second[0];
93    }
94
95    std::vector<const Section*> getSections(const char* name) {
96        auto found = fSections.find(name);
97        if (found == fSections.end()) {
98            return std::vector<const Section*>();
99        }
100        return found->second;
101    }
102
103    const std::vector<const Variable*>& getParameters() {
104        return fParameters;
105    }
106
107    static bool IsParameter(const Variable& var) {
108        return (var.fModifiers.fFlags & Modifiers::kIn_Flag) &&
109               -1 == var.fModifiers.fLayout.fBuiltin;
110    }
111
112    static bool IsSupportedSection(const char* name) {
113        return !strcmp(name, CLASS_SECTION) ||
114               !strcmp(name, CLONE_SECTION) ||
115               !strcmp(name, CONSTRUCTOR_SECTION) ||
116               !strcmp(name, CONSTRUCTOR_CODE_SECTION) ||
117               !strcmp(name, CONSTRUCTOR_PARAMS_SECTION) ||
118               !strcmp(name, COORD_TRANSFORM_SECTION) ||
119               !strcmp(name, CPP_SECTION) ||
120               !strcmp(name, CPP_END_SECTION) ||
121               !strcmp(name, EMIT_CODE_SECTION) ||
122               !strcmp(name, FIELDS_SECTION) ||
123               !strcmp(name, HEADER_SECTION) ||
124               !strcmp(name, HEADER_END_SECTION) ||
125               !strcmp(name, INITIALIZERS_SECTION) ||
126               !strcmp(name, MAKE_SECTION) ||
127               !strcmp(name, OPTIMIZATION_FLAGS_SECTION) ||
128               !strcmp(name, SAMPLER_PARAMS_SECTION) ||
129               !strcmp(name, SET_DATA_SECTION) ||
130               !strcmp(name, TEST_CODE_SECTION);
131    }
132
133    static bool SectionAcceptsArgument(const char* name) {
134        return !strcmp(name, COORD_TRANSFORM_SECTION) ||
135               !strcmp(name, SAMPLER_PARAMS_SECTION) ||
136               !strcmp(name, SET_DATA_SECTION) ||
137               !strcmp(name, TEST_CODE_SECTION);
138    }
139
140    static bool SectionPermitsDuplicates(const char* name) {
141        return !strcmp(name, COORD_TRANSFORM_SECTION) ||
142               !strcmp(name, SAMPLER_PARAMS_SECTION);
143    }
144
145private:
146    std::vector<const Variable*> fParameters;
147    std::unordered_map<String, std::vector<const Section*>> fSections;
148};
149
150} // namespace SkSL
151
152#endif
153