Coverage Report

Created: 2022-08-24 06:52

/src/solidity/libyul/AsmJsonImporter.cpp
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
 * @author julius <djudju@protonmail.com>
20
 * @date 2019
21
 * Converts an inlineAssembly AST from JSON format to AsmData
22
23
 */
24
25
#include <libyul/AsmJsonImporter.h>
26
#include <libyul/AST.h>
27
#include <libyul/Exceptions.h>
28
29
#include <liblangutil/Exceptions.h>
30
#include <liblangutil/Scanner.h>
31
32
#include <boost/algorithm/string/split.hpp>
33
#include <boost/algorithm/string.hpp>
34
35
#include <vector>
36
37
using namespace std;
38
using namespace solidity::langutil;
39
40
namespace solidity::yul
41
{
42
43
using SourceLocation = langutil::SourceLocation;
44
45
SourceLocation const AsmJsonImporter::createSourceLocation(Json::Value const& _node)
46
0
{
47
0
  yulAssert(member(_node, "src").isString(), "'src' must be a string");
48
49
0
  return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_sourceNames);
50
0
}
51
52
template <class T>
53
T AsmJsonImporter::createAsmNode(Json::Value const& _node)
54
0
{
55
0
  T r;
56
0
  SourceLocation nativeLocation = createSourceLocation(_node);
57
0
  yulAssert(nativeLocation.hasText(), "Invalid source location in Asm AST");
58
  // TODO: We should add originLocation to the AST.
59
  // While it's not included, we'll use nativeLocation for it because we only support importing
60
  // inline assembly as a part of a Solidity AST and there these locations are always the same.
61
0
  r.debugData = DebugData::create(nativeLocation, nativeLocation);
62
0
  return r;
63
0
}
Unexecuted instantiation: solidity::yul::TypedName solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::TypedName>(Json::Value const&)
Unexecuted instantiation: solidity::yul::Block solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::Block>(Json::Value const&)
Unexecuted instantiation: solidity::yul::Literal solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::Literal>(Json::Value const&)
Unexecuted instantiation: solidity::yul::Leave solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::Leave>(Json::Value const&)
Unexecuted instantiation: solidity::yul::Identifier solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::Identifier>(Json::Value const&)
Unexecuted instantiation: solidity::yul::Assignment solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::Assignment>(Json::Value const&)
Unexecuted instantiation: solidity::yul::FunctionCall solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::FunctionCall>(Json::Value const&)
Unexecuted instantiation: solidity::yul::ExpressionStatement solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::ExpressionStatement>(Json::Value const&)
Unexecuted instantiation: solidity::yul::VariableDeclaration solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::VariableDeclaration>(Json::Value const&)
Unexecuted instantiation: solidity::yul::FunctionDefinition solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::FunctionDefinition>(Json::Value const&)
Unexecuted instantiation: solidity::yul::If solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::If>(Json::Value const&)
Unexecuted instantiation: solidity::yul::Case solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::Case>(Json::Value const&)
Unexecuted instantiation: solidity::yul::Switch solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::Switch>(Json::Value const&)
Unexecuted instantiation: solidity::yul::ForLoop solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::ForLoop>(Json::Value const&)
Unexecuted instantiation: solidity::yul::Break solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::Break>(Json::Value const&)
Unexecuted instantiation: solidity::yul::Continue solidity::yul::AsmJsonImporter::createAsmNode<solidity::yul::Continue>(Json::Value const&)
64
65
Json::Value AsmJsonImporter::member(Json::Value const& _node, string const& _name)
66
0
{
67
0
  if (!_node.isMember(_name))
68
0
    return Json::nullValue;
69
0
  return _node[_name];
70
0
}
71
72
TypedName AsmJsonImporter::createTypedName(Json::Value const& _node)
73
0
{
74
0
  auto typedName = createAsmNode<TypedName>(_node);
75
0
  typedName.type = YulString{member(_node, "type").asString()};
76
0
  typedName.name = YulString{member(_node, "name").asString()};
77
0
  return typedName;
78
0
}
79
80
Statement AsmJsonImporter::createStatement(Json::Value const& _node)
81
0
{
82
0
  Json::Value jsonNodeType = member(_node, "nodeType");
83
0
  yulAssert(jsonNodeType.isString(), "Expected \"nodeType\" to be of type string!");
84
0
  string nodeType = jsonNodeType.asString();
85
86
0
  yulAssert(nodeType.substr(0, 3) == "Yul", "Invalid nodeType prefix");
87
0
  nodeType = nodeType.substr(3);
88
89
0
  if (nodeType == "ExpressionStatement")
90
0
    return createExpressionStatement(_node);
91
0
  else if (nodeType == "Assignment")
92
0
    return createAssignment(_node);
93
0
  else if (nodeType == "VariableDeclaration")
94
0
    return createVariableDeclaration(_node);
95
0
  else if (nodeType == "FunctionDefinition")
96
0
    return createFunctionDefinition(_node);
97
0
  else if (nodeType == "If")
98
0
    return createIf(_node);
99
0
  else if (nodeType == "Switch")
100
0
    return createSwitch(_node);
101
0
  else if (nodeType == "ForLoop")
102
0
    return createForLoop(_node);
103
0
  else if (nodeType == "Break")
104
0
    return createBreak(_node);
105
0
  else if (nodeType == "Continue")
106
0
    return createContinue(_node);
107
0
  else if (nodeType == "Leave")
108
0
    return createLeave(_node);
109
0
  else if (nodeType == "Block")
110
0
    return createBlock(_node);
111
0
  else
112
0
    yulAssert(false, "Invalid nodeType as statement");
113
114
  // FIXME: Workaround for spurious GCC 12.1 warning (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105794)
115
0
  util::unreachable();
116
0
}
117
118
Expression AsmJsonImporter::createExpression(Json::Value const& _node)
119
0
{
120
0
  Json::Value jsonNodeType = member(_node, "nodeType");
121
0
  yulAssert(jsonNodeType.isString(), "Expected \"nodeType\" to be of type string!");
122
0
  string nodeType = jsonNodeType.asString();
123
124
0
  yulAssert(nodeType.substr(0, 3) == "Yul", "Invalid nodeType prefix");
125
0
  nodeType = nodeType.substr(3);
126
127
0
  if (nodeType == "FunctionCall")
128
0
    return createFunctionCall(_node);
129
0
  else if (nodeType == "Identifier")
130
0
    return createIdentifier(_node);
131
0
  else if (nodeType == "Literal")
132
0
    return createLiteral(_node);
133
0
  else
134
0
    yulAssert(false, "Invalid nodeType as expression");
135
136
  // FIXME: Workaround for spurious GCC 12.1 warning (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105794)
137
0
  util::unreachable();
138
0
}
139
140
vector<Expression> AsmJsonImporter::createExpressionVector(Json::Value const& _array)
141
0
{
142
0
  vector<Expression> ret;
143
0
  for (auto& var: _array)
144
0
    ret.emplace_back(createExpression(var));
145
0
  return ret;
146
0
}
147
148
vector<Statement> AsmJsonImporter::createStatementVector(Json::Value const& _array)
149
0
{
150
0
  vector<Statement> ret;
151
0
  for (auto& var: _array)
152
0
    ret.emplace_back(createStatement(var));
153
0
  return ret;
154
0
}
155
156
Block AsmJsonImporter::createBlock(Json::Value const& _node)
157
0
{
158
0
  auto block = createAsmNode<Block>(_node);
159
0
  block.statements = createStatementVector(_node["statements"]);
160
0
  return block;
161
0
}
162
163
Literal AsmJsonImporter::createLiteral(Json::Value const& _node)
164
0
{
165
0
  auto lit = createAsmNode<Literal>(_node);
166
0
  string kind = member(_node, "kind").asString();
167
168
0
  solAssert(member(_node, "hexValue").isString() || member(_node, "value").isString(), "");
169
0
  if (_node.isMember("hexValue"))
170
0
    lit.value = YulString{util::asString(util::fromHex(member(_node, "hexValue").asString()))};
171
0
  else
172
0
    lit.value = YulString{member(_node, "value").asString()};
173
174
0
  lit.type= YulString{member(_node, "type").asString()};
175
176
0
  if (kind == "number")
177
0
  {
178
0
    langutil::CharStream charStream(lit.value.str(), "");
179
0
    langutil::Scanner scanner{charStream};
180
0
    lit.kind = LiteralKind::Number;
181
0
    yulAssert(
182
0
      scanner.currentToken() == Token::Number,
183
0
      "Expected number but got " + langutil::TokenTraits::friendlyName(scanner.currentToken()) + string(" while scanning ") + lit.value.str()
184
0
    );
185
0
  }
186
0
  else if (kind == "bool")
187
0
  {
188
0
    langutil::CharStream charStream(lit.value.str(), "");
189
0
    langutil::Scanner scanner{charStream};
190
0
    lit.kind = LiteralKind::Boolean;
191
0
    yulAssert(
192
0
      scanner.currentToken() == Token::TrueLiteral ||
193
0
      scanner.currentToken() == Token::FalseLiteral,
194
0
      "Expected true/false literal!"
195
0
    );
196
0
  }
197
0
  else if (kind == "string")
198
0
  {
199
0
    lit.kind = LiteralKind::String;
200
0
    yulAssert(
201
0
      lit.value.str().size() <= 32,
202
0
      "String literal too long (" + to_string(lit.value.str().size()) + " > 32)"
203
0
    );
204
0
  }
205
0
  else
206
0
    yulAssert(false, "unknown type of literal");
207
208
0
  return lit;
209
0
}
210
211
Leave AsmJsonImporter::createLeave(Json::Value const& _node)
212
0
{
213
0
  return createAsmNode<Leave>(_node);
214
0
}
215
216
Identifier AsmJsonImporter::createIdentifier(Json::Value const& _node)
217
0
{
218
0
  auto identifier = createAsmNode<Identifier>(_node);
219
0
  identifier.name = YulString(member(_node, "name").asString());
220
0
  return identifier;
221
0
}
222
223
Assignment AsmJsonImporter::createAssignment(Json::Value const& _node)
224
0
{
225
0
  auto assignment = createAsmNode<Assignment>(_node);
226
227
0
  if (_node.isMember("variableNames"))
228
0
    for (auto const& var: member(_node, "variableNames"))
229
0
      assignment.variableNames.emplace_back(createIdentifier(var));
230
231
0
  assignment.value = make_unique<Expression>(createExpression(member(_node, "value")));
232
0
  return assignment;
233
0
}
234
235
FunctionCall AsmJsonImporter::createFunctionCall(Json::Value const& _node)
236
0
{
237
0
  auto functionCall = createAsmNode<FunctionCall>(_node);
238
239
0
  for (auto const& var: member(_node, "arguments"))
240
0
    functionCall.arguments.emplace_back(createExpression(var));
241
242
0
  functionCall.functionName = createIdentifier(member(_node, "functionName"));
243
244
0
  return functionCall;
245
0
}
246
247
ExpressionStatement AsmJsonImporter::createExpressionStatement(Json::Value const& _node)
248
0
{
249
0
  auto statement = createAsmNode<ExpressionStatement>(_node);
250
0
  statement.expression = createExpression(member(_node, "expression"));
251
0
  return statement;
252
0
}
253
254
VariableDeclaration AsmJsonImporter::createVariableDeclaration(Json::Value const& _node)
255
0
{
256
0
  auto varDec = createAsmNode<VariableDeclaration>(_node);
257
0
  for (auto const& var: member(_node, "variables"))
258
0
    varDec.variables.emplace_back(createTypedName(var));
259
0
  varDec.value = make_unique<Expression>(createExpression(member(_node, "value")));
260
0
  return varDec;
261
0
}
262
263
FunctionDefinition AsmJsonImporter::createFunctionDefinition(Json::Value const& _node)
264
0
{
265
0
  auto funcDef = createAsmNode<FunctionDefinition>(_node);
266
0
  funcDef.name = YulString{member(_node, "name").asString()};
267
268
0
  if (_node.isMember("parameters"))
269
0
    for (auto const& var: member(_node, "parameters"))
270
0
      funcDef.parameters.emplace_back(createTypedName(var));
271
272
0
  if (_node.isMember("returnVariables"))
273
0
    for (auto const& var: member(_node, "returnVariables"))
274
0
      funcDef.returnVariables.emplace_back(createTypedName(var));
275
276
0
  funcDef.body = createBlock(member(_node, "body"));
277
0
  return funcDef;
278
0
}
279
280
If AsmJsonImporter::createIf(Json::Value const& _node)
281
0
{
282
0
  auto ifStatement = createAsmNode<If>(_node);
283
0
  ifStatement.condition = make_unique<Expression>(createExpression(member(_node, "condition")));
284
0
  ifStatement.body = createBlock(member(_node, "body"));
285
0
  return ifStatement;
286
0
}
287
288
Case AsmJsonImporter::createCase(Json::Value const& _node)
289
0
{
290
0
  auto caseStatement = createAsmNode<Case>(_node);
291
0
  auto const& value = member(_node, "value");
292
0
  if (value.isString())
293
0
    yulAssert(value.asString() == "default", "Expected default case");
294
0
  else
295
0
    caseStatement.value = make_unique<Literal>(createLiteral(value));
296
0
  caseStatement.body = createBlock(member(_node, "body"));
297
0
  return caseStatement;
298
0
}
299
300
Switch AsmJsonImporter::createSwitch(Json::Value const& _node)
301
0
{
302
0
  auto switchStatement = createAsmNode<Switch>(_node);
303
0
  switchStatement.expression = make_unique<Expression>(createExpression(member(_node, "expression")));
304
0
  for (auto const& var: member(_node, "cases"))
305
0
    switchStatement.cases.emplace_back(createCase(var));
306
0
  return switchStatement;
307
0
}
308
309
ForLoop AsmJsonImporter::createForLoop(Json::Value const& _node)
310
0
{
311
0
  auto forLoop = createAsmNode<ForLoop>(_node);
312
0
  forLoop.pre = createBlock(member(_node, "pre"));
313
0
  forLoop.condition = make_unique<Expression>(createExpression(member(_node, "condition")));
314
0
  forLoop.post = createBlock(member(_node, "post"));
315
0
  forLoop.body = createBlock(member(_node, "body"));
316
0
  return forLoop;
317
0
}
318
319
Break AsmJsonImporter::createBreak(Json::Value const& _node)
320
0
{
321
0
  return createAsmNode<Break>(_node);
322
0
}
323
324
Continue AsmJsonImporter::createContinue(Json::Value const& _node)
325
0
{
326
0
  return createAsmNode<Continue>(_node);
327
0
}
328
329
}