Flutter Engine
The Flutter Engine
Public Member Functions | Static Public Member Functions | Static Public Attributes | List of all members
SkSL::SwitchStatement Class Referencefinal

#include <SkSLSwitchStatement.h>

Inheritance diagram for SkSL::SwitchStatement:
SkSL::Statement SkSL::IRNode SkSL::Poolable

Public Member Functions

 SwitchStatement (Position pos, std::unique_ptr< Expression > value, std::unique_ptr< Statement > caseBlock)
 
std::unique_ptr< Expression > & value ()
 
const std::unique_ptr< Expression > & value () const
 
std::unique_ptr< Statement > & caseBlock ()
 
const std::unique_ptr< Statement > & caseBlock () const
 
StatementArraycases ()
 
const StatementArraycases () const
 
std::string description () const override
 
- Public Member Functions inherited from SkSL::Statement
 Statement (Position pos, Kind kind)
 
Kind kind () const
 
virtual bool isEmpty () const
 
- Public Member Functions inherited from SkSL::IRNode
virtual ~IRNode ()
 
virtual std::string description () const =0
 
 IRNode (const IRNode &)=delete
 
IRNodeoperator= (const IRNode &)=delete
 
Position position () const
 
void setPosition (Position p)
 
template<typename T >
bool is () const
 
template<typename T >
const Tas () const
 
template<typename T >
Tas ()
 

Static Public Member Functions

static std::unique_ptr< StatementConvert (const Context &context, Position pos, std::unique_ptr< Expression > value, ExpressionArray caseValues, StatementArray caseStatements, std::unique_ptr< SymbolTable > symbolTable)
 
static std::unique_ptr< StatementMake (const Context &context, Position pos, std::unique_ptr< Expression > value, std::unique_ptr< Statement > caseBlock)
 
- Static Public Member Functions inherited from SkSL::Poolable
static void * operator new (const size_t size)
 
static void operator delete (void *ptr)
 

Static Public Attributes

static constexpr Kind kIRNodeKind = Kind::kSwitch
 

Additional Inherited Members

- Public Types inherited from SkSL::Statement
using Kind = StatementKind
 
- Public Attributes inherited from SkSL::IRNode
Position fPosition
 
- Protected Member Functions inherited from SkSL::IRNode
 IRNode (Position position, int kind)
 
- Protected Attributes inherited from SkSL::IRNode
int fKind
 

Detailed Description

A 'switch' statement.

Definition at line 30 of file SkSLSwitchStatement.h.

Constructor & Destructor Documentation

◆ SwitchStatement()

SkSL::SwitchStatement::SwitchStatement ( Position  pos,
std::unique_ptr< Expression value,
std::unique_ptr< Statement caseBlock 
)
inline

Definition at line 34 of file SkSLSwitchStatement.h.

37 : INHERITED(pos, kIRNodeKind)
38 , fValue(std::move(value))
39 , fCaseBlock(std::move(caseBlock)) {}
SkPoint pos
std::unique_ptr< Expression > & value()
static constexpr Kind kIRNodeKind
std::unique_ptr< Statement > & caseBlock()

Member Function Documentation

◆ caseBlock() [1/2]

std::unique_ptr< Statement > & SkSL::SwitchStatement::caseBlock ( )
inline

Definition at line 66 of file SkSLSwitchStatement.h.

66 {
67 return fCaseBlock;
68 }

◆ caseBlock() [2/2]

const std::unique_ptr< Statement > & SkSL::SwitchStatement::caseBlock ( ) const
inline

Definition at line 70 of file SkSLSwitchStatement.h.

70 {
71 return fCaseBlock;
72 }

◆ cases() [1/2]

StatementArray & SkSL::SwitchStatement::cases ( )
inline

Definition at line 74 of file SkSLSwitchStatement.h.

74 {
75 return fCaseBlock->as<Block>().children();
76 }

◆ cases() [2/2]

const StatementArray & SkSL::SwitchStatement::cases ( ) const
inline

Definition at line 78 of file SkSLSwitchStatement.h.

78 {
79 return fCaseBlock->as<Block>().children();
80 }

◆ Convert()

std::unique_ptr< Statement > SkSL::SwitchStatement::Convert ( const Context context,
Position  pos,
std::unique_ptr< Expression value,
ExpressionArray  caseValues,
StatementArray  caseStatements,
std::unique_ptr< SymbolTable symbolTable 
)
static

Definition at line 146 of file SkSLSwitchStatement.cpp.

