diff --git a/Changelog.md b/Changelog.md
index 21e0e91f5..cd71d617f 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -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:
diff --git a/liblangutil/CMakeLists.txt b/liblangutil/CMakeLists.txt
index 63c9de39d..6a7663d46 100644
--- a/liblangutil/CMakeLists.txt
+++ b/liblangutil/CMakeLists.txt
@@ -16,6 +16,7 @@ set(sources
SemVerHandler.cpp
SemVerHandler.h
SourceLocation.h
+ SourceLocation.cpp
SourceReferenceExtractor.cpp
SourceReferenceExtractor.h
SourceReferenceFormatter.cpp
diff --git a/liblangutil/Exceptions.h b/liblangutil/Exceptions.h
index de72eba37..575847ed9 100644
--- a/liblangutil/Exceptions.h
+++ b/liblangutil/Exceptions.h
@@ -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:
diff --git a/liblangutil/SourceLocation.cpp b/liblangutil/SourceLocation.cpp
new file mode 100644
index 000000000..8c531c625
--- /dev/null
+++ b/liblangutil/SourceLocation.cpp
@@ -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 .
+*/
+
+#include
+
+#include
+#include
+
+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 pos;
+
+ boost::algorithm::split(pos, _input, boost::is_any_of(":"));
+
+ astAssert(
+ pos.size() == 3 &&
+ _maxIndex >= static_cast(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 source = std::make_shared("", _sourceName);
+
+ return SourceLocation{start, end, source};
+}
+
+}
diff --git a/liblangutil/SourceLocation.h b/liblangutil/SourceLocation.h
index d86dd206a..46808f8e0 100644
--- a/liblangutil/SourceLocation.h
+++ b/liblangutil/SourceLocation.h
@@ -23,13 +23,12 @@
#pragma once
#include
-#include // defines noexcept macro for MSVC
#include
+
#include
+
#include
#include
-#include
-#include
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 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;
-}
-
}
diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt
index 87eb0e9b7..242f26c35 100644
--- a/libsolidity/CMakeLists.txt
+++ b/libsolidity/CMakeLists.txt
@@ -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
diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp
index 2a4ce374b..a0764edba 100644
--- a/libsolidity/analysis/GlobalContext.cpp
+++ b/libsolidity/analysis/GlobalContext.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> constructMagicVariables()
{
static auto const magicVarDecl = [](string const& _name, Type const* _type) {
- return make_shared(_name, _type);
+ return make_shared(magicVariableToID(_name), _name, _type);
};
return {
@@ -97,7 +131,7 @@ vector GlobalContext::declarations() const
MagicVariableDeclaration const* GlobalContext::currentThis() const
{
if (!m_thisPointer[m_currentContract])
- m_thisPointer[m_currentContract] = make_shared("this", TypeProvider::contract(*m_currentContract));
+ m_thisPointer[m_currentContract] = make_shared(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("super", TypeProvider::contract(*m_currentContract, true));
+ m_superPointer[m_currentContract] = make_shared(magicVariableToID("super"), "super", TypeProvider::contract(*m_currentContract, true));
return m_superPointer[m_currentContract].get();
}
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index 9f8e1471d..74b042852 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -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)
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index fc0b3a5be..a603a93fb 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -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> c
class SourceUnit: public ASTNode
{
public:
- SourceUnit(SourceLocation const& _location, std::vector> const& _nodes):
- ASTNode(_location), m_nodes(_nodes) {}
+ SourceUnit(int64_t _id, SourceLocation const& _location, std::vector> 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 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 const& _tokens,
std::vector 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;
ImportDirective(
+ int64_t _id,
SourceLocation const& _location,
ASTPointer const& _path,
ASTPointer 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 const& _name,
ASTPointer 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 const& _baseName,
std::unique_ptr>> _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 const& _libraryName,
ASTPointer 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 const& _name,
std::vector> 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 const& _name,
std::vector> 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 const& _name):
- Declaration(_location, _name) {}
+ EnumValue(int64_t _id, SourceLocation const& _location, ASTPointer 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> 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 const& _name,
Visibility _visibility,
@@ -610,7 +618,7 @@ public:
ASTPointer const& _overrides = nullptr,
ASTPointer const& _returnParameters = ASTPointer()
):
- 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> 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 const& _name,
Visibility _visibility,
@@ -678,7 +688,7 @@ public:
ASTPointer const& _returnParameters,
ASTPointer 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 const& _type,
ASTPointer const& _name,
ASTPointer _value,
@@ -759,7 +770,7 @@ public:
ASTPointer 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 const& _name,
ASTPointer const& _documentation,
@@ -855,7 +867,7 @@ public:
ASTPointer const& _overrides,
ASTPointer 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 const& _name,
std::unique_ptr>> _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 const& _name,
ASTPointer const& _documentation,
ASTPointer 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(_name)), m_type(_type) {}
+ MagicVariableDeclaration(int _id, ASTString const& _name, Type const* _type):
+ Declaration(_id, SourceLocation(), std::make_shared(_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 = {}
- ): 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 const& _namePath):
- TypeName(_location), m_namePath(_namePath) {}
+ UserDefinedTypeName(int64_t _id, SourceLocation const& _location, std::vector 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 const& _parameterTypes,
ASTPointer 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 const& _keyType,
ASTPointer 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 const& _baseType,
ASTPointer 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 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 const& _docString,
yul::Dialect const& _dialect,
std::shared_ptr 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 const& _docString,
std::vector> 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 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 const& _docString,
ASTPointer const& _condition,
ASTPointer const& _trueBody,
ASTPointer 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 const& _errorName,
ASTPointer const& _parameters,
ASTPointer 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 const& _docString,
ASTPointer const& _externalCall,
std::vector> 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 const& _docString
- ): Statement(_location, _docString) {}
+ ): Statement(_id, _location, _docString) {}
};
class WhileStatement: public BreakableStatement
{
public:
WhileStatement(
+ int64_t _id,
SourceLocation const& _location,
ASTPointer const& _docString,
ASTPointer const& _condition,
ASTPointer 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 const& _docString,
ASTPointer const& _initExpression,
@@ -1351,7 +1379,7 @@ public:
ASTPointer const& _loopExpression,
ASTPointer 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 const& _docString):
- Statement(_location, _docString) {}
+ explicit Continue(int64_t _id, SourceLocation const& _location, ASTPointer 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 const& _docString):
- Statement(_location, _docString) {}
+ explicit Break(int64_t _id, SourceLocation const& _location, ASTPointer 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 const& _docString,
ASTPointer _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 const& _docString):
- Statement(_location, _docString) {}
+ explicit Throw(int64_t _id, SourceLocation const& _location, ASTPointer 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 const& _docString,
ASTPointer 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 const& _docString,
std::vector> const& _variables,
ASTPointer 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 const& _docString,
ASTPointer _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 const& _condition,
ASTPointer const& _trueExpression,
ASTPointer 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 const& _leftHandSide,
Token _assignmentOperator,
ASTPointer 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> 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 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 const& _left,
Token _operator,
ASTPointer 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 const& _expression,
std::vector> const& _arguments,
std::vector> 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 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,
ASTPointer 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 const& _base,
ASTPointer 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 const& _base,
ASTPointer const& _start,
ASTPointer 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 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 const& _type
):
- PrimaryExpression(_location),
+ PrimaryExpression(_id, _location),
m_type(_type)
{
}
@@ -1874,12 +1918,13 @@ public:
Year = static_cast(Token::SubYear)
};
Literal(
+ int64_t _id,
SourceLocation const& _location,
Token _token,
ASTPointer 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;
diff --git a/libsolidity/ast/ASTJsonImporter.cpp b/libsolidity/ast/ASTJsonImporter.cpp
new file mode 100644
index 000000000..6b1005777
--- /dev/null
+++ b/libsolidity/ast/ASTJsonImporter.cpp
@@ -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 .
+*/
+/**
+ * @author julius
+ * @date 2019
+ *Component that imports an AST from json format to the internal format
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+using namespace std;
+
+namespace solidity::frontend
+{
+
+using SourceLocation = langutil::SourceLocation;
+
+template
+ASTPointer ASTJsonImporter::nullOrCast(Json::Value const& _json)
+{
+ if (_json.isNull())
+ return nullptr;
+ else
+ return dynamic_pointer_cast(convertJsonToASTNode(_json));
+}
+
+
+// ============ public ===========================
+
+map> ASTJsonImporter::jsonToSourceUnit(map const& _sourceList)
+{
+ m_sourceList = _sourceList;
+ for (auto const& src: _sourceList)
+ m_sourceLocations.emplace_back(make_shared(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
+ASTPointer 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(
+ id,
+ createSourceLocation(_node),
+ forward(_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
+ASTPointer ASTJsonImporter::convertJsonToASTNode(Json::Value const& _node)
+{
+ ASTPointer ret = dynamic_pointer_cast(convertJsonToASTNode(_node));
+ astAssert(ret, "cast of converted json-node must not be nullptr");
+ return ret;
+}
+
+
+ASTPointer 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 ASTJsonImporter::createSourceUnit(Json::Value const& _node, string const& _srcName)
+{
+ vector> nodes;
+ for (auto& child: member(_node, "nodes"))
+ nodes.emplace_back(convertJsonToASTNode(child));
+ ASTPointer tmp = createASTNode(_node, nodes);
+ tmp->annotation().path = _srcName;
+ return tmp;
+}
+
+ASTPointer ASTJsonImporter::createPragmaDirective(Json::Value const& _node)
+{
+ vector tokens;
+ vector literals;
+ for (auto const& lit: member(_node, "literals"))
+ {
+ string l = lit.asString();
+ literals.push_back(l);
+ tokens.push_back(scanSingleToken(l));
+ }
+ return createASTNode(_node, tokens, literals);
+}
+
+ASTPointer ASTJsonImporter::createImportDirective(Json::Value const& _node)
+{
+ ASTPointer unitAlias = memberAsASTString(_node, "unitAlias");
+ ASTPointer 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(tuple["local"].asString()),
+ createSourceLocation(tuple["foreign"])}
+ );
+ }
+ ASTPointer tmp = createASTNode(
+ _node,
+ path,
+ unitAlias,
+ move(symbolAliases)
+ );
+
+ astAssert(_node["absolutePath"].isString(), "Expected 'absolutePath' to be a string!");
+
+ tmp->annotation().absolutePath = _node["absolutePath"].asString();
+ return tmp;
+}
+
+ASTPointer ASTJsonImporter::createContractDefinition(Json::Value const& _node)
+{
+ astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
+
+ std::vector> baseContracts;
+
+ for (auto& base: _node["baseContracts"])
+ baseContracts.push_back(createInheritanceSpecifier(base));
+
+ std::vector> subNodes;
+
+ for (auto& subnode: _node["nodes"])
+ subNodes.push_back(convertJsonToASTNode(subnode));
+
+ return createASTNode(
+ _node,
+ make_shared(_node["name"].asString()),
+ nullOrASTString(_node, "documentation"),
+ baseContracts,
+ subNodes,
+ contractKind(_node),
+ memberAsBool(_node, "abstract")
+ );
+}
+
+ASTPointer ASTJsonImporter::createInheritanceSpecifier(Json::Value const& _node)
+{
+ std::vector> arguments;
+ for (auto& arg: member(_node, "arguments"))
+ arguments.push_back(convertJsonToASTNode(arg));
+ return createASTNode(
+ _node,
+ createUserDefinedTypeName(member(_node, "baseName")),
+ member(_node, "arguments").isNull() ? nullptr : make_unique>>(arguments)
+ );
+}
+
+ASTPointer ASTJsonImporter::createUsingForDirective(Json::Value const& _node)
+{
+ return createASTNode(
+ _node,
+ createUserDefinedTypeName(member(_node, "libraryName")),
+ _node["typeName"].isNull() ? nullptr : convertJsonToASTNode(_node["typeName"])
+ );
+}
+
+ASTPointer ASTJsonImporter::createStructDefinition(Json::Value const& _node)
+{
+ std::vector> members;
+ for (auto& member: _node["members"])
+ members.push_back(createVariableDeclaration(member));
+ return createASTNode(
+ _node,
+ memberAsASTString(_node, "name"),
+ members
+ );
+}
+
+ASTPointer ASTJsonImporter::createEnumDefinition(Json::Value const& _node)
+{
+ std::vector> members;
+ for (auto& member: _node["members"])
+ members.push_back(createEnumValue(member));
+ return createASTNode(
+ _node,
+ memberAsASTString(_node, "name"),
+ members
+ );
+}
+
+ASTPointer ASTJsonImporter::createEnumValue(Json::Value const& _node)
+{
+ return createASTNode(
+ _node,
+ memberAsASTString(_node, "name")
+ );
+}
+
+ASTPointer ASTJsonImporter::createParameterList(Json::Value const& _node)
+{
+ std::vector> parameters;
+ for (auto& param: _node["parameters"])
+ parameters.push_back(createVariableDeclaration(param));
+ return createASTNode(
+ _node,
+ parameters
+ );
+}
+
+ASTPointer ASTJsonImporter::createOverrideSpecifier(Json::Value const& _node)
+{
+ std::vector> overrides;
+
+ for (auto& param: _node["overrides"])
+ overrides.push_back(createUserDefinedTypeName(param));
+
+ return createASTNode(
+ _node,
+ overrides
+ );
+}
+
+ASTPointer 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> modifiers;
+ for (auto& mod: member(_node, "modifiers"))
+ modifiers.push_back(createModifierInvocation(mod));
+ return createASTNode(
+ _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 ASTJsonImporter::createVariableDeclaration(Json::Value const& _node)
+{
+ astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
+
+ return createASTNode(
+ _node,
+ nullOrCast(member(_node, "typeName")),
+ make_shared(member(_node, "name").asString()),
+ nullOrCast(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 ASTJsonImporter::createModifierDefinition(Json::Value const& _node)
+{
+ return createASTNode(
+ _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 ASTJsonImporter::createModifierInvocation(Json::Value const& _node)
+{
+ std::vector> arguments;
+ for (auto& arg: member(_node, "arguments"))
+ arguments.push_back(convertJsonToASTNode(arg));
+ return createASTNode(
+ _node,
+ createIdentifier(member(_node, "modifierName")),
+ member(_node, "arguments").isNull() ? nullptr : make_unique>>(arguments)
+ );
+}
+
+ASTPointer ASTJsonImporter::createEventDefinition(Json::Value const& _node)
+{
+ return createASTNode(
+ _node,
+ memberAsASTString(_node, "name"),
+ nullOrASTString(_node, "documentation"),
+ createParameterList(member(_node, "parameters")),
+ memberAsBool(_node, "anonymous")
+ );
+}
+
+ASTPointer 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 mutability = {};
+ if (_node.isMember("stateMutability"))
+ mutability = stateMutability(_node);
+
+ return createASTNode(_node, elem, mutability);
+}
+
+ASTPointer ASTJsonImporter::createUserDefinedTypeName(Json::Value const& _node)
+{
+ astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
+
+ vector namePath;
+ vector 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(
+ _node,
+ namePath
+ );
+}
+
+ASTPointer ASTJsonImporter::createFunctionTypeName(Json::Value const& _node)
+{
+ return createASTNode(
+ _node,
+ createParameterList(member(_node, "parameterTypes")),
+ createParameterList(member(_node, "returnParameterTypes")),
+ visibility(_node),
+ stateMutability(_node)
+ );
+}
+
+ASTPointer ASTJsonImporter::createMapping(Json::Value const& _node)
+{
+ return createASTNode(
+ _node,
+ createElementaryTypeName(member(_node, "keyType")),
+ convertJsonToASTNode(member(_node, "valueType"))
+ );
+}
+
+ASTPointer ASTJsonImporter::createArrayTypeName(Json::Value const& _node)
+{
+ return createASTNode(
+ _node,
+ convertJsonToASTNode(member(_node, "baseType")),
+ nullOrCast(member(_node, "length"))
+ );
+}
+
+ASTPointer 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 operations = make_shared(AsmJsonImporter(m_currentSourceName).createBlock(member(_node, "AST")));
+ return createASTNode(
+ _node,
+ nullOrASTString(_node, "documentation"),
+ dialect,
+ operations
+ );
+}
+
+ASTPointer ASTJsonImporter::createBlock(Json::Value const& _node)
+{
+ std::vector> statements;
+ for (auto& stat: member(_node, "statements"))
+ statements.push_back(convertJsonToASTNode(stat));
+ return createASTNode(
+ _node,
+ nullOrASTString(_node, "documentation"),
+ statements
+ );
+}
+
+ASTPointer ASTJsonImporter::createPlaceholderStatement(Json::Value const& _node)
+{
+ return createASTNode(
+ _node,
+ nullOrASTString(_node, "documentation")
+ );
+}
+
+ASTPointer ASTJsonImporter::createIfStatement(Json::Value const& _node)
+{
+ return createASTNode