mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7153 from djudjuu/newImportAST
import ast from JSON
This commit is contained in:
commit
b3fe84a6ea
@ -6,6 +6,7 @@ Language Features:
|
||||
|
||||
Compiler Features:
|
||||
* General: Raise warning if runtime bytecode exceeds 24576 bytes (a limit introduced in Spurious Dragon).
|
||||
* General: Support compiling starting from an imported AST. Among others, this can be used for mutation testing.
|
||||
* Yul Optimizer: Apply penalty when trying to rematerialize into loops.
|
||||
|
||||
Bugfixes:
|
||||
|
@ -16,6 +16,7 @@ set(sources
|
||||
SemVerHandler.cpp
|
||||
SemVerHandler.h
|
||||
SourceLocation.h
|
||||
SourceLocation.cpp
|
||||
SourceReferenceExtractor.cpp
|
||||
SourceReferenceExtractor.h
|
||||
SourceReferenceFormatter.cpp
|
||||
|
@ -40,6 +40,7 @@ struct CompilerError: virtual util::Exception {};
|
||||
struct InternalCompilerError: virtual util::Exception {};
|
||||
struct FatalError: virtual util::Exception {};
|
||||
struct UnimplementedFeatureError: virtual util::Exception {};
|
||||
struct InvalidAstError: virtual util::Exception {};
|
||||
|
||||
/// Assertion that throws an InternalCompilerError containing the given description if it is not met.
|
||||
#define solAssert(CONDITION, DESCRIPTION) \
|
||||
@ -51,6 +52,9 @@ struct UnimplementedFeatureError: virtual util::Exception {};
|
||||
#define solUnimplemented(DESCRIPTION) \
|
||||
solUnimplementedAssert(false, DESCRIPTION)
|
||||
|
||||
#define astAssert(CONDITION, DESCRIPTION) \
|
||||
assertThrow(CONDITION, ::solidity::langutil::InvalidAstError, DESCRIPTION)
|
||||
|
||||
class Error: virtual public util::Exception
|
||||
{
|
||||
public:
|
||||
|
51
liblangutil/SourceLocation.cpp
Normal file
51
liblangutil/SourceLocation.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
using namespace solidity;
|
||||
namespace solidity::langutil
|
||||
{
|
||||
|
||||
SourceLocation const parseSourceLocation(std::string const& _input, std::string const& _sourceName, size_t _maxIndex)
|
||||
{
|
||||
// Expected input: "start:length:sourceindex"
|
||||
enum SrcElem : size_t { Start, Length, Index };
|
||||
|
||||
std::vector<std::string> pos;
|
||||
|
||||
boost::algorithm::split(pos, _input, boost::is_any_of(":"));
|
||||
|
||||
astAssert(
|
||||
pos.size() == 3 &&
|
||||
_maxIndex >= static_cast<size_t>(stoi(pos[Index])),
|
||||
"'src'-field ill-formatted or src-index too high"
|
||||
);
|
||||
|
||||
int start = stoi(pos[Start]);
|
||||
int end = start + stoi(pos[Length]);
|
||||
|
||||
// ASSUMPTION: only the name of source is used from here on, the m_source of the CharStream-Object can be empty
|
||||
std::shared_ptr<langutil::CharStream> source = std::make_shared<langutil::CharStream>("", _sourceName);
|
||||
|
||||
return SourceLocation{start, end, source};
|
||||
}
|
||||
|
||||
}
|
@ -23,13 +23,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <libsolutil/Assertions.h>
|
||||
#include <libsolutil/Common.h> // defines noexcept macro for MSVC
|
||||
#include <libsolutil/Exceptions.h>
|
||||
|
||||
#include <liblangutil/CharStream.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
|
||||
namespace solidity::langutil
|
||||
{
|
||||
@ -46,9 +45,28 @@ struct SourceLocation
|
||||
return source.get() == _other.source.get() && start == _other.start && end == _other.end;
|
||||
}
|
||||
bool operator!=(SourceLocation const& _other) const { return !operator==(_other); }
|
||||
inline bool operator<(SourceLocation const& _other) const;
|
||||
inline bool contains(SourceLocation const& _other) const;
|
||||
inline bool intersects(SourceLocation const& _other) const;
|
||||
|
||||
inline bool operator<(SourceLocation const& _other) const
|
||||
{
|
||||
if (!source|| !_other.source)
|
||||
return std::make_tuple(int(!!source), start, end) < std::make_tuple(int(!!_other.source), _other.start, _other.end);
|
||||
else
|
||||
return std::make_tuple(source->name(), start, end) < std::make_tuple(_other.source->name(), _other.start, _other.end);
|
||||
}
|
||||
|
||||
inline bool contains(SourceLocation const& _other) const
|
||||
{
|
||||
if (isEmpty() || _other.isEmpty() || source.get() != _other.source.get())
|
||||
return false;
|
||||
return start <= _other.start && _other.end <= end;
|
||||
}
|
||||
|
||||
inline bool intersects(SourceLocation const& _other) const
|
||||
{
|
||||
if (isEmpty() || _other.isEmpty() || source.get() != _other.source.get())
|
||||
return false;
|
||||
return _other.start < end && start < _other.end;
|
||||
}
|
||||
|
||||
bool isEmpty() const { return start == -1 && end == -1; }
|
||||
|
||||
@ -86,6 +104,8 @@ struct SourceLocation
|
||||
std::shared_ptr<CharStream> source;
|
||||
};
|
||||
|
||||
SourceLocation const parseSourceLocation(std::string const& _input, std::string const& _sourceName, size_t _maxIndex = -1);
|
||||
|
||||
/// Stream output for Location (used e.g. in boost exceptions).
|
||||
inline std::ostream& operator<<(std::ostream& _out, SourceLocation const& _location)
|
||||
{
|
||||
@ -100,26 +120,4 @@ inline std::ostream& operator<<(std::ostream& _out, SourceLocation const& _locat
|
||||
return _out;
|
||||
}
|
||||
|
||||
bool SourceLocation::operator<(SourceLocation const& _other) const
|
||||
{
|
||||
if (!source|| !_other.source)
|
||||
return std::make_tuple(int(!!source), start, end) < std::make_tuple(int(!!_other.source), _other.start, _other.end);
|
||||
else
|
||||
return std::make_tuple(source->name(), start, end) < std::make_tuple(_other.source->name(), _other.start, _other.end);
|
||||
}
|
||||
|
||||
bool SourceLocation::contains(SourceLocation const& _other) const
|
||||
{
|
||||
if (isEmpty() || _other.isEmpty() || source.get() != _other.source.get())
|
||||
return false;
|
||||
return start <= _other.start && _other.end <= end;
|
||||
}
|
||||
|
||||
bool SourceLocation::intersects(SourceLocation const& _other) const
|
||||
{
|
||||
if (isEmpty() || _other.isEmpty() || source.get() != _other.source.get())
|
||||
return false;
|
||||
return _other.start < end && start < _other.end;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,10 +39,14 @@ set(sources
|
||||
ast/ASTAnnotations.h
|
||||
ast/ASTEnums.h
|
||||
ast/ASTForward.h
|
||||
ast/AsmJsonImporter.cpp
|
||||
ast/AsmJsonImporter.h
|
||||
ast/ASTJsonConverter.cpp
|
||||
ast/ASTJsonConverter.h
|
||||
ast/ASTUtils.cpp
|
||||
ast/ASTUtils.h
|
||||
ast/ASTJsonImporter.cpp
|
||||
ast/ASTJsonImporter.h
|
||||
ast/ASTVisitor.h
|
||||
ast/ExperimentalFeatures.h
|
||||
ast/Types.cpp
|
||||
|
@ -33,10 +33,44 @@ using namespace std;
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
/// Magic variables get negative ids for easy differentiation
|
||||
int magicVariableToID(std::string const& _name)
|
||||
{
|
||||
if (_name == "abi") return -1;
|
||||
else if (_name == "addmod") return -2;
|
||||
else if (_name == "assert") return -3;
|
||||
else if (_name == "block") return -4;
|
||||
else if (_name == "blockhash") return -5;
|
||||
else if (_name == "ecrecover") return -6;
|
||||
else if (_name == "gasleft") return -7;
|
||||
else if (_name == "keccak256") return -8;
|
||||
else if (_name == "log0") return -10;
|
||||
else if (_name == "log1") return -11;
|
||||
else if (_name == "log2") return -12;
|
||||
else if (_name == "log3") return -13;
|
||||
else if (_name == "log4") return -14;
|
||||
else if (_name == "msg") return -15;
|
||||
else if (_name == "mulmod") return -16;
|
||||
else if (_name == "now") return -17;
|
||||
else if (_name == "require") return -18;
|
||||
else if (_name == "revert") return -19;
|
||||
else if (_name == "ripemd160") return -20;
|
||||
else if (_name == "selfdestruct") return -21;
|
||||
else if (_name == "sha256") return -22;
|
||||
else if (_name == "sha3") return -23;
|
||||
else if (_name == "suicide") return -24;
|
||||
else if (_name == "super") return -25;
|
||||
else if (_name == "tx") return -26;
|
||||
else if (_name == "type") return -27;
|
||||
else if (_name == "this") return -28;
|
||||
else
|
||||
solAssert(false, "Unknown magic variable: \"" + _name + "\".");
|
||||
}
|
||||
|
||||
inline vector<shared_ptr<MagicVariableDeclaration const>> constructMagicVariables()
|
||||
{
|
||||
static auto const magicVarDecl = [](string const& _name, Type const* _type) {
|
||||
return make_shared<MagicVariableDeclaration>(_name, _type);
|
||||
return make_shared<MagicVariableDeclaration>(magicVariableToID(_name), _name, _type);
|
||||
};
|
||||
|
||||
return {
|
||||
@ -97,7 +131,7 @@ vector<Declaration const*> GlobalContext::declarations() const
|
||||
MagicVariableDeclaration const* GlobalContext::currentThis() const
|
||||
{
|
||||
if (!m_thisPointer[m_currentContract])
|
||||
m_thisPointer[m_currentContract] = make_shared<MagicVariableDeclaration>("this", TypeProvider::contract(*m_currentContract));
|
||||
m_thisPointer[m_currentContract] = make_shared<MagicVariableDeclaration>(magicVariableToID("this"), "this", TypeProvider::contract(*m_currentContract));
|
||||
return m_thisPointer[m_currentContract].get();
|
||||
|
||||
}
|
||||
@ -105,7 +139,7 @@ MagicVariableDeclaration const* GlobalContext::currentThis() const
|
||||
MagicVariableDeclaration const* GlobalContext::currentSuper() const
|
||||
{
|
||||
if (!m_superPointer[m_currentContract])
|
||||
m_superPointer[m_currentContract] = make_shared<MagicVariableDeclaration>("super", TypeProvider::contract(*m_currentContract, true));
|
||||
m_superPointer[m_currentContract] = make_shared<MagicVariableDeclaration>(magicVariableToID("super"), "super", TypeProvider::contract(*m_currentContract, true));
|
||||
return m_superPointer[m_currentContract].get();
|
||||
}
|
||||
|
||||
|
@ -35,31 +35,12 @@ using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::frontend;
|
||||
|
||||
class IDDispenser
|
||||
{
|
||||
public:
|
||||
static size_t next() { return ++instance(); }
|
||||
static void reset() { instance() = 0; }
|
||||
private:
|
||||
static size_t& instance()
|
||||
{
|
||||
static IDDispenser dispenser;
|
||||
return dispenser.id;
|
||||
}
|
||||
size_t id = 0;
|
||||
};
|
||||
|
||||
ASTNode::ASTNode(SourceLocation const& _location):
|
||||
m_id(IDDispenser::next()),
|
||||
ASTNode::ASTNode(int64_t _id, SourceLocation const& _location):
|
||||
m_id(_id),
|
||||
m_location(_location)
|
||||
{
|
||||
}
|
||||
|
||||
void ASTNode::resetID()
|
||||
{
|
||||
IDDispenser::reset();
|
||||
}
|
||||
|
||||
ASTAnnotation& ASTNode::annotation() const
|
||||
{
|
||||
if (!m_annotation)
|
||||
|
@ -64,13 +64,11 @@ class ASTNode: private boost::noncopyable
|
||||
public:
|
||||
using SourceLocation = langutil::SourceLocation;
|
||||
|
||||
explicit ASTNode(SourceLocation const& _location);
|
||||
explicit ASTNode(int64_t _id, SourceLocation const& _location);
|
||||
virtual ~ASTNode() {}
|
||||
|
||||
/// @returns an identifier of this AST node that is unique for a single compilation run.
|
||||
size_t id() const { return m_id; }
|
||||
/// Resets the global ID counter. This invalidates all previous IDs.
|
||||
static void resetID();
|
||||
int64_t id() const { return m_id; }
|
||||
|
||||
virtual void accept(ASTVisitor& _visitor) = 0;
|
||||
virtual void accept(ASTConstVisitor& _visitor) const = 0;
|
||||
@ -139,8 +137,8 @@ std::vector<_T const*> ASTNode::filteredNodes(std::vector<ASTPointer<ASTNode>> c
|
||||
class SourceUnit: public ASTNode
|
||||
{
|
||||
public:
|
||||
SourceUnit(SourceLocation const& _location, std::vector<ASTPointer<ASTNode>> const& _nodes):
|
||||
ASTNode(_location), m_nodes(_nodes) {}
|
||||
SourceUnit(int64_t _id, SourceLocation const& _location, std::vector<ASTPointer<ASTNode>> const& _nodes):
|
||||
ASTNode(_id, _location), m_nodes(_nodes) {}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
@ -206,11 +204,12 @@ public:
|
||||
}
|
||||
|
||||
Declaration(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
Visibility _visibility = Visibility::Default
|
||||
):
|
||||
ASTNode(_location), m_name(_name), m_visibility(_visibility) {}
|
||||
ASTNode(_id, _location), m_name(_name), m_visibility(_visibility) {}
|
||||
|
||||
/// @returns the declared name.
|
||||
ASTString const& name() const { return *m_name; }
|
||||
@ -253,10 +252,11 @@ class PragmaDirective: public ASTNode
|
||||
{
|
||||
public:
|
||||
PragmaDirective(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
std::vector<Token> const& _tokens,
|
||||
std::vector<ASTString> const& _literals
|
||||
): ASTNode(_location), m_tokens(_tokens), m_literals(_literals)
|
||||
): ASTNode(_id, _location), m_tokens(_tokens), m_literals(_literals)
|
||||
{}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
@ -295,12 +295,13 @@ public:
|
||||
using SymbolAliasList = std::vector<SymbolAlias>;
|
||||
|
||||
ImportDirective(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _path,
|
||||
ASTPointer<ASTString> const& _unitAlias,
|
||||
SymbolAliasList _symbolAliases
|
||||
):
|
||||
Declaration(_location, _unitAlias),
|
||||
Declaration(_id, _location, _unitAlias),
|
||||
m_path(_path),
|
||||
m_symbolAliases(move(_symbolAliases))
|
||||
{ }
|
||||
@ -385,6 +386,7 @@ class ContractDefinition: public Declaration, public Documented
|
||||
{
|
||||
public:
|
||||
ContractDefinition(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
ASTPointer<ASTString> const& _documentation,
|
||||
@ -393,7 +395,7 @@ public:
|
||||
ContractKind _contractKind = ContractKind::Contract,
|
||||
bool _abstract = false
|
||||
):
|
||||
Declaration(_location, _name),
|
||||
Declaration(_id, _location, _name),
|
||||
Documented(_documentation),
|
||||
m_baseContracts(_baseContracts),
|
||||
m_subNodes(_subNodes),
|
||||
@ -465,11 +467,12 @@ class InheritanceSpecifier: public ASTNode
|
||||
{
|
||||
public:
|
||||
InheritanceSpecifier(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<UserDefinedTypeName> const& _baseName,
|
||||
std::unique_ptr<std::vector<ASTPointer<Expression>>> _arguments
|
||||
):
|
||||
ASTNode(_location), m_baseName(_baseName), m_arguments(std::move(_arguments)) {}
|
||||
ASTNode(_id, _location), m_baseName(_baseName), m_arguments(std::move(_arguments)) {}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
@ -494,11 +497,12 @@ class UsingForDirective: public ASTNode
|
||||
{
|
||||
public:
|
||||
UsingForDirective(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<UserDefinedTypeName> const& _libraryName,
|
||||
ASTPointer<TypeName> const& _typeName
|
||||
):
|
||||
ASTNode(_location), m_libraryName(_libraryName), m_typeName(_typeName) {}
|
||||
ASTNode(_id, _location), m_libraryName(_libraryName), m_typeName(_typeName) {}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
@ -516,11 +520,12 @@ class StructDefinition: public Declaration
|
||||
{
|
||||
public:
|
||||
StructDefinition(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
std::vector<ASTPointer<VariableDeclaration>> const& _members
|
||||
):
|
||||
Declaration(_location, _name), m_members(_members) {}
|
||||
Declaration(_id, _location, _name), m_members(_members) {}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
@ -539,11 +544,12 @@ class EnumDefinition: public Declaration
|
||||
{
|
||||
public:
|
||||
EnumDefinition(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
std::vector<ASTPointer<EnumValue>> const& _members
|
||||
):
|
||||
Declaration(_location, _name), m_members(_members) {}
|
||||
Declaration(_id, _location, _name), m_members(_members) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -563,8 +569,8 @@ private:
|
||||
class EnumValue: public Declaration
|
||||
{
|
||||
public:
|
||||
EnumValue(SourceLocation const& _location, ASTPointer<ASTString> const& _name):
|
||||
Declaration(_location, _name) {}
|
||||
EnumValue(int64_t _id, SourceLocation const& _location, ASTPointer<ASTString> const& _name):
|
||||
Declaration(_id, _location, _name) {}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
@ -581,10 +587,11 @@ class ParameterList: public ASTNode
|
||||
{
|
||||
public:
|
||||
ParameterList(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
std::vector<ASTPointer<VariableDeclaration>> const& _parameters
|
||||
):
|
||||
ASTNode(_location), m_parameters(_parameters) {}
|
||||
ASTNode(_id, _location), m_parameters(_parameters) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -602,6 +609,7 @@ class CallableDeclaration: public Declaration, public VariableScope
|
||||
{
|
||||
public:
|
||||
CallableDeclaration(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
Visibility _visibility,
|
||||
@ -610,7 +618,7 @@ public:
|
||||
ASTPointer<OverrideSpecifier> const& _overrides = nullptr,
|
||||
ASTPointer<ParameterList> const& _returnParameters = ASTPointer<ParameterList>()
|
||||
):
|
||||
Declaration(_location, _name, _visibility),
|
||||
Declaration(_id, _location, _name, _visibility),
|
||||
m_parameters(_parameters),
|
||||
m_overrides(_overrides),
|
||||
m_returnParameters(_returnParameters),
|
||||
@ -643,10 +651,11 @@ class OverrideSpecifier: public ASTNode
|
||||
{
|
||||
public:
|
||||
OverrideSpecifier(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
std::vector<ASTPointer<UserDefinedTypeName>> const& _overrides
|
||||
):
|
||||
ASTNode(_location),
|
||||
ASTNode(_id, _location),
|
||||
m_overrides(_overrides)
|
||||
{
|
||||
}
|
||||
@ -665,6 +674,7 @@ class FunctionDefinition: public CallableDeclaration, public Documented, public
|
||||
{
|
||||
public:
|
||||
FunctionDefinition(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
Visibility _visibility,
|
||||
@ -678,7 +688,7 @@ public:
|
||||
ASTPointer<ParameterList> const& _returnParameters,
|
||||
ASTPointer<Block> const& _body
|
||||
):
|
||||
CallableDeclaration(_location, _name, _visibility, _parameters, _isVirtual, _overrides, _returnParameters),
|
||||
CallableDeclaration(_id, _location, _name, _visibility, _parameters, _isVirtual, _overrides, _returnParameters),
|
||||
Documented(_documentation),
|
||||
ImplementationOptional(_body != nullptr),
|
||||
m_stateMutability(_stateMutability),
|
||||
@ -748,7 +758,8 @@ public:
|
||||
enum Location { Unspecified, Storage, Memory, CallData };
|
||||
|
||||
VariableDeclaration(
|
||||
SourceLocation const& _sourceLocation,
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<TypeName> const& _type,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
ASTPointer<Expression> _value,
|
||||
@ -759,7 +770,7 @@ public:
|
||||
ASTPointer<OverrideSpecifier> const& _overrides = nullptr,
|
||||
Location _referenceLocation = Location::Unspecified
|
||||
):
|
||||
Declaration(_sourceLocation, _name, _visibility),
|
||||
Declaration(_id, _location, _name, _visibility),
|
||||
m_typeName(_type),
|
||||
m_value(_value),
|
||||
m_isStateVariable(_isStateVar),
|
||||
@ -847,6 +858,7 @@ class ModifierDefinition: public CallableDeclaration, public Documented
|
||||
{
|
||||
public:
|
||||
ModifierDefinition(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
ASTPointer<ASTString> const& _documentation,
|
||||
@ -855,7 +867,7 @@ public:
|
||||
ASTPointer<OverrideSpecifier> const& _overrides,
|
||||
ASTPointer<Block> const& _body
|
||||
):
|
||||
CallableDeclaration(_location, _name, Visibility::Internal, _parameters, _isVirtual, _overrides),
|
||||
CallableDeclaration(_id, _location, _name, Visibility::Internal, _parameters, _isVirtual, _overrides),
|
||||
Documented(_documentation),
|
||||
m_body(_body)
|
||||
{
|
||||
@ -881,11 +893,12 @@ class ModifierInvocation: public ASTNode
|
||||
{
|
||||
public:
|
||||
ModifierInvocation(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<Identifier> const& _name,
|
||||
std::unique_ptr<std::vector<ASTPointer<Expression>>> _arguments
|
||||
):
|
||||
ASTNode(_location), m_modifierName(_name), m_arguments(std::move(_arguments)) {}
|
||||
ASTNode(_id, _location), m_modifierName(_name), m_arguments(std::move(_arguments)) {}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
@ -908,13 +921,14 @@ class EventDefinition: public CallableDeclaration, public Documented
|
||||
{
|
||||
public:
|
||||
EventDefinition(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
ASTPointer<ASTString> const& _documentation,
|
||||
ASTPointer<ParameterList> const& _parameters,
|
||||
bool _anonymous = false
|
||||
):
|
||||
CallableDeclaration(_location, _name, Visibility::Default, _parameters),
|
||||
CallableDeclaration(_id, _location, _name, Visibility::Default, _parameters),
|
||||
Documented(_documentation),
|
||||
m_anonymous(_anonymous)
|
||||
{
|
||||
@ -936,13 +950,13 @@ private:
|
||||
|
||||
/**
|
||||
* Pseudo AST node that is used as declaration for "this", "msg", "tx", "block" and the global
|
||||
* functions when such an identifier is encountered. Will never have a valid location in the source code.
|
||||
* functions when such an identifier is encountered. Will never have a valid location in the source code
|
||||
*/
|
||||
class MagicVariableDeclaration: public Declaration
|
||||
{
|
||||
public:
|
||||
MagicVariableDeclaration(ASTString const& _name, Type const* _type):
|
||||
Declaration(SourceLocation(), std::make_shared<ASTString>(_name)), m_type(_type) {}
|
||||
MagicVariableDeclaration(int _id, ASTString const& _name, Type const* _type):
|
||||
Declaration(_id, SourceLocation(), std::make_shared<ASTString>(_name)), m_type(_type) { }
|
||||
|
||||
void accept(ASTVisitor&) override
|
||||
{
|
||||
@ -973,7 +987,7 @@ private:
|
||||
class TypeName: public ASTNode
|
||||
{
|
||||
protected:
|
||||
explicit TypeName(SourceLocation const& _location): ASTNode(_location) {}
|
||||
explicit TypeName(int64_t _id, SourceLocation const& _location): ASTNode(_id, _location) {}
|
||||
|
||||
public:
|
||||
TypeNameAnnotation& annotation() const override;
|
||||
@ -987,10 +1001,11 @@ class ElementaryTypeName: public TypeName
|
||||
{
|
||||
public:
|
||||
ElementaryTypeName(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ElementaryTypeNameToken const& _elem,
|
||||
std::optional<StateMutability> _stateMutability = {}
|
||||
): TypeName(_location), m_type(_elem), m_stateMutability(_stateMutability)
|
||||
): TypeName(_id, _location), m_type(_elem), m_stateMutability(_stateMutability)
|
||||
{
|
||||
solAssert(!_stateMutability.has_value() || _elem.token() == Token::Address, "");
|
||||
}
|
||||
@ -1013,8 +1028,8 @@ private:
|
||||
class UserDefinedTypeName: public TypeName
|
||||
{
|
||||
public:
|
||||
UserDefinedTypeName(SourceLocation const& _location, std::vector<ASTString> const& _namePath):
|
||||
TypeName(_location), m_namePath(_namePath) {}
|
||||
UserDefinedTypeName(int64_t _id, SourceLocation const& _location, std::vector<ASTString> const& _namePath):
|
||||
TypeName(_id, _location), m_namePath(_namePath) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1033,13 +1048,14 @@ class FunctionTypeName: public TypeName
|
||||
{
|
||||
public:
|
||||
FunctionTypeName(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ParameterList> const& _parameterTypes,
|
||||
ASTPointer<ParameterList> const& _returnTypes,
|
||||
Visibility _visibility,
|
||||
StateMutability _stateMutability
|
||||
):
|
||||
TypeName(_location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes),
|
||||
TypeName(_id, _location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes),
|
||||
m_visibility(_visibility), m_stateMutability(_stateMutability)
|
||||
{}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
@ -1071,11 +1087,12 @@ class Mapping: public TypeName
|
||||
{
|
||||
public:
|
||||
Mapping(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ElementaryTypeName> const& _keyType,
|
||||
ASTPointer<TypeName> const& _valueType
|
||||
):
|
||||
TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) {}
|
||||
TypeName(_id, _location), m_keyType(_keyType), m_valueType(_valueType) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1094,11 +1111,12 @@ class ArrayTypeName: public TypeName
|
||||
{
|
||||
public:
|
||||
ArrayTypeName(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<TypeName> const& _baseType,
|
||||
ASTPointer<Expression> const& _length
|
||||
):
|
||||
TypeName(_location), m_baseType(_baseType), m_length(_length) {}
|
||||
TypeName(_id, _location), m_baseType(_baseType), m_length(_length) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1123,9 +1141,10 @@ class Statement: public ASTNode, public Documented
|
||||
{
|
||||
public:
|
||||
explicit Statement(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString
|
||||
): ASTNode(_location), Documented(_docString) {}
|
||||
): ASTNode(_id, _location), Documented(_docString) {}
|
||||
|
||||
StatementAnnotation& annotation() const override;
|
||||
};
|
||||
@ -1137,12 +1156,13 @@ class InlineAssembly: public Statement
|
||||
{
|
||||
public:
|
||||
InlineAssembly(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString,
|
||||
yul::Dialect const& _dialect,
|
||||
std::shared_ptr<yul::Block> const& _operations
|
||||
):
|
||||
Statement(_location, _docString), m_dialect(_dialect), m_operations(_operations) {}
|
||||
Statement(_id, _location, _docString), m_dialect(_dialect), m_operations(_operations) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1163,11 +1183,12 @@ class Block: public Statement, public Scopable
|
||||
{
|
||||
public:
|
||||
Block(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString,
|
||||
std::vector<ASTPointer<Statement>> const& _statements
|
||||
):
|
||||
Statement(_location, _docString), m_statements(_statements) {}
|
||||
Statement(_id, _location, _docString), m_statements(_statements) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1187,9 +1208,10 @@ class PlaceholderStatement: public Statement
|
||||
{
|
||||
public:
|
||||
explicit PlaceholderStatement(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString
|
||||
): Statement(_location, _docString) {}
|
||||
): Statement(_id, _location, _docString) {}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
@ -1203,13 +1225,14 @@ class IfStatement: public Statement
|
||||
{
|
||||
public:
|
||||
IfStatement(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString,
|
||||
ASTPointer<Expression> const& _condition,
|
||||
ASTPointer<Statement> const& _trueBody,
|
||||
ASTPointer<Statement> const& _falseBody
|
||||
):
|
||||
Statement(_location, _docString),
|
||||
Statement(_id, _location, _docString),
|
||||
m_condition(_condition),
|
||||
m_trueBody(_trueBody),
|
||||
m_falseBody(_falseBody)
|
||||
@ -1237,12 +1260,13 @@ class TryCatchClause: public ASTNode, public Scopable
|
||||
{
|
||||
public:
|
||||
TryCatchClause(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _errorName,
|
||||
ASTPointer<ParameterList> const& _parameters,
|
||||
ASTPointer<Block> const& _block
|
||||
):
|
||||
ASTNode(_location),
|
||||
ASTNode(_id, _location),
|
||||
m_errorName(_errorName),
|
||||
m_parameters(_parameters),
|
||||
m_block(_block)
|
||||
@ -1280,12 +1304,13 @@ class TryStatement: public Statement
|
||||
{
|
||||
public:
|
||||
TryStatement(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString,
|
||||
ASTPointer<Expression> const& _externalCall,
|
||||
std::vector<ASTPointer<TryCatchClause>> const& _clauses
|
||||
):
|
||||
Statement(_location, _docString),
|
||||
Statement(_id, _location, _docString),
|
||||
m_externalCall(_externalCall),
|
||||
m_clauses(_clauses)
|
||||
{}
|
||||
@ -1307,22 +1332,24 @@ class BreakableStatement: public Statement
|
||||
{
|
||||
public:
|
||||
explicit BreakableStatement(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString
|
||||
): Statement(_location, _docString) {}
|
||||
): Statement(_id, _location, _docString) {}
|
||||
};
|
||||
|
||||
class WhileStatement: public BreakableStatement
|
||||
{
|
||||
public:
|
||||
WhileStatement(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString,
|
||||
ASTPointer<Expression> const& _condition,
|
||||
ASTPointer<Statement> const& _body,
|
||||
bool _isDoWhile
|
||||
):
|
||||
BreakableStatement(_location, _docString), m_condition(_condition), m_body(_body),
|
||||
BreakableStatement(_id, _location, _docString), m_condition(_condition), m_body(_body),
|
||||
m_isDoWhile(_isDoWhile) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
@ -1344,6 +1371,7 @@ class ForStatement: public BreakableStatement, public Scopable
|
||||
{
|
||||
public:
|
||||
ForStatement(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString,
|
||||
ASTPointer<Statement> const& _initExpression,
|
||||
@ -1351,7 +1379,7 @@ public:
|
||||
ASTPointer<ExpressionStatement> const& _loopExpression,
|
||||
ASTPointer<Statement> const& _body
|
||||
):
|
||||
BreakableStatement(_location, _docString),
|
||||
BreakableStatement(_id, _location, _docString),
|
||||
m_initExpression(_initExpression),
|
||||
m_condExpression(_conditionExpression),
|
||||
m_loopExpression(_loopExpression),
|
||||
@ -1381,8 +1409,8 @@ private:
|
||||
class Continue: public Statement
|
||||
{
|
||||
public:
|
||||
explicit Continue(SourceLocation const& _location, ASTPointer<ASTString> const& _docString):
|
||||
Statement(_location, _docString) {}
|
||||
explicit Continue(int64_t _id, SourceLocation const& _location, ASTPointer<ASTString> const& _docString):
|
||||
Statement(_id, _location, _docString) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
};
|
||||
@ -1390,8 +1418,8 @@ public:
|
||||
class Break: public Statement
|
||||
{
|
||||
public:
|
||||
explicit Break(SourceLocation const& _location, ASTPointer<ASTString> const& _docString):
|
||||
Statement(_location, _docString) {}
|
||||
explicit Break(int64_t _id, SourceLocation const& _location, ASTPointer<ASTString> const& _docString):
|
||||
Statement(_id, _location, _docString) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
};
|
||||
@ -1400,10 +1428,11 @@ class Return: public Statement
|
||||
{
|
||||
public:
|
||||
Return(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString,
|
||||
ASTPointer<Expression> _expression
|
||||
): Statement(_location, _docString), m_expression(_expression) {}
|
||||
): Statement(_id, _location, _docString), m_expression(_expression) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1421,8 +1450,8 @@ private:
|
||||
class Throw: public Statement
|
||||
{
|
||||
public:
|
||||
explicit Throw(SourceLocation const& _location, ASTPointer<ASTString> const& _docString):
|
||||
Statement(_location, _docString) {}
|
||||
explicit Throw(int64_t _id, SourceLocation const& _location, ASTPointer<ASTString> const& _docString):
|
||||
Statement(_id, _location, _docString) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
};
|
||||
@ -1434,11 +1463,12 @@ class EmitStatement: public Statement
|
||||
{
|
||||
public:
|
||||
explicit EmitStatement(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString,
|
||||
ASTPointer<FunctionCall> const& _functionCall
|
||||
):
|
||||
Statement(_location, _docString), m_eventCall(_functionCall) {}
|
||||
Statement(_id, _location, _docString), m_eventCall(_functionCall) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1460,12 +1490,13 @@ class VariableDeclarationStatement: public Statement
|
||||
{
|
||||
public:
|
||||
VariableDeclarationStatement(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString,
|
||||
std::vector<ASTPointer<VariableDeclaration>> const& _variables,
|
||||
ASTPointer<Expression> const& _initialValue
|
||||
):
|
||||
Statement(_location, _docString), m_variables(_variables), m_initialValue(_initialValue) {}
|
||||
Statement(_id, _location, _docString), m_variables(_variables), m_initialValue(_initialValue) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1489,11 +1520,12 @@ class ExpressionStatement: public Statement
|
||||
{
|
||||
public:
|
||||
ExpressionStatement(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _docString,
|
||||
ASTPointer<Expression> _expression
|
||||
):
|
||||
Statement(_location, _docString), m_expression(_expression) {}
|
||||
Statement(_id, _location, _docString), m_expression(_expression) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1516,7 +1548,7 @@ private:
|
||||
class Expression: public ASTNode
|
||||
{
|
||||
public:
|
||||
explicit Expression(SourceLocation const& _location): ASTNode(_location) {}
|
||||
explicit Expression(int64_t _id, SourceLocation const& _location): ASTNode(_id, _location) {}
|
||||
|
||||
ExpressionAnnotation& annotation() const override;
|
||||
};
|
||||
@ -1525,12 +1557,13 @@ class Conditional: public Expression
|
||||
{
|
||||
public:
|
||||
Conditional(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<Expression> const& _condition,
|
||||
ASTPointer<Expression> const& _trueExpression,
|
||||
ASTPointer<Expression> const& _falseExpression
|
||||
):
|
||||
Expression(_location),
|
||||
Expression(_id, _location),
|
||||
m_condition(_condition),
|
||||
m_trueExpression(_trueExpression),
|
||||
m_falseExpression(_falseExpression)
|
||||
@ -1554,12 +1587,13 @@ class Assignment: public Expression
|
||||
{
|
||||
public:
|
||||
Assignment(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<Expression> const& _leftHandSide,
|
||||
Token _assignmentOperator,
|
||||
ASTPointer<Expression> const& _rightHandSide
|
||||
):
|
||||
Expression(_location),
|
||||
Expression(_id, _location),
|
||||
m_leftHandSide(_leftHandSide),
|
||||
m_assigmentOperator(_assignmentOperator),
|
||||
m_rightHandSide(_rightHandSide)
|
||||
@ -1591,11 +1625,12 @@ class TupleExpression: public Expression
|
||||
{
|
||||
public:
|
||||
TupleExpression(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
std::vector<ASTPointer<Expression>> const& _components,
|
||||
bool _isArray
|
||||
):
|
||||
Expression(_location),
|
||||
Expression(_id, _location),
|
||||
m_components(_components),
|
||||
m_isArray(_isArray) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
@ -1617,12 +1652,13 @@ class UnaryOperation: public Expression
|
||||
{
|
||||
public:
|
||||
UnaryOperation(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
Token _operator,
|
||||
ASTPointer<Expression> const& _subExpression,
|
||||
bool _isPrefix
|
||||
):
|
||||
Expression(_location),
|
||||
Expression(_id, _location),
|
||||
m_operator(_operator),
|
||||
m_subExpression(_subExpression),
|
||||
m_isPrefix(_isPrefix)
|
||||
@ -1650,12 +1686,13 @@ class BinaryOperation: public Expression
|
||||
{
|
||||
public:
|
||||
BinaryOperation(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<Expression> const& _left,
|
||||
Token _operator,
|
||||
ASTPointer<Expression> const& _right
|
||||
):
|
||||
Expression(_location), m_left(_left), m_operator(_operator), m_right(_right)
|
||||
Expression(_id, _location), m_left(_left), m_operator(_operator), m_right(_right)
|
||||
{
|
||||
solAssert(TokenTraits::isBinaryOp(_operator) || TokenTraits::isCompareOp(_operator), "");
|
||||
}
|
||||
@ -1681,12 +1718,13 @@ class FunctionCall: public Expression
|
||||
{
|
||||
public:
|
||||
FunctionCall(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<Expression> const& _expression,
|
||||
std::vector<ASTPointer<Expression>> const& _arguments,
|
||||
std::vector<ASTPointer<ASTString>> const& _names
|
||||
):
|
||||
Expression(_location), m_expression(_expression), m_arguments(_arguments), m_names(_names) {}
|
||||
Expression(_id, _location), m_expression(_expression), m_arguments(_arguments), m_names(_names) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1710,10 +1748,11 @@ class NewExpression: public Expression
|
||||
{
|
||||
public:
|
||||
NewExpression(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<TypeName> const& _typeName
|
||||
):
|
||||
Expression(_location), m_typeName(_typeName) {}
|
||||
Expression(_id, _location), m_typeName(_typeName) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1730,11 +1769,12 @@ class MemberAccess: public Expression
|
||||
{
|
||||
public:
|
||||
MemberAccess(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<Expression> _expression,
|
||||
ASTPointer<ASTString> const& _memberName
|
||||
):
|
||||
Expression(_location), m_expression(_expression), m_memberName(_memberName) {}
|
||||
Expression(_id, _location), m_expression(_expression), m_memberName(_memberName) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
Expression const& expression() const { return *m_expression; }
|
||||
@ -1754,11 +1794,12 @@ class IndexAccess: public Expression
|
||||
{
|
||||
public:
|
||||
IndexAccess(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<Expression> const& _base,
|
||||
ASTPointer<Expression> const& _index
|
||||
):
|
||||
Expression(_location), m_base(_base), m_index(_index) {}
|
||||
Expression(_id, _location), m_base(_base), m_index(_index) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1777,12 +1818,13 @@ class IndexRangeAccess: public Expression
|
||||
{
|
||||
public:
|
||||
IndexRangeAccess(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<Expression> const& _base,
|
||||
ASTPointer<Expression> const& _start,
|
||||
ASTPointer<Expression> const& _end
|
||||
):
|
||||
Expression(_location), m_base(_base), m_start(_start), m_end(_end) {}
|
||||
Expression(_id, _location), m_base(_base), m_start(_start), m_end(_end) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1803,7 +1845,7 @@ private:
|
||||
class PrimaryExpression: public Expression
|
||||
{
|
||||
public:
|
||||
PrimaryExpression(SourceLocation const& _location): Expression(_location) {}
|
||||
PrimaryExpression(int64_t _id, SourceLocation const& _location): Expression(_id, _location) {}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1813,10 +1855,11 @@ class Identifier: public PrimaryExpression
|
||||
{
|
||||
public:
|
||||
Identifier(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name
|
||||
):
|
||||
PrimaryExpression(_location), m_name(_name) {}
|
||||
PrimaryExpression(_id, _location), m_name(_name) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -1837,10 +1880,11 @@ class ElementaryTypeNameExpression: public PrimaryExpression
|
||||
{
|
||||
public:
|
||||
ElementaryTypeNameExpression(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ElementaryTypeName> const& _type
|
||||
):
|
||||
PrimaryExpression(_location),
|
||||
PrimaryExpression(_id, _location),
|
||||
m_type(_type)
|
||||
{
|
||||
}
|
||||
@ -1874,12 +1918,13 @@ public:
|
||||
Year = static_cast<int>(Token::SubYear)
|
||||
};
|
||||
Literal(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
Token _token,
|
||||
ASTPointer<ASTString> const& _value,
|
||||
SubDenomination _sub = SubDenomination::None
|
||||
):
|
||||
PrimaryExpression(_location), m_token(_token), m_value(_value), m_subDenomination(_sub) {}
|
||||
PrimaryExpression(_id, _location), m_token(_token), m_value(_value), m_subDenomination(_sub) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include <libyul/AsmJsonConverter.h>
|
||||
#include <libyul/AsmData.h>
|
||||
#include <libyul/AsmPrinter.h>
|
||||
#include <libyul/backends/evm/EVMDialect.h>
|
||||
|
||||
#include <libsolutil/JSON.h>
|
||||
#include <libsolutil/UTF8.h>
|
||||
|
||||
@ -492,13 +494,16 @@ bool ASTJsonConverter::visit(ArrayTypeName const& _node)
|
||||
bool ASTJsonConverter::visit(InlineAssembly const& _node)
|
||||
{
|
||||
vector<pair<string, Json::Value>> externalReferences;
|
||||
|
||||
for (auto const& it: _node.annotation().externalReferences)
|
||||
if (it.first)
|
||||
externalReferences.emplace_back(make_pair(
|
||||
it.first->name.str(),
|
||||
inlineAssemblyIdentifierToJson(it)
|
||||
));
|
||||
|
||||
Json::Value externalReferencesJson = Json::arrayValue;
|
||||
|
||||
for (auto&& it: boost::range::sort(externalReferences))
|
||||
externalReferencesJson.append(std::move(it.second));
|
||||
|
||||
@ -506,8 +511,10 @@ bool ASTJsonConverter::visit(InlineAssembly const& _node)
|
||||
m_legacy ?
|
||||
make_pair("operations", Json::Value(yul::AsmPrinter()(_node.operations()))) :
|
||||
make_pair("AST", Json::Value(yul::AsmJsonConverter(sourceIndexFromLocation(_node.location()))(_node.operations()))),
|
||||
make_pair("externalReferences", std::move(externalReferencesJson))
|
||||
make_pair("externalReferences", std::move(externalReferencesJson)),
|
||||
make_pair("evmVersion", dynamic_cast<solidity::yul::EVMDialect const&>(_node.dialect()).evmVersion().name())
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
982
libsolidity/ast/ASTJsonImporter.cpp
Normal file
982
libsolidity/ast/ASTJsonImporter.cpp
Normal file
@ -0,0 +1,982 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @author julius <djudju@protonmail.com>
|
||||
* @date 2019
|
||||
*Component that imports an AST from json format to the internal format
|
||||
*/
|
||||
|
||||
#include <libsolidity/ast/ASTJsonImporter.h>
|
||||
#include <libsolidity/ast/AsmJsonImporter.h>
|
||||
#include <liblangutil/Scanner.h>
|
||||
#include <libyul/Dialect.h>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <liblangutil/Token.h>
|
||||
#include <libyul/AsmParser.h>
|
||||
#include <libyul/backends/evm/EVMDialect.h>
|
||||
#include <liblangutil/SourceLocation.h>
|
||||
#include <liblangutil/Exceptions.h>
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
using SourceLocation = langutil::SourceLocation;
|
||||
|
||||
template<class T>
|
||||
ASTPointer<T> ASTJsonImporter::nullOrCast(Json::Value const& _json)
|
||||
{
|
||||
if (_json.isNull())
|
||||
return nullptr;
|
||||
else
|
||||
return dynamic_pointer_cast<T>(convertJsonToASTNode(_json));
|
||||
}
|
||||
|
||||
|
||||
// ============ public ===========================
|
||||
|
||||
map<string, ASTPointer<SourceUnit>> ASTJsonImporter::jsonToSourceUnit(map<string, Json::Value> const& _sourceList)
|
||||
{
|
||||
m_sourceList = _sourceList;
|
||||
for (auto const& src: _sourceList)
|
||||
m_sourceLocations.emplace_back(make_shared<string const>(src.first));
|
||||
for (auto const& srcPair: m_sourceList)
|
||||
{
|
||||
astAssert(!srcPair.second.isNull(), "");
|
||||
astAssert(member(srcPair.second,"nodeType") == "SourceUnit", "The 'nodeType' of the highest node must be 'SourceUnit'.");
|
||||
m_currentSourceName = srcPair.first;
|
||||
m_sourceUnits[srcPair.first] = createSourceUnit(srcPair.second, srcPair.first);
|
||||
}
|
||||
return m_sourceUnits;
|
||||
}
|
||||
|
||||
// ============ private ===========================
|
||||
|
||||
// =========== general creation functions ==============
|
||||
template <typename T, typename... Args>
|
||||
ASTPointer<T> ASTJsonImporter::createASTNode(Json::Value const& _node, Args&&... _args)
|
||||
{
|
||||
astAssert(member(_node, "id").isInt64(), "'id'-field must be 64bit integer.");
|
||||
|
||||
int64_t id = _node["id"].asInt64();
|
||||
|
||||
astAssert(m_usedIDs.insert(id).second, "Found duplicate node ID!");
|
||||
|
||||
auto n = make_shared<T>(
|
||||
id,
|
||||
createSourceLocation(_node),
|
||||
forward<Args>(_args)...
|
||||
);
|
||||
return n;
|
||||
}
|
||||
|
||||
SourceLocation const ASTJsonImporter::createSourceLocation(Json::Value const& _node)
|
||||
{
|
||||
astAssert(member(_node, "src").isString(), "'src' must be a string");
|
||||
|
||||
return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, int(m_sourceLocations.size()));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
ASTPointer<T> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _node)
|
||||
{
|
||||
ASTPointer<T> ret = dynamic_pointer_cast<T>(convertJsonToASTNode(_node));
|
||||
astAssert(ret, "cast of converted json-node must not be nullptr");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ASTPointer<ASTNode> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _json)
|
||||
{
|
||||
astAssert(_json["nodeType"].isString() && _json.isMember("id"), "JSON-Node needs to have 'nodeType' and 'id' fields.");
|
||||
string nodeType = _json["nodeType"].asString();
|
||||
if (nodeType == "PragmaDirective")
|
||||
return createPragmaDirective(_json);
|
||||
if (nodeType == "ImportDirective")
|
||||
return createImportDirective(_json);
|
||||
if (nodeType == "ContractDefinition")
|
||||
return createContractDefinition(_json);
|
||||
if (nodeType == "InheritanceSpecifier")
|
||||
return createInheritanceSpecifier(_json);
|
||||
if (nodeType == "UsingForDirective")
|
||||
return createUsingForDirective(_json);
|
||||
if (nodeType == "StructDefinition")
|
||||
return createStructDefinition(_json);
|
||||
if (nodeType == "EnumDefinition")
|
||||
return createEnumDefinition(_json);
|
||||
if (nodeType == "EnumValue")
|
||||
return createEnumValue(_json);
|
||||
if (nodeType == "ParameterList")
|
||||
return createParameterList(_json);
|
||||
if (nodeType == "OverrideSpecifier")
|
||||
return createOverrideSpecifier(_json);
|
||||
if (nodeType == "FunctionDefinition")
|
||||
return createFunctionDefinition(_json);
|
||||
if (nodeType == "VariableDeclaration")
|
||||
return createVariableDeclaration(_json);
|
||||
if (nodeType == "ModifierDefinition")
|
||||
return createModifierDefinition(_json);
|
||||
if (nodeType == "ModifierInvocation")
|
||||
return createModifierInvocation(_json);
|
||||
if (nodeType == "EventDefinition")
|
||||
return createEventDefinition(_json);
|
||||
if (nodeType == "ElementaryTypeName")
|
||||
return createElementaryTypeName(_json);
|
||||
if (nodeType == "UserDefinedTypeName")
|
||||
return createUserDefinedTypeName(_json);
|
||||
if (nodeType == "FunctionTypeName")
|
||||
return createFunctionTypeName(_json);
|
||||
if (nodeType == "Mapping")
|
||||
return createMapping(_json);
|
||||
if (nodeType == "ArrayTypeName")
|
||||
return createArrayTypeName(_json);
|
||||
if (nodeType == "InlineAssembly")
|
||||
return createInlineAssembly(_json);
|
||||
if (nodeType == "Block")
|
||||
return createBlock(_json);
|
||||
if (nodeType == "PlaceholderStatement")
|
||||
return createPlaceholderStatement(_json);
|
||||
if (nodeType == "IfStatement")
|
||||
return createIfStatement(_json);
|
||||
if (nodeType == "TryCatchClause")
|
||||
return createTryCatchClause(_json);
|
||||
if (nodeType == "TryStatement")
|
||||
return createTryStatement(_json);
|
||||
if (nodeType == "WhileStatement")
|
||||
return createWhileStatement(_json, false);
|
||||
if (nodeType == "DoWhileStatement")
|
||||
return createWhileStatement(_json, true);
|
||||
if (nodeType == "ForStatement")
|
||||
return createForStatement(_json);
|
||||
if (nodeType == "Continue")
|
||||
return createContinue(_json);
|
||||
if (nodeType == "Break")
|
||||
return createBreak(_json);
|
||||
if (nodeType == "Return")
|
||||
return createReturn(_json);
|
||||
if (nodeType == "EmitStatement")
|
||||
return createEmitStatement(_json);
|
||||
if (nodeType == "Throw")
|
||||
return createThrow(_json);
|
||||
if (nodeType == "VariableDeclarationStatement")
|
||||
return createVariableDeclarationStatement(_json);
|
||||
if (nodeType == "ExpressionStatement")
|
||||
return createExpressionStatement(_json);
|
||||
if (nodeType == "Conditional")
|
||||
return createConditional(_json);
|
||||
if (nodeType == "Assignment")
|
||||
return createAssignment(_json);
|
||||
if (nodeType == "TupleExpression")
|
||||
return createTupleExpression(_json);
|
||||
if (nodeType == "UnaryOperation")
|
||||
return createUnaryOperation(_json);
|
||||
if (nodeType == "BinaryOperation")
|
||||
return createBinaryOperation(_json);
|
||||
if (nodeType == "FunctionCall")
|
||||
return createFunctionCall(_json);
|
||||
if (nodeType == "NewExpression")
|
||||
return createNewExpression(_json);
|
||||
if (nodeType == "MemberAccess")
|
||||
return createMemberAccess(_json);
|
||||
if (nodeType == "IndexAccess")
|
||||
return createIndexAccess(_json);
|
||||
if (nodeType == "IndexRangeAccess")
|
||||
return createIndexRangeAccess(_json);
|
||||
if (nodeType == "Identifier")
|
||||
return createIdentifier(_json);
|
||||
if (nodeType == "ElementaryTypeNameExpression")
|
||||
return createElementaryTypeNameExpression(_json);
|
||||
if (nodeType == "Literal")
|
||||
return createLiteral(_json);
|
||||
else
|
||||
astAssert(false, "Unknown type of ASTNode: " + nodeType);
|
||||
}
|
||||
|
||||
// ============ functions to instantiate the AST-Nodes from Json-Nodes ==============
|
||||
|
||||
ASTPointer<SourceUnit> ASTJsonImporter::createSourceUnit(Json::Value const& _node, string const& _srcName)
|
||||
{
|
||||
vector<ASTPointer<ASTNode>> nodes;
|
||||
for (auto& child: member(_node, "nodes"))
|
||||
nodes.emplace_back(convertJsonToASTNode(child));
|
||||
ASTPointer<SourceUnit> tmp = createASTNode<SourceUnit>(_node, nodes);
|
||||
tmp->annotation().path = _srcName;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
ASTPointer<PragmaDirective> ASTJsonImporter::createPragmaDirective(Json::Value const& _node)
|
||||
{
|
||||
vector<Token> tokens;
|
||||
vector<ASTString> literals;
|
||||
for (auto const& lit: member(_node, "literals"))
|
||||
{
|
||||
string l = lit.asString();
|
||||
literals.push_back(l);
|
||||
tokens.push_back(scanSingleToken(l));
|
||||
}
|
||||
return createASTNode<PragmaDirective>(_node, tokens, literals);
|
||||
}
|
||||
|
||||
ASTPointer<ImportDirective> ASTJsonImporter::createImportDirective(Json::Value const& _node)
|
||||
{
|
||||
ASTPointer<ASTString> unitAlias = memberAsASTString(_node, "unitAlias");
|
||||
ASTPointer<ASTString> path = memberAsASTString(_node, "file");
|
||||
ImportDirective::SymbolAliasList symbolAliases;
|
||||
|
||||
for (auto& tuple: member(_node, "symbolAliases"))
|
||||
{
|
||||
astAssert(tuple["local"].isNull() || tuple["local"].isString(), "expected 'local' to be a string or null!");
|
||||
|
||||
symbolAliases.push_back({
|
||||
createIdentifier(tuple["foreign"]),
|
||||
tuple["local"].isNull() ? nullptr : make_shared<ASTString>(tuple["local"].asString()),
|
||||
createSourceLocation(tuple["foreign"])}
|
||||
);
|
||||
}
|
||||
ASTPointer<ImportDirective> tmp = createASTNode<ImportDirective>(
|
||||
_node,
|
||||
path,
|
||||
unitAlias,
|
||||
move(symbolAliases)
|
||||
);
|
||||
|
||||
astAssert(_node["absolutePath"].isString(), "Expected 'absolutePath' to be a string!");
|
||||
|
||||
tmp->annotation().absolutePath = _node["absolutePath"].asString();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
ASTPointer<ContractDefinition> ASTJsonImporter::createContractDefinition(Json::Value const& _node)
|
||||
{
|
||||
astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
|
||||
|
||||
std::vector<ASTPointer<InheritanceSpecifier>> baseContracts;
|
||||
|
||||
for (auto& base: _node["baseContracts"])
|
||||
baseContracts.push_back(createInheritanceSpecifier(base));
|
||||
|
||||
std::vector<ASTPointer<ASTNode>> subNodes;
|
||||
|
||||
for (auto& subnode: _node["nodes"])
|
||||
subNodes.push_back(convertJsonToASTNode(subnode));
|
||||
|
||||
return createASTNode<ContractDefinition>(
|
||||
_node,
|
||||
make_shared<ASTString>(_node["name"].asString()),
|
||||
nullOrASTString(_node, "documentation"),
|
||||
baseContracts,
|
||||
subNodes,
|
||||
contractKind(_node),
|
||||
memberAsBool(_node, "abstract")
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<InheritanceSpecifier> ASTJsonImporter::createInheritanceSpecifier(Json::Value const& _node)
|
||||
{
|
||||
std::vector<ASTPointer<Expression>> arguments;
|
||||
for (auto& arg: member(_node, "arguments"))
|
||||
arguments.push_back(convertJsonToASTNode<Expression>(arg));
|
||||
return createASTNode<InheritanceSpecifier>(
|
||||
_node,
|
||||
createUserDefinedTypeName(member(_node, "baseName")),
|
||||
member(_node, "arguments").isNull() ? nullptr : make_unique<std::vector<ASTPointer<Expression>>>(arguments)
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<UsingForDirective> ASTJsonImporter::createUsingForDirective(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<UsingForDirective>(
|
||||
_node,
|
||||
createUserDefinedTypeName(member(_node, "libraryName")),
|
||||
_node["typeName"].isNull() ? nullptr : convertJsonToASTNode<TypeName>(_node["typeName"])
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<ASTNode> ASTJsonImporter::createStructDefinition(Json::Value const& _node)
|
||||
{
|
||||
std::vector<ASTPointer<VariableDeclaration>> members;
|
||||
for (auto& member: _node["members"])
|
||||
members.push_back(createVariableDeclaration(member));
|
||||
return createASTNode<StructDefinition>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name"),
|
||||
members
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<EnumDefinition> ASTJsonImporter::createEnumDefinition(Json::Value const& _node)
|
||||
{
|
||||
std::vector<ASTPointer<EnumValue>> members;
|
||||
for (auto& member: _node["members"])
|
||||
members.push_back(createEnumValue(member));
|
||||
return createASTNode<EnumDefinition>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name"),
|
||||
members
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<EnumValue> ASTJsonImporter::createEnumValue(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<EnumValue>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name")
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<ParameterList> ASTJsonImporter::createParameterList(Json::Value const& _node)
|
||||
{
|
||||
std::vector<ASTPointer<VariableDeclaration>> parameters;
|
||||
for (auto& param: _node["parameters"])
|
||||
parameters.push_back(createVariableDeclaration(param));
|
||||
return createASTNode<ParameterList>(
|
||||
_node,
|
||||
parameters
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<OverrideSpecifier> ASTJsonImporter::createOverrideSpecifier(Json::Value const& _node)
|
||||
{
|
||||
std::vector<ASTPointer<UserDefinedTypeName>> overrides;
|
||||
|
||||
for (auto& param: _node["overrides"])
|
||||
overrides.push_back(createUserDefinedTypeName(param));
|
||||
|
||||
return createASTNode<OverrideSpecifier>(
|
||||
_node,
|
||||
overrides
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<FunctionDefinition> ASTJsonImporter::createFunctionDefinition(Json::Value const& _node)
|
||||
{
|
||||
astAssert(_node["kind"].isString(), "Expected 'kind' to be a string!");
|
||||
|
||||
Token kind;
|
||||
string kindStr = member(_node, "kind").asString();
|
||||
|
||||
if (kindStr == "constructor")
|
||||
kind = Token::Constructor;
|
||||
else if (kindStr == "function")
|
||||
kind = Token::Function;
|
||||
else if (kindStr == "fallback")
|
||||
kind = Token::Fallback;
|
||||
else if (kindStr == "receive")
|
||||
kind = Token::Receive;
|
||||
else
|
||||
astAssert(false, "Expected 'kind' to be one of [constructor, function, fallback, receive]");
|
||||
|
||||
std::vector<ASTPointer<ModifierInvocation>> modifiers;
|
||||
for (auto& mod: member(_node, "modifiers"))
|
||||
modifiers.push_back(createModifierInvocation(mod));
|
||||
return createASTNode<FunctionDefinition>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name"),
|
||||
visibility(_node),
|
||||
stateMutability(_node),
|
||||
kind,
|
||||
memberAsBool(_node, "virtual"),
|
||||
_node["overrides"].isNull() ? nullptr : createOverrideSpecifier(member(_node, "overrides")),
|
||||
nullOrASTString(_node, "documentation"),
|
||||
createParameterList(member(_node, "parameters")),
|
||||
modifiers,
|
||||
createParameterList(member(_node, "returnParameters")),
|
||||
memberAsBool(_node, "implemented") ? createBlock(member(_node, "body")) : nullptr
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<VariableDeclaration> ASTJsonImporter::createVariableDeclaration(Json::Value const& _node)
|
||||
{
|
||||
astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
|
||||
|
||||
return createASTNode<VariableDeclaration>(
|
||||
_node,
|
||||
nullOrCast<TypeName>(member(_node, "typeName")),
|
||||
make_shared<ASTString>(member(_node, "name").asString()),
|
||||
nullOrCast<Expression>(member(_node, "value")),
|
||||
visibility(_node),
|
||||
memberAsBool(_node, "stateVariable"),
|
||||
_node.isMember("indexed") ? memberAsBool(_node, "indexed") : false,
|
||||
memberAsBool(_node, "constant"),
|
||||
_node["overrides"].isNull() ? nullptr : createOverrideSpecifier(member(_node, "overrides")),
|
||||
location(_node)
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<ModifierDefinition> ASTJsonImporter::createModifierDefinition(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<ModifierDefinition>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name"),
|
||||
nullOrASTString(_node,"documentation"),
|
||||
createParameterList(member(_node, "parameters")),
|
||||
memberAsBool(_node, "virtual"),
|
||||
_node["overrides"].isNull() ? nullptr : createOverrideSpecifier(member(_node, "overrides")),
|
||||
createBlock(member(_node, "body"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<ModifierInvocation> ASTJsonImporter::createModifierInvocation(Json::Value const& _node)
|
||||
{
|
||||
std::vector<ASTPointer<Expression>> arguments;
|
||||
for (auto& arg: member(_node, "arguments"))
|
||||
arguments.push_back(convertJsonToASTNode<Expression>(arg));
|
||||
return createASTNode<ModifierInvocation>(
|
||||
_node,
|
||||
createIdentifier(member(_node, "modifierName")),
|
||||
member(_node, "arguments").isNull() ? nullptr : make_unique<std::vector<ASTPointer<Expression>>>(arguments)
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<EventDefinition> ASTJsonImporter::createEventDefinition(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<EventDefinition>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name"),
|
||||
nullOrASTString(_node, "documentation"),
|
||||
createParameterList(member(_node, "parameters")),
|
||||
memberAsBool(_node, "anonymous")
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<ElementaryTypeName> ASTJsonImporter::createElementaryTypeName(Json::Value const& _node)
|
||||
{
|
||||
unsigned short firstNum;
|
||||
unsigned short secondNum;
|
||||
|
||||
astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
|
||||
|
||||
string name = member(_node, "name").asString();
|
||||
Token token;
|
||||
tie(token, firstNum, secondNum) = TokenTraits::fromIdentifierOrKeyword(name);
|
||||
ElementaryTypeNameToken elem(token, firstNum, secondNum);
|
||||
|
||||
std::optional<StateMutability> mutability = {};
|
||||
if (_node.isMember("stateMutability"))
|
||||
mutability = stateMutability(_node);
|
||||
|
||||
return createASTNode<ElementaryTypeName>(_node, elem, mutability);
|
||||
}
|
||||
|
||||
ASTPointer<UserDefinedTypeName> ASTJsonImporter::createUserDefinedTypeName(Json::Value const& _node)
|
||||
{
|
||||
astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
|
||||
|
||||
vector<ASTString> namePath;
|
||||
vector<string> strs;
|
||||
string nameString = member(_node, "name").asString();
|
||||
boost::algorithm::split(strs, nameString, boost::is_any_of("."));
|
||||
for (string s: strs)
|
||||
namePath.push_back(ASTString(s));
|
||||
return createASTNode<UserDefinedTypeName>(
|
||||
_node,
|
||||
namePath
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<FunctionTypeName> ASTJsonImporter::createFunctionTypeName(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<FunctionTypeName>(
|
||||
_node,
|
||||
createParameterList(member(_node, "parameterTypes")),
|
||||
createParameterList(member(_node, "returnParameterTypes")),
|
||||
visibility(_node),
|
||||
stateMutability(_node)
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<Mapping> ASTJsonImporter::createMapping(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<Mapping>(
|
||||
_node,
|
||||
createElementaryTypeName(member(_node, "keyType")),
|
||||
convertJsonToASTNode<TypeName>(member(_node, "valueType"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<ArrayTypeName> ASTJsonImporter::createArrayTypeName(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<ArrayTypeName>(
|
||||
_node,
|
||||
convertJsonToASTNode<TypeName>(member(_node, "baseType")),
|
||||
nullOrCast<Expression>(member(_node, "length"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<InlineAssembly> ASTJsonImporter::createInlineAssembly(Json::Value const& _node)
|
||||
{
|
||||
astAssert(_node["evmVersion"].isString(), "Expected evmVersion to be a string!");
|
||||
auto evmVersion = langutil::EVMVersion::fromString(_node["evmVersion"].asString());
|
||||
astAssert(evmVersion.has_value(), "Invalid EVM version!");
|
||||
astAssert(m_evmVersion == evmVersion, "Imported tree evm version differs from configured evm version!");
|
||||
|
||||
yul::Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(evmVersion.value());
|
||||
shared_ptr<yul::Block> operations = make_shared<yul::Block>(AsmJsonImporter(m_currentSourceName).createBlock(member(_node, "AST")));
|
||||
return createASTNode<InlineAssembly>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation"),
|
||||
dialect,
|
||||
operations
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<Block> ASTJsonImporter::createBlock(Json::Value const& _node)
|
||||
{
|
||||
std::vector<ASTPointer<Statement>> statements;
|
||||
for (auto& stat: member(_node, "statements"))
|
||||
statements.push_back(convertJsonToASTNode<Statement>(stat));
|
||||
return createASTNode<Block>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation"),
|
||||
statements
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<PlaceholderStatement> ASTJsonImporter::createPlaceholderStatement(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<PlaceholderStatement>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation")
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<IfStatement> ASTJsonImporter::createIfStatement(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<IfStatement>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation"),
|
||||
convertJsonToASTNode<Expression>(member(_node, "condition")),
|
||||
convertJsonToASTNode<Statement>(member(_node, "trueBody")),
|
||||
nullOrCast<Statement>(member(_node, "falseBody"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<TryCatchClause> ASTJsonImporter::createTryCatchClause(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<TryCatchClause>(
|
||||
_node,
|
||||
memberAsASTString(_node, "errorName"),
|
||||
nullOrCast<ParameterList>(member(_node, "parameters")),
|
||||
convertJsonToASTNode<Block>(member(_node, "block"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<TryStatement> ASTJsonImporter::createTryStatement(Json::Value const& _node)
|
||||
{
|
||||
vector<ASTPointer<TryCatchClause>> clauses;
|
||||
|
||||
for (auto& param: _node["clauses"])
|
||||
clauses.emplace_back(createTryCatchClause(param));
|
||||
|
||||
return createASTNode<TryStatement>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation"),
|
||||
convertJsonToASTNode<Expression>(member(_node, "externalCall")),
|
||||
clauses
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<WhileStatement> ASTJsonImporter::createWhileStatement(Json::Value const& _node, bool _isDoWhile=false)
|
||||
{
|
||||
return createASTNode<WhileStatement>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation"),
|
||||
convertJsonToASTNode<Expression>(member(_node, "condition")),
|
||||
convertJsonToASTNode<Statement>(member(_node, "body")),
|
||||
_isDoWhile
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<ForStatement> ASTJsonImporter::createForStatement(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<ForStatement>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation"),
|
||||
nullOrCast<Statement>(member(_node, "initializationExpression")),
|
||||
nullOrCast<Expression>(member(_node, "condition")),
|
||||
nullOrCast<ExpressionStatement>(member(_node, "loopExpression")),
|
||||
convertJsonToASTNode<Statement>(member(_node, "body"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<Continue> ASTJsonImporter::createContinue(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<Continue>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation")
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<Break> ASTJsonImporter::createBreak(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<Break>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation")
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<Return> ASTJsonImporter::createReturn(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<Return>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation"),
|
||||
nullOrCast<Expression>(member(_node, "expression"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<Throw> ASTJsonImporter::createThrow(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<Throw>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation")
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<EmitStatement> ASTJsonImporter::createEmitStatement(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<EmitStatement>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation"),
|
||||
createFunctionCall(member(_node, "eventCall"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<VariableDeclarationStatement> ASTJsonImporter::createVariableDeclarationStatement(Json::Value const& _node)
|
||||
{
|
||||
std::vector<ASTPointer<VariableDeclaration>> variables;
|
||||
for (auto& var: member(_node, "declarations"))
|
||||
variables.push_back(var.isNull() ? nullptr : createVariableDeclaration(var)); //unnamed components are empty pointers
|
||||
return createASTNode<VariableDeclarationStatement>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation"),
|
||||
variables,
|
||||
nullOrCast<Expression>(member(_node, "initialValue"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<ExpressionStatement> ASTJsonImporter::createExpressionStatement(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<ExpressionStatement>(
|
||||
_node,
|
||||
nullOrASTString(_node, "documentation"),
|
||||
convertJsonToASTNode<Expression>(member(_node, "expression"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<Conditional> ASTJsonImporter::createConditional(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<Conditional>(
|
||||
_node,
|
||||
convertJsonToASTNode<Expression>(member(_node, "condition")),
|
||||
convertJsonToASTNode<Expression>(member(_node, "trueExpression")),
|
||||
convertJsonToASTNode<Expression>(member(_node, "falseExpression"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<Assignment> ASTJsonImporter::createAssignment(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<Assignment>(
|
||||
_node,
|
||||
convertJsonToASTNode<Expression>(member(_node, "leftHandSide")),
|
||||
scanSingleToken(member(_node, "operator")),
|
||||
convertJsonToASTNode<Expression>(member(_node, "rightHandSide"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<TupleExpression> ASTJsonImporter::createTupleExpression(Json::Value const& _node)
|
||||
{
|
||||
std::vector<ASTPointer<Expression>> components;
|
||||
for (auto& comp: member(_node, "components"))
|
||||
components.push_back(nullOrCast<Expression>(comp));
|
||||
return createASTNode<TupleExpression>(
|
||||
_node,
|
||||
components,
|
||||
memberAsBool(_node, "isInlineArray")
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<UnaryOperation> ASTJsonImporter::createUnaryOperation(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<UnaryOperation>(
|
||||
_node,
|
||||
scanSingleToken(member(_node, "operator")),
|
||||
convertJsonToASTNode<Expression>(member(_node, "subExpression")),
|
||||
memberAsBool(_node, "prefix")
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<BinaryOperation> ASTJsonImporter::createBinaryOperation(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<BinaryOperation>(
|
||||
_node,
|
||||
convertJsonToASTNode<Expression>(member(_node, "leftExpression")),
|
||||
scanSingleToken(member(_node, "operator")),
|
||||
convertJsonToASTNode<Expression>(member(_node, "rightExpression"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<FunctionCall> ASTJsonImporter::createFunctionCall(Json::Value const& _node)
|
||||
{
|
||||
std::vector<ASTPointer<Expression>> arguments;
|
||||
for (auto& arg: member(_node, "arguments"))
|
||||
arguments.push_back(convertJsonToASTNode<Expression>(arg));
|
||||
std::vector<ASTPointer<ASTString>> names;
|
||||
for (auto& name: member(_node, "names"))
|
||||
{
|
||||
astAssert(name.isString(), "Expected 'names' members to be strings!");
|
||||
names.push_back(make_shared<ASTString>(name.asString()));
|
||||
}
|
||||
return createASTNode<FunctionCall>(
|
||||
_node,
|
||||
convertJsonToASTNode<Expression>(member(_node, "expression")),
|
||||
arguments,
|
||||
names
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<NewExpression> ASTJsonImporter::createNewExpression(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<NewExpression>(
|
||||
_node,
|
||||
convertJsonToASTNode<TypeName>(member(_node, "typeName"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<MemberAccess> ASTJsonImporter::createMemberAccess(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<MemberAccess>(
|
||||
_node,
|
||||
convertJsonToASTNode<Expression>(member(_node, "expression")),
|
||||
memberAsASTString(_node, "memberName")
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<IndexAccess> ASTJsonImporter::createIndexAccess(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<IndexAccess>(
|
||||
_node,
|
||||
convertJsonToASTNode<Expression>(member(_node, "baseExpression")),
|
||||
nullOrCast<Expression>(member(_node, "indexExpression"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<IndexRangeAccess> ASTJsonImporter::createIndexRangeAccess(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<IndexRangeAccess>(
|
||||
_node,
|
||||
convertJsonToASTNode<Expression>(member(_node, "baseExpression")),
|
||||
nullOrCast<Expression>(member(_node, "startExpression")),
|
||||
nullOrCast<Expression>(member(_node, "endExpression"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<Identifier> ASTJsonImporter::createIdentifier(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<Identifier>(_node, memberAsASTString(_node, "name"));
|
||||
}
|
||||
|
||||
ASTPointer<ElementaryTypeNameExpression> ASTJsonImporter::createElementaryTypeNameExpression(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<ElementaryTypeNameExpression>(
|
||||
_node,
|
||||
createElementaryTypeName(member(_node, "typeName"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<ASTNode> ASTJsonImporter::createLiteral(Json::Value const& _node)
|
||||
{
|
||||
static string const valStr = "value";
|
||||
static string const hexValStr = "hexValue";
|
||||
|
||||
astAssert(member(_node, valStr).isString() || member(_node, hexValStr).isString(), "Literal-value is unset.");
|
||||
|
||||
ASTPointer<ASTString> value = _node.isMember(hexValStr) ?
|
||||
make_shared<ASTString>(util::asString(util::fromHex(_node[hexValStr].asString()))) :
|
||||
make_shared<ASTString>(_node[valStr].asString());
|
||||
|
||||
return createASTNode<Literal>(
|
||||
_node,
|
||||
literalTokenKind(_node),
|
||||
value,
|
||||
member(_node, "subdenomination").isNull() ? Literal::SubDenomination::None : subdenomination(_node)
|
||||
);
|
||||
}
|
||||
|
||||
// ===== helper functions ==========
|
||||
|
||||
Json::Value ASTJsonImporter::member(Json::Value const& _node, string const& _name)
|
||||
{
|
||||
astAssert(_node.isMember(_name), "Node '" + _node["nodeType"].asString() + "' (id " + _node["id"].asString() + ") is missing field '" + _name + "'.");
|
||||
return _node[_name];
|
||||
}
|
||||
|
||||
Token ASTJsonImporter::scanSingleToken(Json::Value const& _node)
|
||||
{
|
||||
langutil::Scanner scanner{langutil::CharStream(_node.asString(), "")};
|
||||
astAssert(scanner.peekNextToken() == Token::EOS, "Token string is too long.");
|
||||
return scanner.currentToken();
|
||||
}
|
||||
|
||||
ASTPointer<ASTString> ASTJsonImporter::nullOrASTString(Json::Value const& _json, string const& _name)
|
||||
{
|
||||
return _json[_name].isString() ? memberAsASTString(_json, _name) : nullptr;
|
||||
}
|
||||
|
||||
ASTPointer<ASTString> ASTJsonImporter::memberAsASTString(Json::Value const& _node, string const& _name)
|
||||
{
|
||||
Json::Value value = member(_node, _name);
|
||||
astAssert(value.isString(), "field " + _name + " must be of type string.");
|
||||
return make_shared<ASTString>(_node[_name].asString());
|
||||
}
|
||||
|
||||
bool ASTJsonImporter::memberAsBool(Json::Value const& _node, string const& _name)
|
||||
{
|
||||
Json::Value value = member(_node, _name);
|
||||
astAssert(value.isBool(), "field " + _name + " must be of type boolean.");
|
||||
return _node[_name].asBool();
|
||||
}
|
||||
|
||||
|
||||
// =========== JSON to definition helpers =======================
|
||||
|
||||
ContractKind ASTJsonImporter::contractKind(Json::Value const& _node)
|
||||
{
|
||||
ContractKind kind;
|
||||
astAssert(!member(_node, "contractKind").isNull(), "'Contract-kind' can not be null.");
|
||||
if (_node["contractKind"].asString() == "interface")
|
||||
kind = ContractKind::Interface;
|
||||
else if (_node["contractKind"].asString() == "contract")
|
||||
kind = ContractKind::Contract;
|
||||
else if (_node["contractKind"].asString() == "library")
|
||||
kind = ContractKind::Library;
|
||||
else
|
||||
astAssert(false, "Unknown ContractKind");
|
||||
return kind;
|
||||
}
|
||||
|
||||
Token ASTJsonImporter::literalTokenKind(Json::Value const& _node)
|
||||
{
|
||||
astAssert(member(_node, "kind").isString(), "Token-'kind' expected to be a string.");
|
||||
Token tok;
|
||||
if (_node["kind"].asString() == "number")
|
||||
tok = Token::Number;
|
||||
else if (_node["kind"].asString() == "string")
|
||||
tok = Token::StringLiteral;
|
||||
else if (_node["kind"].asString() == "bool")
|
||||
tok = (member(_node, "value").asString() == "true") ? Token::TrueLiteral : Token::FalseLiteral;
|
||||
else
|
||||
astAssert(false, "Unknown kind of literalString");
|
||||
return tok;
|
||||
}
|
||||
|
||||
Visibility ASTJsonImporter::visibility(Json::Value const& _node)
|
||||
{
|
||||
Json::Value visibility = member(_node, "visibility");
|
||||
astAssert(visibility.isString(), "'visibility' expected to be a string.");
|
||||
|
||||
string const visibilityStr = visibility.asString();
|
||||
|
||||
if (visibilityStr == "default")
|
||||
return Visibility::Default;
|
||||
else if (visibilityStr == "private")
|
||||
return Visibility::Private;
|
||||
else if ( visibilityStr == "internal")
|
||||
return Visibility::Internal;
|
||||
else if (visibilityStr == "public")
|
||||
return Visibility::Public;
|
||||
else if (visibilityStr == "external")
|
||||
return Visibility::External;
|
||||
else
|
||||
astAssert(false, "Unknown visibility declaration");
|
||||
}
|
||||
|
||||
VariableDeclaration::Location ASTJsonImporter::location(Json::Value const& _node)
|
||||
{
|
||||
Json::Value storageLoc = member(_node, "storageLocation");
|
||||
astAssert(storageLoc.isString(), "'storageLocation' expected to be a string.");
|
||||
|
||||
string const storageLocStr = storageLoc.asString();
|
||||
|
||||
if (storageLocStr == "default")
|
||||
return VariableDeclaration::Location::Unspecified;
|
||||
else if (storageLocStr == "storage")
|
||||
return VariableDeclaration::Location::Storage;
|
||||
else if (storageLocStr == "memory")
|
||||
return VariableDeclaration::Location::Memory;
|
||||
else if (storageLocStr == "calldata")
|
||||
return VariableDeclaration::Location::CallData;
|
||||
else
|
||||
astAssert(false, "Unknown location declaration");
|
||||
}
|
||||
|
||||
Literal::SubDenomination ASTJsonImporter::subdenomination(Json::Value const& _node)
|
||||
{
|
||||
Json::Value subDen = member(_node, "subdenomination");
|
||||
|
||||
if (subDen.isNull())
|
||||
return Literal::SubDenomination::None;
|
||||
|
||||
astAssert(subDen.isString(), "'subDenomination' expected to be string.");
|
||||
|
||||
string const subDenStr = subDen.asString();
|
||||
|
||||
if (subDenStr == "wei")
|
||||
return Literal::SubDenomination::Wei;
|
||||
else if (subDenStr == "szabo")
|
||||
return Literal::SubDenomination::Szabo;
|
||||
else if (subDenStr == "finney")
|
||||
return Literal::SubDenomination::Finney;
|
||||
else if (subDenStr == "ether")
|
||||
return Literal::SubDenomination::Ether;
|
||||
else if (subDenStr == "seconds")
|
||||
return Literal::SubDenomination::Second;
|
||||
else if (subDenStr == "minutes")
|
||||
return Literal::SubDenomination::Minute;
|
||||
else if (subDenStr == "hours")
|
||||
return Literal::SubDenomination::Hour;
|
||||
else if (subDenStr == "days")
|
||||
return Literal::SubDenomination::Day;
|
||||
else if (subDenStr == "weeks")
|
||||
return Literal::SubDenomination::Week;
|
||||
else if (subDenStr == "years")
|
||||
return Literal::SubDenomination::Year;
|
||||
else
|
||||
astAssert(false, "Unknown subdenomination");
|
||||
}
|
||||
|
||||
StateMutability ASTJsonImporter::stateMutability(Json::Value const& _node)
|
||||
{
|
||||
astAssert(member(_node, "stateMutability").isString(), "StateMutability' expected to be string.");
|
||||
string const mutabilityStr = member(_node, "stateMutability").asString();
|
||||
|
||||
if (mutabilityStr == "pure")
|
||||
return StateMutability::Pure;
|
||||
else if (mutabilityStr == "view")
|
||||
return StateMutability::View;
|
||||
else if (mutabilityStr == "nonpayable")
|
||||
return StateMutability::NonPayable;
|
||||
else if (mutabilityStr == "payable")
|
||||
return StateMutability::Payable;
|
||||
else
|
||||
astAssert(false, "Unknown stateMutability");
|
||||
}
|
||||
|
||||
}
|
161
libsolidity/ast/ASTJsonImporter.h
Normal file
161
libsolidity/ast/ASTJsonImporter.h
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @author julius <djudju@protonmail.com>
|
||||
* @date 2019
|
||||
* Converts the AST from JSON format to ASTNode
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <json/json.h>
|
||||
#include <libsolidity/ast/ASTAnnotations.h>
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
#include <liblangutil/Exceptions.h>
|
||||
#include <liblangutil/SourceLocation.h>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
/**
|
||||
* Component that imports an AST from json format to the internal format
|
||||
*/
|
||||
class ASTJsonImporter
|
||||
{
|
||||
public:
|
||||
ASTJsonImporter(langutil::EVMVersion _evmVersion)
|
||||
:m_evmVersion(_evmVersion)
|
||||
{}
|
||||
|
||||
/// Converts the AST from JSON-format to ASTPointer
|
||||
/// @a _sourceList used to provide source names for the ASTs
|
||||
/// @returns map of sourcenames to their respective ASTs
|
||||
std::map<std::string, ASTPointer<SourceUnit>> jsonToSourceUnit(std::map<std::string, Json::Value> const& _sourceList);
|
||||
|
||||
private:
|
||||
|
||||
// =========== general creation functions ==============
|
||||
|
||||
/// Sets the source location and nodeID
|
||||
/// @returns the ASTNode Object class of the respective JSON node,
|
||||
template <typename T, typename... Args>
|
||||
ASTPointer<T> createASTNode(Json::Value const& _node, Args&&... _args);
|
||||
/// @returns the sourceLocation-object created from the string in the JSON node
|
||||
langutil::SourceLocation const createSourceLocation(Json::Value const& _node);
|
||||
/// Creates an ASTNode for a given JSON-ast of unknown type
|
||||
/// @returns Pointer to a new created ASTNode
|
||||
ASTPointer<ASTNode> convertJsonToASTNode(Json::Value const& _ast);
|
||||
/// @returns a pointer to the more specific subclass of ASTNode
|
||||
/// as indicated by the nodeType field of the json
|
||||
template<class T>
|
||||
ASTPointer<T> convertJsonToASTNode(Json::Value const& _node);
|
||||
|
||||
|
||||
/// \defgroup nodeCreators JSON to AST-Nodes
|
||||
///@{
|
||||
ASTPointer<SourceUnit> createSourceUnit(Json::Value const& _node, std::string const& _srcName);
|
||||
ASTPointer<PragmaDirective> createPragmaDirective(Json::Value const& _node);
|
||||
ASTPointer<ImportDirective> createImportDirective(Json::Value const& _node);
|
||||
ASTPointer<ContractDefinition> createContractDefinition(Json::Value const& _node);
|
||||
ASTPointer<InheritanceSpecifier> createInheritanceSpecifier(Json::Value const& _node);
|
||||
ASTPointer<UsingForDirective> createUsingForDirective(Json::Value const& _node);
|
||||
ASTPointer<ASTNode> createStructDefinition(Json::Value const& _node);
|
||||
ASTPointer<EnumDefinition> createEnumDefinition(Json::Value const& _node);
|
||||
ASTPointer<EnumValue> createEnumValue(Json::Value const& _node);
|
||||
ASTPointer<ParameterList> createParameterList(Json::Value const& _node);
|
||||
ASTPointer<OverrideSpecifier> createOverrideSpecifier(Json::Value const& _node);
|
||||
ASTPointer<FunctionDefinition> createFunctionDefinition(Json::Value const& _node);
|
||||
ASTPointer<VariableDeclaration> createVariableDeclaration(Json::Value const& _node);
|
||||
ASTPointer<ModifierDefinition> createModifierDefinition(Json::Value const& _node);
|
||||
ASTPointer<ModifierInvocation> createModifierInvocation(Json::Value const& _node);
|
||||
ASTPointer<EventDefinition> createEventDefinition(Json::Value const& _node);
|
||||
ASTPointer<ElementaryTypeName> createElementaryTypeName(Json::Value const& _node);
|
||||
ASTPointer<UserDefinedTypeName> createUserDefinedTypeName(Json::Value const& _node);
|
||||
ASTPointer<FunctionTypeName> createFunctionTypeName(Json::Value const& _node);
|
||||
ASTPointer<Mapping> createMapping(Json::Value const& _node);
|
||||
ASTPointer<ArrayTypeName> createArrayTypeName(Json::Value const& _node);
|
||||
ASTPointer<InlineAssembly> createInlineAssembly(Json::Value const& _node);
|
||||
ASTPointer<Block> createBlock(Json::Value const& _node);
|
||||
ASTPointer<PlaceholderStatement> createPlaceholderStatement(Json::Value const& _node);
|
||||
ASTPointer<IfStatement> createIfStatement(Json::Value const& _node);
|
||||
ASTPointer<TryCatchClause> createTryCatchClause(Json::Value const& _node);
|
||||
ASTPointer<TryStatement> createTryStatement(Json::Value const& _node);
|
||||
ASTPointer<WhileStatement> createWhileStatement(Json::Value const& _node, bool _isDoWhile);
|
||||
ASTPointer<ForStatement> createForStatement(Json::Value const& _node);
|
||||
ASTPointer<Continue> createContinue(Json::Value const& _node);
|
||||
ASTPointer<Break> createBreak(Json::Value const& _node);
|
||||
ASTPointer<Return> createReturn(Json::Value const& _node);
|
||||
ASTPointer<Throw> createThrow(Json::Value const& _node);
|
||||
ASTPointer<EmitStatement> createEmitStatement(Json::Value const& _node);
|
||||
ASTPointer<VariableDeclarationStatement> createVariableDeclarationStatement(Json::Value const& _node);
|
||||
ASTPointer<ExpressionStatement> createExpressionStatement(Json::Value const& _node);
|
||||
ASTPointer<Conditional> createConditional(Json::Value const& _node);
|
||||
ASTPointer<Assignment> createAssignment(Json::Value const& _node);
|
||||
ASTPointer<TupleExpression> createTupleExpression(Json::Value const& _node);
|
||||
ASTPointer<UnaryOperation> createUnaryOperation(Json::Value const& _node);
|
||||
ASTPointer<BinaryOperation> createBinaryOperation(Json::Value const& _node);
|
||||
ASTPointer<FunctionCall> createFunctionCall(Json::Value const& _node);
|
||||
ASTPointer<NewExpression> createNewExpression(Json::Value const& _node);
|
||||
ASTPointer<MemberAccess> createMemberAccess(Json::Value const& _node);
|
||||
ASTPointer<IndexAccess> createIndexAccess(Json::Value const& _node);
|
||||
ASTPointer<IndexRangeAccess> createIndexRangeAccess(Json::Value const& _node);
|
||||
ASTPointer<Identifier> createIdentifier(Json::Value const& _node);
|
||||
ASTPointer<ElementaryTypeNameExpression> createElementaryTypeNameExpression(Json::Value const& _node);
|
||||
ASTPointer<ASTNode> createLiteral(Json::Value const& _node);
|
||||
///@}
|
||||
|
||||
// =============== general helper functions ===================
|
||||
/// @returns the member of a given JSON object, throws if member does not exist
|
||||
Json::Value member(Json::Value const& _node, std::string const& _name);
|
||||
/// @returns the appropriate TokenObject used in parsed Strings (pragma directive or operator)
|
||||
Token scanSingleToken(Json::Value const& _node);
|
||||
template<class T>
|
||||
///@returns nullptr or an ASTPointer cast to a specific Class
|
||||
ASTPointer<T> nullOrCast(Json::Value const& _json);
|
||||
/// @returns nullptr or ASTString, given an JSON string or an empty field
|
||||
ASTPointer<ASTString> nullOrASTString(Json::Value const& _json, std::string const& _name);
|
||||
|
||||
// ============== JSON to definition helpers ===============
|
||||
/// \defgroup typeHelpers Json to ast-datatype helpers
|
||||
/// {@
|
||||
ASTPointer<ASTString> memberAsASTString(Json::Value const& _node, std::string const& _name);
|
||||
bool memberAsBool(Json::Value const& _node, std::string const& _name);
|
||||
Visibility visibility(Json::Value const& _node);
|
||||
StateMutability stateMutability(Json::Value const& _node);
|
||||
VariableDeclaration::Location location(Json::Value const& _node);
|
||||
ContractKind contractKind(Json::Value const& _node);
|
||||
Token literalTokenKind(Json::Value const& _node);
|
||||
Literal::SubDenomination subdenomination(Json::Value const& _node);
|
||||
///@}
|
||||
|
||||
// =========== member variables ===============
|
||||
/// Stores filepath as sourcenames to AST in JSON format
|
||||
std::map<std::string, Json::Value> m_sourceList;
|
||||
/// list of filepaths (used as sourcenames)
|
||||
std::vector<std::shared_ptr<std::string const>> m_sourceLocations;
|
||||
/// filepath to AST
|
||||
std::map<std::string, ASTPointer<SourceUnit>> m_sourceUnits;
|
||||
std::string m_currentSourceName;
|
||||
/// IDs already used by the nodes
|
||||
std::set<int64_t> m_usedIDs;
|
||||
/// Configured EVM version
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
};
|
||||
|
||||
}
|
303
libsolidity/ast/AsmJsonImporter.cpp
Normal file
303
libsolidity/ast/AsmJsonImporter.cpp
Normal file
@ -0,0 +1,303 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @author julius <djudju@protonmail.com>
|
||||
* @date 2019
|
||||
* Converts an inlineAssembly AST from JSON format to AsmData
|
||||
|
||||
*/
|
||||
|
||||
#include <libsolidity/ast/AsmJsonImporter.h>
|
||||
#include <libsolidity/ast/ASTJsonImporter.h>
|
||||
#include <libsolidity/ast/Types.h>
|
||||
#include <libyul/AsmData.h>
|
||||
#include <libyul/AsmDataForward.h>
|
||||
#include <liblangutil/Exceptions.h>
|
||||
#include <liblangutil/Scanner.h>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::yul;
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
using SourceLocation = langutil::SourceLocation;
|
||||
|
||||
SourceLocation const AsmJsonImporter::createSourceLocation(Json::Value const& _node)
|
||||
{
|
||||
astAssert(member(_node, "src").isString(), "'src' must be a string");
|
||||
|
||||
return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_sourceName);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T AsmJsonImporter::createAsmNode(Json::Value const& _node)
|
||||
{
|
||||
T r;
|
||||
r.location = createSourceLocation(_node);
|
||||
astAssert(!r.location.isEmpty() || !r.location.source, "Invalid source location in Asm AST");
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
Json::Value AsmJsonImporter::member(Json::Value const& _node, string const& _name)
|
||||
{
|
||||
astAssert(_node.isMember(_name), "Node is missing field '" + _name + "'.");
|
||||
return _node[_name];
|
||||
}
|
||||
|
||||
yul::TypedName AsmJsonImporter::createTypedName(Json::Value const& _node)
|
||||
{
|
||||
auto typedName = createAsmNode<yul::TypedName>(_node);
|
||||
typedName.type = YulString{member(_node, "type").asString()};
|
||||
typedName.name = YulString{member(_node, "name").asString()};
|
||||
return typedName;
|
||||
}
|
||||
|
||||
yul::Statement AsmJsonImporter::createStatement(Json::Value const& _node)
|
||||
{
|
||||
Json::Value jsonNodeType = member(_node, "nodeType");
|
||||
astAssert(jsonNodeType.isString(), "Expected \"nodeType\" to be of type string!");
|
||||
string nodeType = jsonNodeType.asString();
|
||||
|
||||
astAssert(nodeType.substr(0, 3) == "Yul", "Invalid nodeType prefix");
|
||||
nodeType = nodeType.substr(3);
|
||||
|
||||
if (nodeType == "ExpressionStatement")
|
||||
return createExpressionStatement(_node);
|
||||
else if (nodeType == "Assignment")
|
||||
return createAssignment(_node);
|
||||
else if (nodeType == "VariableDeclaration")
|
||||
return createVariableDeclaration(_node);
|
||||
else if (nodeType == "FunctionDefinition")
|
||||
return createFunctionDefinition(_node);
|
||||
else if (nodeType == "If")
|
||||
return createIf(_node);
|
||||
else if (nodeType == "Switch")
|
||||
return createSwitch(_node);
|
||||
else if (nodeType == "ForLoop")
|
||||
return createForLoop(_node);
|
||||
else if (nodeType == "Break")
|
||||
return createBreak(_node);
|
||||
else if (nodeType == "Continue")
|
||||
return createContinue(_node);
|
||||
else if (nodeType == "Leave")
|
||||
return createLeave(_node);
|
||||
else
|
||||
astAssert(false, "Invalid nodeType as statement");
|
||||
}
|
||||
|
||||
yul::Expression AsmJsonImporter::createExpression(Json::Value const& _node)
|
||||
{
|
||||
Json::Value jsonNodeType = member(_node, "nodeType");
|
||||
astAssert(jsonNodeType.isString(), "Expected \"nodeType\" to be of type string!");
|
||||
string nodeType = jsonNodeType.asString();
|
||||
|
||||
astAssert(nodeType.substr(0, 3) == "Yul", "Invalid nodeType prefix");
|
||||
nodeType = nodeType.substr(3);
|
||||
|
||||
if (nodeType == "FunctionCall")
|
||||
return createFunctionCall(_node);
|
||||
else if (nodeType == "Identifier")
|
||||
return createIdentifier(_node);
|
||||
else if (nodeType == "Literal")
|
||||
return createLiteral(_node);
|
||||
else
|
||||
astAssert(false, "Invalid nodeType as expression");
|
||||
}
|
||||
|
||||
vector<yul::Expression> AsmJsonImporter::createExpressionVector(Json::Value const& _array)
|
||||
{
|
||||
vector<yul::Expression> ret;
|
||||
for (auto& var: _array)
|
||||
ret.emplace_back(createExpression(var));
|
||||
return ret;
|
||||
}
|
||||
|
||||
vector<yul::Statement> AsmJsonImporter::createStatementVector(Json::Value const& _array)
|
||||
{
|
||||
vector<yul::Statement> ret;
|
||||
for (auto& var: _array)
|
||||
ret.emplace_back(createStatement(var));
|
||||
return ret;
|
||||
}
|
||||
|
||||
yul::Block AsmJsonImporter::createBlock(Json::Value const& _node)
|
||||
{
|
||||
auto block = createAsmNode<yul::Block>(_node);
|
||||
block.statements = createStatementVector(_node["statements"]);
|
||||
return block;
|
||||
}
|
||||
|
||||
yul::Literal AsmJsonImporter::createLiteral(Json::Value const& _node)
|
||||
{
|
||||
auto lit = createAsmNode<yul::Literal>(_node);
|
||||
string kind = member(_node, "kind").asString();
|
||||
|
||||
lit.value = YulString{member(_node, "value").asString()};
|
||||
lit.type= YulString{member(_node, "type").asString()};
|
||||
|
||||
langutil::Scanner scanner{langutil::CharStream(lit.value.str(), "")};
|
||||
|
||||
if (kind == "number")
|
||||
{
|
||||
lit.kind = yul::LiteralKind::Number;
|
||||
astAssert(
|
||||
scanner.currentToken() == Token::Number,
|
||||
"Expected number but got " + langutil::TokenTraits::friendlyName(scanner.currentToken()) + string(" while scanning ") + lit.value.str()
|
||||
);
|
||||
}
|
||||
else if (kind == "bool")
|
||||
{
|
||||
lit.kind = yul::LiteralKind::Boolean;
|
||||
astAssert(
|
||||
scanner.currentToken() == Token::TrueLiteral ||
|
||||
scanner.currentToken() == Token::FalseLiteral,
|
||||
"Expected true/false literal!"
|
||||
);
|
||||
}
|
||||
else if (kind == "string")
|
||||
{
|
||||
lit.kind = yul::LiteralKind::String;
|
||||
astAssert(scanner.currentToken() == Token::StringLiteral, "Expected string literal!");
|
||||
}
|
||||
else
|
||||
solAssert(false, "unknown type of literal");
|
||||
|
||||
return lit;
|
||||
}
|
||||
|
||||
yul::Leave AsmJsonImporter::createLeave(Json::Value const& _node)
|
||||
{
|
||||
return createAsmNode<yul::Leave>(_node);
|
||||
}
|
||||
|
||||
yul::Identifier AsmJsonImporter::createIdentifier(Json::Value const& _node)
|
||||
{
|
||||
auto identifier = createAsmNode<yul::Identifier>(_node);
|
||||
identifier.name = YulString(member(_node, "name").asString());
|
||||
return identifier;
|
||||
}
|
||||
|
||||
yul::Assignment AsmJsonImporter::createAssignment(Json::Value const& _node)
|
||||
{
|
||||
auto assignment = createAsmNode<yul::Assignment>(_node);
|
||||
|
||||
if (_node.isMember("variableNames"))
|
||||
for (auto const& var: member(_node, "variableNames"))
|
||||
assignment.variableNames.emplace_back(createIdentifier(var));
|
||||
|
||||
assignment.value = make_unique<yul::Expression>(createExpression(member(_node, "value")));
|
||||
return assignment;
|
||||
}
|
||||
|
||||
yul::FunctionCall AsmJsonImporter::createFunctionCall(Json::Value const& _node)
|
||||
{
|
||||
auto functionCall = createAsmNode<yul::FunctionCall>(_node);
|
||||
|
||||
for (auto const& var: member(_node, "arguments"))
|
||||
functionCall.arguments.emplace_back(createExpression(var));
|
||||
|
||||
functionCall.functionName = createIdentifier(member(_node, "functionName"));
|
||||
|
||||
return functionCall;
|
||||
}
|
||||
|
||||
yul::ExpressionStatement AsmJsonImporter::createExpressionStatement(Json::Value const& _node)
|
||||
{
|
||||
auto statement = createAsmNode<yul::ExpressionStatement>(_node);
|
||||
statement.expression = createExpression(member(_node, "expression"));
|
||||
return statement;
|
||||
}
|
||||
|
||||
yul::VariableDeclaration AsmJsonImporter::createVariableDeclaration(Json::Value const& _node)
|
||||
{
|
||||
auto varDec = createAsmNode<yul::VariableDeclaration>(_node);
|
||||
for (auto const& var: member(_node, "variables"))
|
||||
varDec.variables.emplace_back(createTypedName(var));
|
||||
varDec.value = make_unique<yul::Expression>(createExpression(member(_node, "value")));
|
||||
return varDec;
|
||||
}
|
||||
|
||||
yul::FunctionDefinition AsmJsonImporter::createFunctionDefinition(Json::Value const& _node)
|
||||
{
|
||||
auto funcDef = createAsmNode<yul::FunctionDefinition>(_node);
|
||||
funcDef.name = YulString{member(_node, "name").asString()};
|
||||
|
||||
if (_node.isMember("parameters"))
|
||||
for (auto const& var: member(_node, "parameters"))
|
||||
funcDef.parameters.emplace_back(createTypedName(var));
|
||||
|
||||
if (_node.isMember("returnVariables"))
|
||||
for (auto const& var: member(_node, "returnVariables"))
|
||||
funcDef.returnVariables.emplace_back(createTypedName(var));
|
||||
|
||||
funcDef.body = createBlock(member(_node, "body"));
|
||||
return funcDef;
|
||||
}
|
||||
|
||||
yul::If AsmJsonImporter::createIf(Json::Value const& _node)
|
||||
{
|
||||
auto ifStatement = createAsmNode<yul::If>(_node);
|
||||
ifStatement.condition = make_unique<yul::Expression>(createExpression(member(_node, "condition")));
|
||||
ifStatement.body = createBlock(member(_node, "body"));
|
||||
return ifStatement;
|
||||
}
|
||||
|
||||
yul::Case AsmJsonImporter::createCase(Json::Value const& _node)
|
||||
{
|
||||
auto caseStatement = createAsmNode<yul::Case>(_node);
|
||||
caseStatement.value = member(_node, "value").asString() == "default" ? nullptr : make_unique<yul::Literal>(createLiteral(member(_node, "value")));
|
||||
caseStatement.body = createBlock(member(_node, "body"));
|
||||
return caseStatement;
|
||||
}
|
||||
|
||||
yul::Switch AsmJsonImporter::createSwitch(Json::Value const& _node)
|
||||
{
|
||||
auto switchStatement = createAsmNode<yul::Switch>(_node);
|
||||
switchStatement.expression = make_unique<yul::Expression>(createExpression(member(_node, "value")));
|
||||
for (auto const& var: member(_node, "cases"))
|
||||
switchStatement.cases.emplace_back(createCase(var));
|
||||
return switchStatement;
|
||||
}
|
||||
|
||||
yul::ForLoop AsmJsonImporter::createForLoop(Json::Value const& _node)
|
||||
{
|
||||
auto forLoop = createAsmNode<yul::ForLoop>(_node);
|
||||
forLoop.pre = createBlock(member(_node, "pre"));
|
||||
forLoop.condition = make_unique<yul::Expression>(createExpression(member(_node, "condition")));
|
||||
forLoop.post = createBlock(member(_node, "post"));
|
||||
forLoop.body = createBlock(member(_node, "body"));
|
||||
return forLoop;
|
||||
}
|
||||
|
||||
yul::Break AsmJsonImporter::createBreak(Json::Value const& _node)
|
||||
{
|
||||
return createAsmNode<yul::Break>(_node);
|
||||
}
|
||||
|
||||
yul::Continue AsmJsonImporter::createContinue(Json::Value const& _node)
|
||||
{
|
||||
return createAsmNode<yul::Continue>(_node);
|
||||
}
|
||||
|
||||
}
|
74
libsolidity/ast/AsmJsonImporter.h
Normal file
74
libsolidity/ast/AsmJsonImporter.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @author julius <djudju@protonmail.com>
|
||||
* @date 2019
|
||||
* Converts an inlineAssembly AST from JSON format to AsmData
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <json/json.h>
|
||||
#include <liblangutil/SourceLocation.h>
|
||||
#include <libyul/AsmDataForward.h>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
/**
|
||||
* Component that imports an AST from json format to the internal format
|
||||
*/
|
||||
class AsmJsonImporter
|
||||
{
|
||||
public:
|
||||
explicit AsmJsonImporter(std::string _sourceName) : m_sourceName(_sourceName) {}
|
||||
yul::Block createBlock(Json::Value const& _node);
|
||||
|
||||
private:
|
||||
langutil::SourceLocation const createSourceLocation(Json::Value const& _node);
|
||||
template <class T>
|
||||
T createAsmNode(Json::Value const& _node);
|
||||
/// helper function to access member functions of the JSON
|
||||
/// and throw an error if it does not exist
|
||||
Json::Value member(Json::Value const& _node, std::string const& _name);
|
||||
|
||||
yul::Statement createStatement(Json::Value const& _node);
|
||||
yul::Expression createExpression(Json::Value const& _node);
|
||||
std::vector<yul::Statement> createStatementVector(Json::Value const& _array);
|
||||
std::vector<yul::Expression> createExpressionVector(Json::Value const& _array);
|
||||
|
||||
yul::TypedName createTypedName(Json::Value const& _node);
|
||||
yul::Literal createLiteral(Json::Value const& _node);
|
||||
yul::Leave createLeave(Json::Value const& _node);
|
||||
yul::Identifier createIdentifier(Json::Value const& _node);
|
||||
yul::Assignment createAssignment(Json::Value const& _node);
|
||||
yul::FunctionCall createFunctionCall(Json::Value const& _node);
|
||||
yul::ExpressionStatement createExpressionStatement(Json::Value const& _node);
|
||||
yul::VariableDeclaration createVariableDeclaration(Json::Value const& _node);
|
||||
yul::FunctionDefinition createFunctionDefinition(Json::Value const& _node);
|
||||
yul::If createIf(Json::Value const& _node);
|
||||
yul::Case createCase(Json::Value const& _node);
|
||||
yul::Switch createSwitch(Json::Value const& _node);
|
||||
yul::ForLoop createForLoop(Json::Value const& _node);
|
||||
yul::Break createBreak(Json::Value const& _node);
|
||||
yul::Continue createContinue(Json::Value const& _node);
|
||||
|
||||
std::string m_sourceName;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -38,6 +38,7 @@
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/ast/ASTJsonImporter.h>
|
||||
#include <libsolidity/codegen/Compiler.h>
|
||||
#include <libsolidity/formal/ModelChecker.h>
|
||||
#include <libsolidity/interface/ABI.h>
|
||||
@ -233,11 +234,12 @@ bool CompilerStack::parse()
|
||||
if (m_stackState != SourcesSet)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must call parse only after the SourcesSet state."));
|
||||
m_errorReporter.clear();
|
||||
ASTNode::resetID();
|
||||
|
||||
if (SemVerVersion{string(VersionString)}.isPrerelease())
|
||||
m_errorReporter.warning("This is a pre-release compiler version, please do not use it in production.");
|
||||
|
||||
Parser parser{m_errorReporter, m_evmVersion, m_parserErrorRecovery};
|
||||
|
||||
vector<string> sourcesToParse;
|
||||
for (auto const& s: m_sources)
|
||||
sourcesToParse.push_back(s.first);
|
||||
@ -246,7 +248,7 @@ bool CompilerStack::parse()
|
||||
string const& path = sourcesToParse[i];
|
||||
Source& source = m_sources[path];
|
||||
source.scanner->reset();
|
||||
source.ast = Parser(m_errorReporter, m_evmVersion, m_parserErrorRecovery).parse(source.scanner);
|
||||
source.ast = parser.parse(source.scanner);
|
||||
if (!source.ast)
|
||||
solAssert(!Error::containsOnlyWarnings(m_errorReporter.errors()), "Parser returned null but did not report error.");
|
||||
else
|
||||
@ -268,6 +270,26 @@ bool CompilerStack::parse()
|
||||
return !m_hasError;
|
||||
}
|
||||
|
||||
void CompilerStack::importASTs(map<string, Json::Value> const& _sources)
|
||||
{
|
||||
if (m_stackState != Empty)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must call importASTs only before the SourcesSet state."));
|
||||
m_sourceJsons = _sources;
|
||||
map<string, ASTPointer<SourceUnit>> reconstructedSources = ASTJsonImporter(m_evmVersion).jsonToSourceUnit(m_sourceJsons);
|
||||
for (auto& src: reconstructedSources)
|
||||
{
|
||||
string const& path = src.first;
|
||||
Source source;
|
||||
source.ast = src.second;
|
||||
string srcString = util::jsonCompactPrint(m_sourceJsons[src.first]);
|
||||
ASTPointer<Scanner> scanner = make_shared<Scanner>(langutil::CharStream(srcString, src.first));
|
||||
source.scanner = scanner;
|
||||
m_sources[path] = source;
|
||||
}
|
||||
m_stackState = ParsingPerformed;
|
||||
m_importedSources = true;
|
||||
}
|
||||
|
||||
bool CompilerStack::analyze()
|
||||
{
|
||||
if (m_stackState != ParsingPerformed || m_stackState >= AnalysisPerformed)
|
||||
@ -1158,7 +1180,7 @@ string CompilerStack::createMetadata(Contract const& _contract) const
|
||||
{
|
||||
Json::Value meta;
|
||||
meta["version"] = 1;
|
||||
meta["language"] = "Solidity";
|
||||
meta["language"] = m_importedSources ? "SolidityAST" : "Solidity";
|
||||
meta["compiler"]["version"] = VersionStringStrict;
|
||||
|
||||
/// All the source files (including self), which should be included in the metadata.
|
||||
|
@ -199,6 +199,10 @@ public:
|
||||
/// @returns false on error.
|
||||
bool parse();
|
||||
|
||||
/// Imports given SourceUnits so they can be analyzed. Leads to the same internal state as parse().
|
||||
/// Will throw errors if the import fails
|
||||
void importASTs(std::map<std::string, Json::Value> const& _sources);
|
||||
|
||||
/// Performs the analysis steps (imports, scopesetting, syntaxCheck, referenceResolving,
|
||||
/// typechecking, staticAnalysis) on previously parsed sources.
|
||||
/// @returns false on error.
|
||||
@ -440,6 +444,8 @@ private:
|
||||
/// "context:prefix=target"
|
||||
std::vector<Remapping> m_remappings;
|
||||
std::map<std::string const, Source> m_sources;
|
||||
// if imported, store AST-JSONS for each filename
|
||||
std::map<std::string, Json::Value> m_sourceJsons;
|
||||
std::vector<std::string> m_unhandledSMTLib2Queries;
|
||||
std::map<util::h256, std::string> m_smtlib2Responses;
|
||||
std::shared_ptr<GlobalContext> m_globalContext;
|
||||
@ -453,6 +459,7 @@ private:
|
||||
MetadataHash m_metadataHash = MetadataHash::IPFS;
|
||||
bool m_parserErrorRecovery = false;
|
||||
State m_stackState = Empty;
|
||||
bool m_importedSources = false;
|
||||
/// Whether or not there has been an error during processing.
|
||||
/// If this is true, the stack will refuse to generate code.
|
||||
bool m_hasError = false;
|
||||
|
@ -44,9 +44,9 @@ namespace solidity::frontend
|
||||
class Parser::ASTNodeFactory
|
||||
{
|
||||
public:
|
||||
explicit ASTNodeFactory(Parser const& _parser):
|
||||
explicit ASTNodeFactory(Parser& _parser):
|
||||
m_parser(_parser), m_location{_parser.position(), -1, _parser.source()} {}
|
||||
ASTNodeFactory(Parser const& _parser, ASTPointer<ASTNode> const& _childNode):
|
||||
ASTNodeFactory(Parser& _parser, ASTPointer<ASTNode> const& _childNode):
|
||||
m_parser(_parser), m_location{_childNode->location()} {}
|
||||
|
||||
void markEndPosition() { m_location.end = m_parser.endPosition(); }
|
||||
@ -61,18 +61,19 @@ public:
|
||||
solAssert(m_location.source, "");
|
||||
if (m_location.end < 0)
|
||||
markEndPosition();
|
||||
return make_shared<NodeType>(m_location, std::forward<Args>(_args)...);
|
||||
return make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...);
|
||||
}
|
||||
|
||||
SourceLocation const& location() const noexcept { return m_location; }
|
||||
|
||||
private:
|
||||
Parser const& m_parser;
|
||||
Parser& m_parser;
|
||||
SourceLocation m_location;
|
||||
};
|
||||
|
||||
ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner)
|
||||
{
|
||||
solAssert(!m_insideModifier, "");
|
||||
try
|
||||
{
|
||||
m_recursionDepth = 0;
|
||||
@ -1193,7 +1194,7 @@ ASTPointer<InlineAssembly> Parser::parseInlineAssembly(ASTPointer<ASTString> con
|
||||
BOOST_THROW_EXCEPTION(FatalError());
|
||||
|
||||
location.end = block->location.end;
|
||||
return make_shared<InlineAssembly>(location, _docString, dialect, block);
|
||||
return make_shared<InlineAssembly>(nextID(), location, _docString, dialect, block);
|
||||
}
|
||||
|
||||
ASTPointer<IfStatement> Parser::parseIfStatement(ASTPointer<ASTString> const& _docString)
|
||||
|
@ -173,6 +173,9 @@ private:
|
||||
bool empty() const;
|
||||
};
|
||||
|
||||
/// Returns the next AST node ID
|
||||
int64_t nextID() { return ++m_currentNodeID; }
|
||||
|
||||
std::pair<LookAheadInfo, IndexAccessedPath> tryParseIndexAccessedPath();
|
||||
/// Performs limited look-ahead to distinguish between variable declaration and expression statement.
|
||||
/// For source code of the form "a[][8]" ("IndexAccessStructure"), this is not possible to
|
||||
@ -198,6 +201,8 @@ private:
|
||||
/// Flag that signifies whether '_' is parsed as a PlaceholderStatement or a regular identifier.
|
||||
bool m_insideModifier = false;
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
/// Counter for the next AST node ID
|
||||
int64_t m_currentNodeID = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
113
scripts/ASTImportTest.sh
Executable file
113
scripts/ASTImportTest.sh
Executable file
@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Bash script to test the ast-import option of the compiler by
|
||||
# first exporting a .sol file to JSON, then loading it into the compiler
|
||||
# and exporting it again. The second JSON should be identical to the first
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")"/..)
|
||||
SOLIDITY_BUILD_DIR=${SOLIDITY_BUILD_DIR:-build}
|
||||
SOLC=${REPO_ROOT}/${SOLIDITY_BUILD_DIR}/solc/solc
|
||||
SPLITSOURCES=${REPO_ROOT}/scripts/splitSources.py
|
||||
|
||||
SYNTAXTESTS_DIR="${REPO_ROOT}/test/libsolidity/syntaxTests"
|
||||
NSOURCES="$(find $SYNTAXTESTS_DIR -type f | wc -l)"
|
||||
|
||||
# DEV_DIR="${REPO_ROOT}/../tmp/contracts/"
|
||||
# NSOURCES="$(find $DEV_DIR -type f | wc -l)" #TODO use find command
|
||||
|
||||
FAILED=0
|
||||
UNCOMPILABLE=0
|
||||
TESTED=0
|
||||
|
||||
if [ $(ls | wc -l) -ne 0 ]; then
|
||||
echo "Test directory not empty. Skipping!"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# function tests whether exporting and importing again leaves the JSON ast unchanged
|
||||
# Results are recorded by adding to FAILED or UNCOMPILABLE.
|
||||
# Also, in case of a mismatch a diff and the respective ASTs are printed
|
||||
# Expected parameters:
|
||||
# $1 name of the file to be exported and imported
|
||||
# $2 any files needed to do so that might be in parent directories
|
||||
function testImportExportEquivalence {
|
||||
if $SOLC $1 $2 > /dev/null 2>&1
|
||||
then
|
||||
# save exported json as expected result (silently)
|
||||
$SOLC --combined-json ast,compact-format --pretty-json $1 $2> expected.json 2> /dev/null
|
||||
# import it, and export it again as obtained result (silently)
|
||||
$SOLC --import-ast --combined-json ast,compact-format --pretty-json expected.json > obtained.json 2> /dev/null
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
# For investigating, use exit 1 here so the script stops at the
|
||||
# first failing test
|
||||
# exit 1
|
||||
FAILED=$((FAILED + 1))
|
||||
return 1
|
||||
fi
|
||||
DIFF="$(diff expected.json obtained.json)"
|
||||
if [ "$DIFF" != "" ]
|
||||
then
|
||||
if [ "$DIFFVIEW" == "" ]
|
||||
then
|
||||
echo -e "ERROR: JSONS differ for $1: \n $DIFF \n"
|
||||
echo "Expected:"
|
||||
echo "$(cat ./expected.json)"
|
||||
echo "Obtained:"
|
||||
echo "$(cat ./obtained.json)"
|
||||
else
|
||||
# Use user supplied diff view binary
|
||||
$DIFFVIEW expected.json obtained.json
|
||||
fi
|
||||
FAILED=$((FAILED + 1))
|
||||
return 2
|
||||
fi
|
||||
TESTED=$((TESTED + 1))
|
||||
rm expected.json obtained.json
|
||||
else
|
||||
# echo "contract $solfile could not be compiled "
|
||||
UNCOMPILABLE=$((UNCOMPILABLE + 1))
|
||||
fi
|
||||
# return 0
|
||||
}
|
||||
echo "Looking at $NSOURCES .sol files..."
|
||||
|
||||
WORKINGDIR=$PWD
|
||||
|
||||
# for solfile in $(find $DEV_DIR -name *.sol)
|
||||
for solfile in $(find $SYNTAXTESTS_DIR -name *.sol)
|
||||
do
|
||||
echo -n "."
|
||||
# create a temporary sub-directory
|
||||
FILETMP=$(mktemp -d -p $WORKINGDIR)
|
||||
cd $FILETMP
|
||||
|
||||
OUTPUT=$($SPLITSOURCES $solfile)
|
||||
if [ $? != 1 ]
|
||||
then
|
||||
# echo $OUTPUT
|
||||
NSOURCES=$((NSOURCES - 1))
|
||||
for i in $OUTPUT;
|
||||
do
|
||||
testImportExportEquivalence $i $OUTPUT
|
||||
NSOURCES=$((NSOURCES + 1))
|
||||
done
|
||||
|
||||
else
|
||||
testImportExportEquivalence $solfile
|
||||
fi
|
||||
|
||||
cd $WORKINGDIR
|
||||
# Delete temporary files
|
||||
rm -rf $FILETMP
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
if [ "$FAILED" = 0 ]
|
||||
then
|
||||
echo "SUCCESS: $TESTED syntaxTests passed, $FAILED failed, $UNCOMPILABLE could not be compiled ($NSOURCES sources total)."
|
||||
else
|
||||
echo "FAILURE: Out of $NSOURCES sources, $FAILED failed, ($UNCOMPILABLE could not be compiled)."
|
||||
exit 1
|
||||
fi
|
62
scripts/splitSources.py
Executable file
62
scripts/splitSources.py
Executable file
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python2
|
||||
#
|
||||
# This script reads a syntaxTest file and writes all
|
||||
# sources into their own files. If one source-name specifies subdirectories
|
||||
# those will be created too.
|
||||
|
||||
# Usage: scripts/splitSources.py pathToTestfile
|
||||
# as a result prints
|
||||
# - string of created files separated by whitespaces
|
||||
# - 'false' if the file only had one source
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
hasMultipleSources = False
|
||||
createdSources = []
|
||||
|
||||
def extractSourceName(line):
|
||||
if line.find("/") > -1:
|
||||
filePath = line[13: line.rindex("/")]
|
||||
# fileName = line[line.rindex("/")+1: line.find(" ====")]
|
||||
srcName = line[line.find(":")+2: line.find(" ====")]
|
||||
return filePath, srcName
|
||||
return False, line[line.find(":")+2 : line.find(" ====")]
|
||||
|
||||
# expects the first line of lines to be "==== Source: sourceName ===="
|
||||
# writes the following source into a file named sourceName
|
||||
def writeSourceToFile(lines):
|
||||
filePath, srcName = extractSourceName(lines[0])
|
||||
# print "sourceName is", srcName
|
||||
# print "filePath is", filePath
|
||||
if filePath != False:
|
||||
os.system("mkdir -p " + filePath)
|
||||
f = open(srcName, 'a+')
|
||||
createdSources.append(srcName)
|
||||
i = 0
|
||||
for idx, line in enumerate(lines[1:]):
|
||||
|
||||
# write to file
|
||||
if line[:12] != "==== Source:":
|
||||
f.write(line)
|
||||
|
||||
# recursive call if there is another source
|
||||
else:
|
||||
writeSourceToFile(lines[1+idx:])
|
||||
break
|
||||
|
||||
if __name__ == '__main__':
|
||||
filePath = sys.argv[1]
|
||||
# decide if file has multiple sources
|
||||
lines = open(filePath, 'rb').read().splitlines()
|
||||
if lines[0][:12] == "==== Source:":
|
||||
hasMultipleSources = True
|
||||
writeSourceToFile(lines)
|
||||
|
||||
if hasMultipleSources:
|
||||
srcString = ""
|
||||
for src in createdSources:
|
||||
srcString += src + ' '
|
||||
print srcString
|
||||
else:
|
||||
sys.exit(1)
|
@ -28,6 +28,7 @@
|
||||
#include <libsolidity/interface/Version.h>
|
||||
#include <libsolidity/parsing/Parser.h>
|
||||
#include <libsolidity/ast/ASTJsonConverter.h>
|
||||
#include <libsolidity/ast/ASTJsonImporter.h>
|
||||
#include <libsolidity/analysis/NameAndTypeResolver.h>
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
#include <libsolidity/interface/StandardCompiler.h>
|
||||
@ -120,6 +121,7 @@ static string const g_strEVMVersion = "evm-version";
|
||||
static string const g_strEwasm = "ewasm";
|
||||
static string const g_strGas = "gas";
|
||||
static string const g_strHelp = "help";
|
||||
static string const g_strImportAst = "import-ast";
|
||||
static string const g_strInputFile = "input-file";
|
||||
static string const g_strInterface = "interface";
|
||||
static string const g_strYul = "yul";
|
||||
@ -184,6 +186,7 @@ static string const g_argCompactJSON = g_strCompactJSON;
|
||||
static string const g_argErrorRecovery = g_strErrorRecovery;
|
||||
static string const g_argGas = g_strGas;
|
||||
static string const g_argHelp = g_strHelp;
|
||||
static string const g_argImportAst = g_strImportAst;
|
||||
static string const g_argInputFile = g_strInputFile;
|
||||
static string const g_argYul = g_strYul;
|
||||
static string const g_argIR = g_strIR;
|
||||
@ -623,6 +626,33 @@ bool CommandLineInterface::parseLibraryOption(string const& _input)
|
||||
return true;
|
||||
}
|
||||
|
||||
map<string, Json::Value> CommandLineInterface::parseAstFromInput()
|
||||
{
|
||||
map<string, Json::Value> sourceJsons;
|
||||
map<string, string> tmpSources;
|
||||
|
||||
for (auto const& srcPair: m_sourceCodes)
|
||||
{
|
||||
Json::Value ast;
|
||||
astAssert(jsonParseStrict(srcPair.second, ast), "Input file could not be parsed to JSON");
|
||||
astAssert(ast.isMember("sources"), "Invalid Format for import-JSON: Must have 'sources'-object");
|
||||
|
||||
for (auto& src: ast["sources"].getMemberNames())
|
||||
{
|
||||
std::string astKey = ast["sources"][src].isMember("ast") ? "ast" : "AST";
|
||||
|
||||
astAssert(ast["sources"][src].isMember(astKey), "astkey is not member");
|
||||
astAssert(ast["sources"][src][astKey]["nodeType"].asString() == "SourceUnit", "Top-level node should be a 'SourceUnit'");
|
||||
astAssert(sourceJsons.count(src) == 0, "All sources must have unique names");
|
||||
sourceJsons.emplace(src, move(ast["sources"][src][astKey]));
|
||||
tmpSources[src] = util::jsonCompactPrint(ast);
|
||||
}
|
||||
}
|
||||
|
||||
m_sourceCodes = std::move(tmpSources);
|
||||
return sourceJsons;
|
||||
}
|
||||
|
||||
void CommandLineInterface::createFile(string const& _fileName, string const& _data)
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
@ -722,6 +752,12 @@ Allowed options)",
|
||||
"Switch to Standard JSON input / output mode, ignoring all options. "
|
||||
"It reads from standard input and provides the result on the standard output."
|
||||
)
|
||||
(
|
||||
g_argImportAst.c_str(),
|
||||
"Import ASTs to be compiled, assumes input holds the AST in compact JSON format."
|
||||
" Supported Inputs is the output of the standard-json or the one produced by --combined-json ast,compact-format"
|
||||
)
|
||||
|
||||
(
|
||||
g_argAssemble.c_str(),
|
||||
"Switch to assembly mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is assembly."
|
||||
@ -1065,10 +1101,9 @@ bool CommandLineInterface::processInput()
|
||||
m_compiler->setMetadataHash(m_metadataHash);
|
||||
if (m_args.count(g_argInputFile))
|
||||
m_compiler->setRemappings(m_remappings);
|
||||
m_compiler->setSources(m_sourceCodes);
|
||||
|
||||
if (m_args.count(g_argLibraries))
|
||||
m_compiler->setLibraries(m_libraries);
|
||||
m_compiler->setParserErrorRecovery(m_args.count(g_argErrorRecovery));
|
||||
m_compiler->setEVMVersion(m_evmVersion);
|
||||
m_compiler->setRevertStringBehaviour(m_revertStrings);
|
||||
// TODO: Perhaps we should not compile unless requested
|
||||
@ -1082,6 +1117,32 @@ bool CommandLineInterface::processInput()
|
||||
settings.optimizeStackAllocation = settings.runYulOptimiser;
|
||||
m_compiler->setOptimiserSettings(settings);
|
||||
|
||||
if (m_args.count(g_argImportAst))
|
||||
{
|
||||
try
|
||||
{
|
||||
m_compiler->importASTs(parseAstFromInput());
|
||||
|
||||
if (!m_compiler->analyze())
|
||||
{
|
||||
for (auto const& error: m_compiler->errors())
|
||||
formatter->printErrorInformation(*error);
|
||||
astAssert(false, "Analysis of the AST failed");
|
||||
}
|
||||
}
|
||||
catch (Exception const& _exc)
|
||||
{
|
||||
serr() << string("Failed to import AST: ") << _exc.what() << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_compiler->setSources(m_sourceCodes);
|
||||
if (m_args.count(g_argErrorRecovery))
|
||||
m_compiler->setParserErrorRecovery(true);
|
||||
}
|
||||
|
||||
bool successful = m_compiler->compile();
|
||||
|
||||
for (auto const& error: m_compiler->errors())
|
||||
|
@ -80,6 +80,12 @@ private:
|
||||
/// It then tries to parse the contents and appends to m_libraries.
|
||||
bool parseLibraryOption(std::string const& _input);
|
||||
|
||||
/// Tries to read @ m_sourceCodes as a JSONs holding ASTs
|
||||
/// such that they can be imported into the compiler (importASTs())
|
||||
/// (produced by --combined-json ast,compact-format <file.sol>
|
||||
/// or standard-json output
|
||||
std::map<std::string, Json::Value> parseAstFromInput();
|
||||
|
||||
/// Create a file in the given directory
|
||||
/// @arg _fileName the name of the file
|
||||
/// @arg _data to be written
|
||||
|
@ -437,6 +437,19 @@ SOLTMPDIR=$(mktemp -d)
|
||||
fi
|
||||
)
|
||||
|
||||
printTask "Testing AST import..."
|
||||
SOLTMPDIR=$(mktemp -d)
|
||||
(
|
||||
cd "$SOLTMPDIR"
|
||||
$REPO_ROOT/scripts/ASTImportTest.sh
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
rm -rf "$SOLTMPDIR"
|
||||
exit 1
|
||||
fi
|
||||
)
|
||||
rm -rf "$SOLTMPDIR"
|
||||
|
||||
printTask "Testing soljson via the fuzzer..."
|
||||
SOLTMPDIR=$(mktemp -d)
|
||||
(
|
||||
|
@ -282,7 +282,7 @@
|
||||
"name": "this",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [],
|
||||
"referencedDeclaration": 68,
|
||||
"referencedDeclaration": -28,
|
||||
"src": "217:4:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
|
@ -446,7 +446,7 @@
|
||||
[
|
||||
null
|
||||
],
|
||||
"referencedDeclaration": 68,
|
||||
"referencedDeclaration": -28,
|
||||
"type": "contract C",
|
||||
"value": "this"
|
||||
},
|
||||
|
@ -124,6 +124,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences": [],
|
||||
"id": 3,
|
||||
"nodeType": "InlineAssembly",
|
||||
|
@ -89,6 +89,7 @@
|
||||
{
|
||||
"attributes":
|
||||
{
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences":
|
||||
[
|
||||
null
|
||||
|
@ -111,6 +111,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences": [],
|
||||
"id": 3,
|
||||
"nodeType": "InlineAssembly",
|
||||
|
@ -89,6 +89,7 @@
|
||||
{
|
||||
"attributes":
|
||||
{
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences":
|
||||
[
|
||||
null
|
||||
|
@ -61,6 +61,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences": [],
|
||||
"id": 3,
|
||||
"nodeType": "InlineAssembly",
|
||||
|
@ -89,6 +89,7 @@
|
||||
{
|
||||
"attributes":
|
||||
{
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences":
|
||||
[
|
||||
null
|
||||
|
@ -124,6 +124,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences": [],
|
||||
"id": 3,
|
||||
"nodeType": "InlineAssembly",
|
||||
|
@ -89,6 +89,7 @@
|
||||
{
|
||||
"attributes":
|
||||
{
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences":
|
||||
[
|
||||
null
|
||||
|
@ -176,6 +176,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences":
|
||||
[
|
||||
{
|
||||
|
@ -166,6 +166,7 @@
|
||||
{
|
||||
"attributes":
|
||||
{
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences":
|
||||
[
|
||||
{
|
||||
|
@ -65,6 +65,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences": [],
|
||||
"id": 3,
|
||||
"nodeType": "InlineAssembly",
|
||||
|
@ -89,6 +89,7 @@
|
||||
{
|
||||
"attributes":
|
||||
{
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences":
|
||||
[
|
||||
null
|
||||
|
@ -157,6 +157,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences": [],
|
||||
"id": 3,
|
||||
"nodeType": "InlineAssembly",
|
||||
|
@ -89,6 +89,7 @@
|
||||
{
|
||||
"attributes":
|
||||
{
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences":
|
||||
[
|
||||
null
|
||||
|
@ -107,6 +107,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences":
|
||||
[
|
||||
{
|
||||
|
@ -135,6 +135,7 @@
|
||||
{
|
||||
"attributes":
|
||||
{
|
||||
"evmVersion": %EVMVERSION%,
|
||||
"externalReferences":
|
||||
[
|
||||
{
|
||||
|
@ -15,6 +15,7 @@
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <test/libsolidity/ASTJSONTest.h>
|
||||
#include <test/Options.h>
|
||||
#include <libsolutil/AnsiColorized.h>
|
||||
@ -38,6 +39,30 @@ using namespace std;
|
||||
namespace fs = boost::filesystem;
|
||||
using namespace boost::unit_test;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void replaceVersionWithTag(string& _input)
|
||||
{
|
||||
boost::algorithm::replace_all(
|
||||
_input,
|
||||
"\"" + solidity::test::Options::get().evmVersion().name() + "\"",
|
||||
"%EVMVERSION%"
|
||||
);
|
||||
}
|
||||
|
||||
void replaceTagWithVersion(string& _input)
|
||||
{
|
||||
boost::algorithm::replace_all(
|
||||
_input,
|
||||
"%EVMVERSION%",
|
||||
"\"" + solidity::test::Options::get().evmVersion().name() + "\""
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
ASTJSONTest::ASTJSONTest(string const& _filename)
|
||||
{
|
||||
if (!boost::algorithm::ends_with(_filename, ".sol"))
|
||||
@ -126,6 +151,8 @@ TestCase::TestResult ASTJSONTest::run(ostream& _stream, string const& _linePrefi
|
||||
|
||||
bool resultsMatch = true;
|
||||
|
||||
replaceTagWithVersion(m_expectation);
|
||||
|
||||
if (m_expectation != m_result)
|
||||
{
|
||||
string nextIndentLevel = _linePrefix + " ";
|
||||
@ -158,6 +185,8 @@ TestCase::TestResult ASTJSONTest::run(ostream& _stream, string const& _linePrefi
|
||||
m_resultLegacy += "\n";
|
||||
}
|
||||
|
||||
replaceTagWithVersion(m_expectationLegacy);
|
||||
|
||||
if (m_expectationLegacy != m_resultLegacy)
|
||||
{
|
||||
string nextIndentLevel = _linePrefix + " ";
|
||||
@ -202,12 +231,21 @@ void ASTJSONTest::printUpdatedExpectations(std::ostream&, std::string const&) co
|
||||
ofstream file(m_astFilename.c_str());
|
||||
if (!file) BOOST_THROW_EXCEPTION(runtime_error("Cannot write AST expectation to \"" + m_astFilename + "\"."));
|
||||
file.exceptions(ios::badbit);
|
||||
file << m_result;
|
||||
|
||||
string replacedResult = m_result;
|
||||
replaceVersionWithTag(replacedResult);
|
||||
|
||||
file << replacedResult;
|
||||
file.flush();
|
||||
file.close();
|
||||
|
||||
file.open(m_legacyAstFilename.c_str());
|
||||
if (!file) BOOST_THROW_EXCEPTION(runtime_error("Cannot write legacy AST expectation to \"" + m_legacyAstFilename + "\"."));
|
||||
file << m_resultLegacy;
|
||||
|
||||
string replacedResultLegacy = m_resultLegacy;
|
||||
replaceVersionWithTag(replacedResultLegacy);
|
||||
|
||||
file << replacedResultLegacy;
|
||||
file.flush();
|
||||
file.close();
|
||||
}
|
||||
|
@ -145,7 +145,8 @@ BOOST_AUTO_TEST_CASE(type_identifier_escaping)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(type_identifiers)
|
||||
{
|
||||
ASTNode::resetID();
|
||||
int64_t id = 0;
|
||||
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("uint128")->identifier(), "t_uint128");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("int128")->identifier(), "t_int128");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("address")->identifier(), "t_address");
|
||||
@ -157,7 +158,7 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
|
||||
BOOST_CHECK_EQUAL(RationalNumberType(rational(2 * 200, 2 * 77)).identifier(), "t_rational_200_by_77");
|
||||
BOOST_CHECK_EQUAL(RationalNumberType(rational(-2 * 200, 2 * 77)).identifier(), "t_rational_minus_200_by_77");
|
||||
BOOST_CHECK_EQUAL(
|
||||
StringLiteralType(Literal(SourceLocation{}, Token::StringLiteral, make_shared<string>("abc - def"))).identifier(),
|
||||
StringLiteralType(Literal(++id, SourceLocation{}, Token::StringLiteral, make_shared<string>("abc - def"))).identifier(),
|
||||
"t_stringliteral_196a9142ee0d40e274a6482393c762b16dd8315713207365e1e13d8d85b74fc4"
|
||||
);
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("byte")->identifier(), "t_bytes1");
|
||||
@ -178,14 +179,14 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
|
||||
TypePointer multiArray = TypeProvider::array(DataLocation::Storage, stringArray);
|
||||
BOOST_CHECK_EQUAL(multiArray->identifier(), "t_array$_t_array$_t_string_storage_$20_storage_$dyn_storage_ptr");
|
||||
|
||||
ContractDefinition c(SourceLocation{}, make_shared<string>("MyContract$"), {}, {}, {}, ContractKind::Contract);
|
||||
ContractDefinition c(++id, SourceLocation{}, make_shared<string>("MyContract$"), {}, {}, {}, ContractKind::Contract);
|
||||
BOOST_CHECK_EQUAL(c.type()->identifier(), "t_type$_t_contract$_MyContract$$$_$2_$");
|
||||
BOOST_CHECK_EQUAL(ContractType(c, true).identifier(), "t_super$_MyContract$$$_$2");
|
||||
|
||||
StructDefinition s({}, make_shared<string>("Struct"), {});
|
||||
StructDefinition s(++id, {}, make_shared<string>("Struct"), {});
|
||||
BOOST_CHECK_EQUAL(s.type()->identifier(), "t_type$_t_struct$_Struct_$3_storage_ptr_$");
|
||||
|
||||
EnumDefinition e({}, make_shared<string>("Enum"), {});
|
||||
EnumDefinition e(++id, {}, make_shared<string>("Enum"), {});
|
||||
BOOST_CHECK_EQUAL(e.type()->identifier(), "t_type$_t_enum$_Enum_$4_$");
|
||||
|
||||
TupleType t({e.type(), s.type(), stringArray, nullptr});
|
||||
@ -203,11 +204,11 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
|
||||
|
||||
// TypeType is tested with contract
|
||||
|
||||
auto emptyParams = make_shared<ParameterList>(SourceLocation(), std::vector<ASTPointer<VariableDeclaration>>());
|
||||
ModifierDefinition mod(SourceLocation{}, make_shared<string>("modif"), {}, emptyParams, {}, {}, {});
|
||||
auto emptyParams = make_shared<ParameterList>(++id, SourceLocation(), std::vector<ASTPointer<VariableDeclaration>>());
|
||||
ModifierDefinition mod(++id, SourceLocation{}, make_shared<string>("modif"), {}, emptyParams, {}, {}, {});
|
||||
BOOST_CHECK_EQUAL(ModifierType(mod).identifier(), "t_modifier$__$");
|
||||
|
||||
SourceUnit su({}, {});
|
||||
SourceUnit su(++id, {}, {});
|
||||
BOOST_CHECK_EQUAL(ModuleType(su).identifier(), "t_module_7");
|
||||
BOOST_CHECK_EQUAL(MagicType(MagicType::Kind::Block).identifier(), "t_magic_block");
|
||||
BOOST_CHECK_EQUAL(MagicType(MagicType::Kind::Message).identifier(), "t_magic_message");
|
||||
|
Loading…
Reference in New Issue
Block a user