151 {
152 SkASSERT(caseValues.size() == caseStatements.size());
153
154 value = context.fTypes.fInt->coerceExpression(std::move(value), context);
155 if (!value) {
156 return nullptr;
157 }
158
160 for (int i = 0; i < caseValues.size(); ++i) {
161 if (caseValues[i]) {
162 Position casePos = caseValues[i]->fPosition;
163 // Case values must be constant integers of the same type as the switch value
164 std::unique_ptr<Expression> caseValue = value->type().coerceExpression(
165 std::move(caseValues[i]), context);
166 if (!caseValue) {
167 return nullptr;
168 }
169 SKSL_INT intValue;
170 if (!ConstantFolder::GetConstantInt(*caseValue, &intValue)) {
171 context.fErrors->error(casePos, "case value must be a constant integer");
172 return nullptr;
173 }
174 cases.push_back(SwitchCase::Make(casePos, intValue, std::move(caseStatements[i])));
175 } else {
176 cases.push_back(SwitchCase::MakeDefault(pos, std::move(caseStatements[i])));
177 }
178 }
179
180 // Detect duplicate `case` labels and report an error.
182 if (!duplicateCases.empty()) {
183 for (const SwitchCase* sc : duplicateCases) {
184 if (sc->isDefault()) {
185 context.fErrors->error(sc->fPosition, "duplicate default case");
186 } else {
187 context.fErrors->error(sc->fPosition, "duplicate case value '" +
188 std::to_string(sc->value()) + "'");
189 }
190 }
191 return nullptr;
192 }
193
194 return SwitchStatement::Make(context,
195 pos,
196 std::move(value),
198 std::move(cases),
199 Block::Kind::kBracedScope,
200 std::move(symbolTable)));
201}
#define SkASSERT(cond)
Definition: SkAssert.h:116
int64_t SKSL_INT
Definition: SkSLDefines.h:16
static std::unique_ptr< Block > MakeBlock(Position pos, StatementArray statements, Kind kind=Kind::kBracedScope, std::unique_ptr< SymbolTable > symbols=nullptr)
Definition: SkSLBlock.cpp:59
static bool GetConstantInt(const Expression &value, SKSL_INT *out)
static std::unique_ptr< SwitchCase > MakeDefault(Position pos, std::unique_ptr< Statement > statement)
static std::unique_ptr< SwitchCase > Make(Position pos, SKSL_INT value, std::unique_ptr< Statement > statement)
static std::unique_ptr< Statement > Make(const Context &context, Position pos, std::unique_ptr< Expression > value, std::unique_ptr< Statement > caseBlock)
StatementArray & cases()
bool empty() const
Definition: SkTArray.h:199
skia_private::STArray< 2, std::unique_ptr< Statement > > StatementArray
Definition: SkSLDefines.h:32
static TArray< const SwitchCase * > find_duplicate_case_values(const StatementArray &cases)
static SkString to_string(int n)
Definition: nanobench.cpp:119

◆ description()

std::string SkSL::SwitchStatement::description ( ) const
overridevirtual

Implements SkSL::IRNode.

Definition at line 36 of file SkSLSwitchStatement.cpp.

36 {
37 return "switch (" + this->value()->description() + ") " + this->caseBlock()->description();
38}

◆ Make()

std::unique_ptr< Statement > SkSL::SwitchStatement::Make ( const Context context,
Position  pos,
std::unique_ptr< Expression value,
std::unique_ptr< Statement caseBlock 
)
static

Definition at line 203 of file SkSLSwitchStatement.cpp.

206 {
207 // Confirm that every statement in `cases` is a SwitchCase.
208 const StatementArray& cases = caseBlock->as<Block>().children();
209 SkASSERT(std::all_of(cases.begin(), cases.end(), [&](const std::unique_ptr<Statement>& stmt) {
210 return stmt->is<SwitchCase>();
211 }));
212
213 // Confirm that every switch-case value is unique.
215
216 // Flatten switch statements if we're optimizing, and the value is known
217 if (context.fConfig->fSettings.fOptimize) {
218 SKSL_INT switchValue;
219 if (ConstantFolder::GetConstantInt(*value, &switchValue)) {
220 SwitchCase* defaultCase = nullptr;
221 SwitchCase* matchingCase = nullptr;
222 for (const std::unique_ptr<Statement>& stmt : cases) {
223 SwitchCase& sc = stmt->as<SwitchCase>();
224 if (sc.isDefault()) {
225 defaultCase = &sc;
226 continue;
227 }
228
229 if (sc.value() == switchValue) {
230 matchingCase = &sc;
231 break;
232 }
233 }
234
235 if (!matchingCase) {
236 // No case value matches the switch value.
237 if (!defaultCase) {
238 // No default switch-case exists; the switch had no effect.
239 // We can eliminate the entire switch!
240 return Nop::Make();
241 }
242 // We had a default case; that's what we matched with.
243 matchingCase = defaultCase;
244 }
245
246 // Strip down our case block to contain only the matching case, if we can.
247 if (block_for_case(caseBlock.get(), matchingCase)) {
248 return caseBlock;
249 }
250 }
251 }
252
253 // The switch couldn't be optimized away; emit it normally.
254 auto stmt = std::make_unique<SwitchStatement>(pos, std::move(value), std::move(caseBlock));
255
256 // If a switch-case has variable declarations at its top level, we want to create a scoped block
257 // around the switch, then move the variable declarations out of the switch body and into the
258 // outer scope. This prevents scoping issues in backends which don't offer a native switch.
259 // (skia:14375)
260 return Transform::HoistSwitchVarDeclarationsAtTopLevel(context, std::move(stmt));
261}
static std::unique_ptr< Statement > Make()
Definition: SkSLNop.h:26
EMSCRIPTEN_KEEPALIVE void empty()
std::unique_ptr< Statement > HoistSwitchVarDeclarationsAtTopLevel(const Context &, std::unique_ptr< SwitchStatement >)
static bool block_for_case(Statement *caseBlock, SwitchCase *caseToCapture)

◆ value() [1/2]

std::unique_ptr< Expression > & SkSL::SwitchStatement::value ( )
inline

Definition at line 58 of file SkSLSwitchStatement.h.

58 {
59 return fValue;
60 }

◆ value() [2/2]

const std::unique_ptr< Expression > & SkSL::SwitchStatement::value ( ) const
inline

Definition at line 62 of file SkSLSwitchStatement.h.

62 {
63 return fValue;
64 }

Member Data Documentation

◆ kIRNodeKind

constexpr Kind SkSL::SwitchStatement::kIRNodeKind = Kind::kSwitch
inlinestaticconstexpr

Definition at line 32 of file SkSLSwitchStatement.h.


The documentation for this class was generated from the following files: