Coverage Report

Created: 2025-09-08 08:10

/src/solidity/libyul/YulStack.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
/**
19
 * Full assembly stack that can support Yul as input.
20
 */
21
22
#pragma once
23
24
#include <liblangutil/CharStreamProvider.h>
25
#include <liblangutil/DebugInfoSelection.h>
26
#include <liblangutil/ErrorReporter.h>
27
#include <liblangutil/EVMVersion.h>
28
#include <liblangutil/Exceptions.h>
29
30
#include <libsolutil/JSON.h>
31
32
#include <libyul/Object.h>
33
#include <libyul/ObjectOptimizer.h>
34
#include <libyul/ObjectParser.h>
35
36
#include <libsolidity/interface/OptimiserSettings.h>
37
38
#include <libevmasm/LinkerObject.h>
39
40
#include <memory>
41
#include <string>
42
43
namespace solidity::evmasm
44
{
45
class Assembly;
46
}
47
48
namespace solidity::langutil
49
{
50
class Scanner;
51
}
52
53
namespace solidity::yul
54
{
55
class AbstractAssembly;
56
57
58
struct MachineAssemblyObject
59
{
60
  std::shared_ptr<evmasm::LinkerObject> bytecode;
61
  std::shared_ptr<evmasm::Assembly> assembly;
62
  std::unique_ptr<std::string> sourceMappings;
63
  Json ethdebug = Json::object();
64
};
65
66
/*
67
 * Full assembly stack that can support EVM-assembly and Yul as input and EVM as output.
68
 */
69
class YulStack: public langutil::CharStreamProvider
70
{
71
public:
72
  using Language = yul::Language;
73
  enum class Machine { EVM };
74
  enum State {
75
    Empty,
76
    Parsed,
77
    AnalysisSuccessful
78
  };
79
80
  YulStack():
81
    YulStack(
82
      langutil::EVMVersion{},
83
      std::nullopt,
84
      Language::Assembly,
85
      solidity::frontend::OptimiserSettings::none(),
86
      langutil::DebugInfoSelection::Default()
87
    )
88
0
  {}
89
90
  YulStack(
91
    langutil::EVMVersion _evmVersion,
92
    std::optional<uint8_t> _eofVersion,
93
    Language _language,
94
    solidity::frontend::OptimiserSettings _optimiserSettings,
95
    langutil::DebugInfoSelection const& _debugInfoSelection,
96
    langutil::CharStreamProvider const* _soliditySourceProvider = nullptr,
97
    std::shared_ptr<ObjectOptimizer> _objectOptimizer = nullptr
98
  ):
99
    m_language(_language),
100
    m_evmVersion(_evmVersion),
101
    m_eofVersion(_eofVersion),
102
    m_optimiserSettings(std::move(_optimiserSettings)),
103
    m_debugInfoSelection(_debugInfoSelection),
104
    m_soliditySourceProvider(_soliditySourceProvider),
105
    m_errorReporter(m_errors),
106
    m_objectOptimizer(_objectOptimizer ? std::move(_objectOptimizer) : std::make_shared<ObjectOptimizer>())
107
179k
  {}
108
109
  /// @returns the char stream used during parsing
110
  langutil::CharStream const& charStream(std::string const& _sourceName) const override;
111
112
  /// Runs parsing and analysis steps, returns false if input cannot be assembled.
113
  /// Multiple calls overwrite the previous state.
114
  bool parseAndAnalyze(std::string const& _sourceName, std::string const& _source);
115
116
  /// Run the optimizer suite. Can only be used with Yul or strict assembly.
117
  /// If the settings (see constructor) disabled the optimizer, nothing is done here.
118
  void optimize();
119
120
  /// Run the assembly step (should only be called after parseAndAnalyze).
121
  MachineAssemblyObject assemble(Machine _machine);
122
123
  /// Run the assembly step (should only be called after parseAndAnalyze).
124
  /// In addition to the value returned by @a assemble, returns
125
  /// a second object that is the runtime code.
126
  /// Only available for EVM.
127
  std::pair<MachineAssemblyObject, MachineAssemblyObject>
128
  assembleWithDeployed(
129
    std::optional<std::string_view> _deployName = {}
130
  );
131
132
  /// Run the assembly step (should only be called after parseAndAnalyze).
133
  /// Similar to @a assemblyWithDeployed, but returns EVM assembly objects.
134
  /// Only available for EVM.
135
  std::pair<std::shared_ptr<evmasm::Assembly>, std::shared_ptr<evmasm::Assembly>>
136
  assembleEVMWithDeployed(
137
    std::optional<std::string_view> _deployName = {}
138
  );
139
140
  /// @returns the errors generated during parsing, analysis (and potentially assembly).
141
48.8k
  langutil::ErrorList const& errors() const { return m_errors; }
142
4.90k
  bool hasErrors() const { return m_errorReporter.hasErrors(); }
143
0
  bool hasErrorsWarningsOrInfos() const { return m_errorReporter.hasErrorsWarningsOrInfos(); }
144
145
  /// Pretty-print the input after having parsed it.
146
  std::string print() const;
147
  Json astJson() const;
148
149
  // return the JSON representation of the YuL CFG (experimental)
150
  Json cfgJson() const;
151
152
  /// Return the parsed and analyzed object.
153
  std::shared_ptr<Object> parserResult() const;
154
155
  Dialect const& dialect() const;
156
157
28.5k
  langutil::DebugInfoSelection debugInfoSelection() const { return m_debugInfoSelection; }
158
159
private:
160
  bool parse(std::string const& _sourceName, std::string const& _source);
161
  bool analyzeParsed();
162
  bool analyzeParsed(yul::Object& _object);
163
164
  void compileEVM(yul::AbstractAssembly& _assembly, bool _optimize) const;
165
166
  /// Prints the Yul object stored internally and parses it again.
167
  /// This ensures that the debug info in the AST matches the source that printing would produce
168
  /// rather than the initial source.
169
  /// @warning Does not update the error list or the original source (@a m_charStream) to make
170
  /// it possible to report errors to the user even after the optimization has been performed.
171
  void reparse();
172
173
  void reportUnimplementedFeatureError(langutil::UnimplementedFeatureError const& _error);
174
175
  Language m_language = Language::Assembly;
176
  langutil::EVMVersion m_evmVersion;
177
  std::optional<uint8_t> m_eofVersion;
178
  solidity::frontend::OptimiserSettings m_optimiserSettings;
179
  langutil::DebugInfoSelection m_debugInfoSelection{};
180
181
  /// Provider of the Solidity sources that the Yul code was generated from.
182
  /// Necessary when code snippets are requested as a part of debug info. When null, code snippets are omitted.
183
  /// NOTE: Not owned by YulStack, the user must ensure that it is not destroyed before the stack is.
184
  langutil::CharStreamProvider const* m_soliditySourceProvider{};
185
186
  std::unique_ptr<langutil::CharStream> m_charStream;
187
188
  State m_stackState = Empty;
189
  std::shared_ptr<yul::Object> m_parserResult;
190
  langutil::ErrorList m_errors;
191
  langutil::ErrorReporter m_errorReporter;
192
193
  std::shared_ptr<ObjectOptimizer> m_objectOptimizer;
194
};
195
196
}