blob: f985fd7eed0e3d24d9f24a128576659dffe7ab12 [file] [log] [blame]
John Stilese67bd132021-03-19 18:39:25 -04001/*
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
John Stiles2dda4b62021-09-16 13:18:10 -04008#include "src/sksl/ir/SkSLVarDeclarations.h"
9
10#include "include/sksl/SkSLErrorReporter.h"
John Stilese67bd132021-03-19 18:39:25 -040011#include "src/sksl/SkSLAnalysis.h"
12#include "src/sksl/SkSLContext.h"
13#include "src/sksl/SkSLProgramSettings.h"
John Stilese67bd132021-03-19 18:39:25 -040014
15namespace SkSL {
16
17std::unique_ptr<Statement> VarDeclaration::clone() const {
18 return std::make_unique<VarDeclaration>(&this->var(),
19 &this->baseType(),
20 fArraySize,
21 this->value() ? this->value()->clone() : nullptr);
22}
23
24String VarDeclaration::description() const {
25 String result = this->var().modifiers().description() + this->baseType().description() + " " +
26 this->var().name();
27 if (this->arraySize() > 0) {
28 result.appendf("[%d]", this->arraySize());
John Stilese67bd132021-03-19 18:39:25 -040029 }
30 if (this->value()) {
31 result += " = " + this->value()->description();
32 }
33 result += ";";
34 return result;
35}
36
37std::unique_ptr<Statement> VarDeclaration::Convert(const Context& context,
38 Variable* var,
39 std::unique_ptr<Expression> value) {
John Stiles7bd3f1c2021-08-27 16:12:10 -040040 if (value) {
41 if (var->type().isOpaque()) {
42 context.fErrors->error(value->fOffset, "opaque type '" + var->type().name() +
43 "' cannot use initializer expressions");
44 return nullptr;
45 }
46 if (var->modifiers().fFlags & Modifiers::kIn_Flag) {
47 context.fErrors->error(value->fOffset,
48 "'in' variables cannot use initializer expressions");
49 return nullptr;
50 }
51 if (var->modifiers().fFlags & Modifiers::kUniform_Flag) {
52 context.fErrors->error(value->fOffset,
53 "'uniform' variables cannot use initializer expressions");
54 return nullptr;
55 }
56 if (var->storage() == Variable::Storage::kInterfaceBlock) {
57 context.fErrors->error(value->fOffset,
58 "initializers are not permitted on interface block fields");
59 return nullptr;
60 }
61 value = var->type().coerceExpression(std::move(value), context);
62 if (!value) {
63 return nullptr;
64 }
65 }
John Stilese67bd132021-03-19 18:39:25 -040066 if (var->modifiers().fFlags & Modifiers::kConst_Flag) {
67 if (!value) {
Ethan Nicholas39f6da42021-08-23 13:10:07 -040068 context.fErrors->error(var->fOffset, "'const' variables must be initialized");
John Stilese67bd132021-03-19 18:39:25 -040069 return nullptr;
70 }
71 if (!Analysis::IsConstantExpression(*value)) {
Ethan Nicholas39f6da42021-08-23 13:10:07 -040072 context.fErrors->error(value->fOffset,
Ethan Nicholas8d116542021-08-11 13:27:16 -040073 "'const' variable initializer must be a constant expression");
John Stilese67bd132021-03-19 18:39:25 -040074 return nullptr;
75 }
76 }
John Stiles6efab712021-08-26 11:46:21 -040077 if (var->storage() == Variable::Storage::kInterfaceBlock) {
78 if (var->type().isOpaque()) {
79 context.fErrors->error(var->fOffset, "opaque type '" + var->type().name() +
80 "' is not permitted in an interface block");
81 return nullptr;
82 }
John Stiles6efab712021-08-26 11:46:21 -040083 }
84 if (var->storage() == Variable::Storage::kGlobal) {
85 if (value && !Analysis::IsConstantExpression(*value)) {
Ethan Nicholas39f6da42021-08-23 13:10:07 -040086 context.fErrors->error(value->fOffset,
Ethan Nicholas8d116542021-08-11 13:27:16 -040087 "global variable initializer must be a constant expression");
John Stilese67bd132021-03-19 18:39:25 -040088 return nullptr;
89 }
John Stiles6efab712021-08-26 11:46:21 -040090 }
John Stilese67bd132021-03-19 18:39:25 -040091 const Type* baseType = &var->type();
92 int arraySize = 0;
93 if (baseType->isArray()) {
94 arraySize = baseType->columns();
95 baseType = &baseType->componentType();
96 }
97 return VarDeclaration::Make(context, var, baseType, arraySize, std::move(value));
98}
99
100std::unique_ptr<Statement> VarDeclaration::Make(const Context& context,
101 Variable* var,
102 const Type* baseType,
103 int arraySize,
104 std::unique_ptr<Expression> value) {
105 SkASSERT(!baseType->isArray());
John Stiles3b0d3502021-08-26 14:33:46 -0400106 // function parameters cannot have variable declarations
107 SkASSERT(var->storage() != Variable::Storage::kParameter);
John Stilese67bd132021-03-19 18:39:25 -0400108 // 'const' variables must be initialized
109 SkASSERT(!(var->modifiers().fFlags & Modifiers::kConst_Flag) || value);
110 // 'const' variable initializer must be a constant expression
111 SkASSERT(!(var->modifiers().fFlags & Modifiers::kConst_Flag) ||
112 Analysis::IsConstantExpression(*value));
113 // global variable initializer must be a constant expression
114 SkASSERT(!(value && var->storage() == Variable::Storage::kGlobal &&
John Stilese67bd132021-03-19 18:39:25 -0400115 !Analysis::IsConstantExpression(*value)));
John Stiles6efab712021-08-26 11:46:21 -0400116 // opaque type not permitted on an interface block
117 SkASSERT(!(var->storage() == Variable::Storage::kInterfaceBlock && var->type().isOpaque()));
118 // initializers are not permitted on interface block fields
119 SkASSERT(!(var->storage() == Variable::Storage::kInterfaceBlock && value));
John Stilese67bd132021-03-19 18:39:25 -0400120 // opaque type cannot use initializer expressions
121 SkASSERT(!(value && var->type().isOpaque()));
122 // 'in' variables cannot use initializer expressions
123 SkASSERT(!(value && (var->modifiers().fFlags & Modifiers::kIn_Flag)));
124 // 'uniform' variables cannot use initializer expressions
125 SkASSERT(!(value && (var->modifiers().fFlags & Modifiers::kUniform_Flag)));
126
John Stilesb0d93cc2021-06-01 11:07:53 -0400127 // Detect and report out-of-range initial-values for this variable.
128 if (value) {
129 var->type().checkForOutOfRangeLiteral(context, *value);
130 }
131
John Stilese67bd132021-03-19 18:39:25 -0400132 auto result = std::make_unique<VarDeclaration>(var, baseType, arraySize, std::move(value));
133 var->setDeclaration(result.get());
134 return std::move(result);
135}
136
137} // namespace SkSL