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