• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ir/SkSLBlock.h"
9 
10 #include "src/sksl/ir/SkSLNop.h"
11 #include "src/sksl/ir/SkSLSymbolTable.h"
12 
13 #include <type_traits>
14 
15 namespace SkSL {
16 
Make(Position pos,StatementArray statements,Kind kind,std::shared_ptr<SymbolTable> symbols)17 std::unique_ptr<Statement> Block::Make(Position pos,
18                                        StatementArray statements,
19                                        Kind kind,
20                                        std::shared_ptr<SymbolTable> symbols) {
21     // We can't simplify away braces or populated symbol tables.
22     if (kind == Kind::kBracedScope || (symbols && symbols->count())) {
23         return std::make_unique<Block>(pos, std::move(statements), kind, std::move(symbols));
24     }
25 
26     // If the Block is completely empty, synthesize a Nop.
27     if (statements.empty()) {
28         return Nop::Make();
29     }
30 
31     if (statements.size() > 1) {
32         // The statement array contains multiple statements, but some of those might be no-ops.
33         // If the statement array only contains one real statement, we can return that directly and
34         // avoid creating an additional Block node.
35         std::unique_ptr<Statement>* foundStatement = nullptr;
36         for (std::unique_ptr<Statement>& stmt : statements) {
37             if (!stmt->isEmpty()) {
38                 if (!foundStatement) {
39                     // We found a single non-empty statement. Remember it and keep looking.
40                     foundStatement = &stmt;
41                     continue;
42                 }
43                 // We found more than one non-empty statement. We actually do need a Block.
44                 return std::make_unique<Block>(pos, std::move(statements), kind,
45                                                /*symbols=*/nullptr);
46             }
47         }
48 
49         // The array wrapped one valid Statement. Avoid allocating a Block by returning it directly.
50         if (foundStatement) {
51             return std::move(*foundStatement);
52         }
53 
54         // The statement array contained nothing but empty statements!
55         // In this case, we don't actually need to allocate a Block.
56         // We can just return one of those empty statements. Fall through to...
57     }
58 
59     return std::move(statements.front());
60 }
61 
MakeBlock(Position pos,StatementArray statements,Kind kind,std::shared_ptr<SymbolTable> symbols)62 std::unique_ptr<Block> Block::MakeBlock(Position pos,
63                                         StatementArray statements,
64                                         Kind kind,
65                                         std::shared_ptr<SymbolTable> symbols) {
66     // Nothing to optimize here--eliminating empty statements doesn't actually improve the generated
67     // code, and we promise to return a Block.
68     return std::make_unique<Block>(pos, std::move(statements), kind, std::move(symbols));
69 }
70 
clone() const71 std::unique_ptr<Statement> Block::clone() const {
72     StatementArray cloned;
73     cloned.reserve_back(this->children().size());
74     for (const std::unique_ptr<Statement>& stmt : this->children()) {
75         cloned.push_back(stmt->clone());
76     }
77     return std::make_unique<Block>(fPosition,
78                                    std::move(cloned),
79                                    fBlockKind,
80                                    SymbolTable::WrapIfBuiltin(this->symbolTable()));
81 }
82 
description() const83 std::string Block::description() const {
84     std::string result;
85 
86     // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
87     // something here to make the code valid).
88     bool isScope = this->isScope() || this->isEmpty();
89     if (isScope) {
90         result += "{";
91     }
92     for (const std::unique_ptr<Statement>& stmt : this->children()) {
93         result += "\n";
94         result += stmt->description();
95     }
96     result += isScope ? "\n}\n" : "\n";
97     return result;
98 }
99 
100 }  // namespace SkSL
101