1 /*
2  * Copyright 2021 Google LLC
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 #include "src/sksl/SkSLAnalysis.h"
9 #include "src/sksl/SkSLContext.h"
10 #include "src/sksl/SkSLProgramSettings.h"
11 #include "src/sksl/ir/SkSLVarDeclarations.h"
12 
13 namespace SkSL {
14 
clone() const15 std::unique_ptr<Statement> VarDeclaration::clone() const {
16     return std::make_unique<VarDeclaration>(&this->var(),
17                                             &this->baseType(),
18                                             fArraySize,
19                                             this->value() ? this->value()->clone() : nullptr);
20 }
21 
description() const22 String VarDeclaration::description() const {
23     String result = this->var().modifiers().description() + this->baseType().description() + " " +
24                     this->var().name();
25     if (this->arraySize() > 0) {
26         result.appendf("[%d]", this->arraySize());
27     } else if (this->arraySize() == Type::kUnsizedArray) {
28         result += "[]";
29     }
30     if (this->value()) {
31         result += " = " + this->value()->description();
32     }
33     result += ";";
34     return result;
35 }
36 
Convert(const Context & context,Variable * var,std::unique_ptr<Expression> value)37 std::unique_ptr<Statement> VarDeclaration::Convert(const Context& context,
38                                                    Variable* var,
39                                                    std::unique_ptr<Expression> value) {
40     if (var->modifiers().fFlags & Modifiers::kConst_Flag) {
41         if (!value) {
42             context.fErrors.error(var->fOffset, "'const' variables must be initialized");
43             return nullptr;
44         }
45         if (!Analysis::IsConstantExpression(*value)) {
46             context.fErrors.error(value->fOffset,
47                                   "'const' variable initializer must be a constant expression");
48             return nullptr;
49         }
50     }
51     if (value) {
52         if (var->storage() == Variable::Storage::kGlobal &&
53             context.fConfig->fKind != ProgramKind::kFragmentProcessor &&
54             !Analysis::IsConstantExpression(*value)) {
55             context.fErrors.error(value->fOffset,
56                                   "global variable initializer must be a constant expression");
57             return nullptr;
58         }
59         if (var->type().isOpaque()) {
60             context.fErrors.error(
61                     value->fOffset,
62                     "opaque type '" + var->type().name() + "' cannot use initializer expressions");
63             return nullptr;
64         }
65         if (var->modifiers().fFlags & Modifiers::kIn_Flag) {
66             context.fErrors.error(value->fOffset,
67                                   "'in' variables cannot use initializer expressions");
68             return nullptr;
69         }
70         if (var->modifiers().fFlags & Modifiers::kUniform_Flag) {
71             context.fErrors.error(value->fOffset,
72                                   "'uniform' variables cannot use initializer expressions");
73             return nullptr;
74         }
75         value = var->type().coerceExpression(std::move(value), context);
76         if (!value) {
77             return nullptr;
78         }
79     }
80     const Type* baseType = &var->type();
81     int arraySize = 0;
82     if (baseType->isArray()) {
83         arraySize = baseType->columns();
84         baseType = &baseType->componentType();
85     }
86     return VarDeclaration::Make(context, var, baseType, arraySize, std::move(value));
87 }
88 
Make(const Context & context,Variable * var,const Type * baseType,int arraySize,std::unique_ptr<Expression> value)89 std::unique_ptr<Statement> VarDeclaration::Make(const Context& context,
90                                                 Variable* var,
91                                                 const Type* baseType,
92                                                 int arraySize,
93                                                 std::unique_ptr<Expression> value) {
94     SkASSERT(!baseType->isArray());
95     // 'const' variables must be initialized
96     SkASSERT(!(var->modifiers().fFlags & Modifiers::kConst_Flag) || value);
97     // 'const' variable initializer must be a constant expression
98     SkASSERT(!(var->modifiers().fFlags & Modifiers::kConst_Flag) ||
99              Analysis::IsConstantExpression(*value));
100     // global variable initializer must be a constant expression
101     SkASSERT(!(value && var->storage() == Variable::Storage::kGlobal &&
102                context.fConfig->fKind != ProgramKind::kFragmentProcessor &&
103                !Analysis::IsConstantExpression(*value)));
104     // opaque type cannot use initializer expressions
105     SkASSERT(!(value && var->type().isOpaque()));
106     // 'in' variables cannot use initializer expressions
107     SkASSERT(!(value && (var->modifiers().fFlags & Modifiers::kIn_Flag)));
108     // 'uniform' variables cannot use initializer expressions
109     SkASSERT(!(value && (var->modifiers().fFlags & Modifiers::kUniform_Flag)));
110 
111     auto result = std::make_unique<VarDeclaration>(var, baseType, arraySize, std::move(value));
112     var->setDeclaration(result.get());
113     return std::move(result);
114 }
115 
116 }  // namespace SkSL
117