WIP-Friday

This commit is contained in:
Christian Parpart 2020-06-05 16:31:35 +02:00
parent 8df6b50a78
commit cca832e56a
11 changed files with 486 additions and 11 deletions

View File

@ -53,6 +53,8 @@ set(sources
ast/ASTJsonImporter.h
ast/ASTVisitor.h
ast/ExperimentalFeatures.h
ast/JsonInterfaceImporter.cpp
ast/JsonInterfaceImporter.h
ast/Types.cpp
ast/Types.h
ast/TypeProvider.cpp

View File

@ -231,6 +231,12 @@ vector<pair<util::FixedHash<4>, FunctionTypePointer>> const& ContractDefinition:
});
}
TypePointer ImportedContractDefinition::type() const
{
return {};
// TODO: Think about whether this type needs to be specified or returning {} is sufficient.
}
TypePointer ContractDefinition::type() const
{
return TypeProvider::typeType(TypeProvider::contract(*this));

View File

@ -454,7 +454,12 @@ protected:
/// @}
/**
* TODO: docstring
* Definition of an imported interface declaration.
*
* This is not the actually imported interface but the reference to it.
* It will be resolved by CompilerStack to add any missing interface definitions
* by looking for any ImportedContractDefinition in the ASTs and append them - embeded into
* SourceUnit's - to its collection of sources.
*/
class ImportedContractDefinition: public Declaration // TODO(needed?), public StructurallyDocumented
{
@ -471,6 +476,7 @@ public:
void accept(ASTVisitor& _visitor) override;
void accept(ASTConstVisitor& _visitor) const override;
TypePointer type() const override;
ASTPointer<ASTString> const& path() const noexcept { return m_path; }

View File

@ -50,7 +50,23 @@ public:
ASTPointer<ContractDefinition> jsonToContract(Json::Value const& _sourceList);
ASTPointer<ContractDefinition> jsonToInterface(
int64_t _nodeId,
langutil::SourceLocation const& _location,
std::string const& _name,
Json::Value const& _source
);
private:
ASTPointer<ASTNode> createInterfaceMember(
langutil::SourceLocation const& _location,
Json::Value const& _node
);
ASTPointer<ParameterList> createInterfaceParameters(
langutil::SourceLocation const& _location,
Json::Value const& _array
);
// =========== general creation functions ==============

View File

@ -0,0 +1,198 @@
#include <libsolidity/ast/JsonInterfaceImporter.h>
using namespace std;
namespace solidity::frontend
{
ASTPointer<SourceUnit> JsonInterfaceImporter::importInterfaceAsSourceUnit(
langutil::SourceLocation const& _location,
std::optional<std::string> const& _license,
std::string const& _name,
Json::Value const& _source
)
{
auto interface = importInterface(_location, _name, _source);
return make_shared<SourceUnit>(
m_nextId++,
_location,
_license,
vector<ASTPointer<ASTNode>>{ interface }
);
}
ASTPointer<ASTNode> JsonInterfaceImporter::importInterface(
langutil::SourceLocation const& _location,
string const& _name,
Json::Value const& _source
)
{
// TODO: contractInheritanceDefinition
// TODO: "anything in ContractDefintion that returns a vector of FunctionDefinitons needs to be refactored to return a base class of FunctionDefiniton such that the imported interface can also return something that is not directly a FunctionDefinition"
vector<ASTPointer<ASTNode>> members;
for (auto const& jsonMember: _source)
if (auto member = createMember(_location, jsonMember); member != nullptr)
members.push_back(member);
return make_shared<ContractDefinition>(
m_nextId++,
_location,
make_shared<ASTString>(_name),
ASTPointer<StructuredDocumentation>{},
vector<ASTPointer<InheritanceSpecifier>>{}, // TODO: see contractInheritanceDefinition
members,
ContractKind::Interface,
false
);
}
ASTPointer<ASTNode> JsonInterfaceImporter::createMember(
langutil::SourceLocation const& _location,
Json::Value const& _node
)
{
if (_node["type"] == "function")
return createFunction(_location, _node);
else if (_node["type"] == "event")
return createEvent(_location, _node);
else
{
// TODO: report error of invalid type. Use m_errorReporter for that.
return nullptr;
}
}
ASTPointer<ASTNode> JsonInterfaceImporter::createFunction(
langutil::SourceLocation const& _location,
Json::Value const& _node
)
{
auto const mutability = stateMutability(_node["stateMutability"]);
auto const name = _node["name"].asString();
auto const inputs = createParameters(_location, false, _node["inputs"]);
auto const outputs = createParameters(_location, false, _node["outputs"]);
auto const kind = Token::Function;
return createASTNode<FunctionDefinition>(
_location,
make_shared<ASTString>(name),
Visibility::Default,
mutability,
kind,
true, // interface functions are always virtual
nullptr, // overrides
nullptr, // documentation
inputs,
vector<ASTPointer<ModifierInvocation>>{},
outputs,
nullptr // no body
);
}
ASTPointer<ASTNode> JsonInterfaceImporter::createEvent(
langutil::SourceLocation const& _location,
Json::Value const& _node
)
{
bool const anonymous = _node["anonymous"].asBool();
auto inputs = createParameters(_location, true, _node["inputs"]);
auto const name = _node["name"].asString();
return createASTNode<EventDefinition>(
_location,
make_shared<ASTString>(name),
ASTPointer<StructuredDocumentation>{},
inputs,
anonymous
);
}
ASTPointer<ParameterList> JsonInterfaceImporter::createParameters(
langutil::SourceLocation const& _location,
bool _indexed,
Json::Value const& _node
)
{
vector<ASTPointer<VariableDeclaration>> parameters;
for (auto& param: _node)
parameters.push_back(createParameter(_location, _indexed, param));
return createASTNode<ParameterList>(_location, parameters);
}
ASTPointer<VariableDeclaration> JsonInterfaceImporter::createParameter(
langutil::SourceLocation const& _location,
bool _indexed,
Json::Value const& _node
)
{
// "indexed" (only when event)
auto const parameterName = _node["name"].asString();
auto const typeName = _node["type"].asString();
ASTPointer<TypeName> type = {}; // TODO (get me from typeName)
return createASTNode<VariableDeclaration>(
_location,
type,
make_shared<ASTString>(parameterName),
ASTPointer<Expression>{}, // value
Visibility::Default,
ASTPointer<StructuredDocumentation>{}, // documentation
false, // isStateVariable
_indexed,
VariableDeclaration::Mutability::Mutable,
ASTPointer<OverrideSpecifier>{}
);
// TODO
// return createASTNode<VariableDeclaration>(
// _location,
// nullOrCast<TypeName>(member(_node, "typeName")),
// make_shared<ASTString>(member(_node, "name").asString()),
// nullOrCast<Expression>(member(_node, "value")),
// visibility(_node),
// _node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
// memberAsBool(_node, "stateVariable"),
// _node.isMember("indexed") ? memberAsBool(_node, "indexed") : false,
// mutability,
// _node["overrides"].isNull() ? nullptr : createOverrideSpecifier(member(_node, "overrides")),
// location(_node)
// );
}
StateMutability JsonInterfaceImporter::stateMutability(Json::Value const& _node) const
{
// TODO: see that we can avoid duplication with ASTJsonImporter
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");
}
Json::Value JsonInterfaceImporter::member(Json::Value const& _node, string const& _name) const
{
// TODO: see that we can avoid duplication with ASTJsonImporter
astAssert(_node.isMember(_name), "Node '" + _node["nodeType"].asString() + "' (id " + _node["id"].asString() + ") is missing field '" + _name + "'.");
return _node[_name];
}
template <typename T, typename... Args>
ASTPointer<T> JsonInterfaceImporter::createASTNode(
langutil::SourceLocation const& _location,
Args&&... _args
)
{
return make_shared<T>(m_nextId++, _location, forward<Args>(_args)...);
}
} // end namespace

View File

@ -0,0 +1,93 @@
/*
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/>.
*/
#pragma once
#include <libsolidity/ast/AST.h>
#include <liblangutil/SourceLocation.h>
#include <json/json.h>
#include <optional>
#include <string>
namespace solidity::frontend
{
class JsonInterfaceImporter
{
public:
JsonInterfaceImporter(int64_t _nextId):
m_nextId{ _nextId }
{}
ASTPointer<SourceUnit> importInterfaceAsSourceUnit(
langutil::SourceLocation const& _location,
std::optional<std::string> const& _licenseString,
std::string const& _name,
Json::Value const& _source
);
ASTPointer<ASTNode> importInterface(
langutil::SourceLocation const& _location,
std::string const& _name,
Json::Value const& _source
);
private:
ASTPointer<ASTNode> createMember(
langutil::SourceLocation const& _location,
Json::Value const& _node
);
ASTPointer<ASTNode> createFunction(
langutil::SourceLocation const& _location,
Json::Value const& _node
);
ASTPointer<ASTNode> createEvent(
langutil::SourceLocation const& _location,
Json::Value const& _node
);
ASTPointer<ParameterList> createParameters(
langutil::SourceLocation const& _location,
bool _indexed,
Json::Value const& _node
);
ASTPointer<VariableDeclaration> createParameter(
langutil::SourceLocation const& _location,
bool _indexed,
Json::Value const& _node
);
private: // helper functions (TODO: that could be shared with ASTJsonImporter)
StateMutability stateMutability(Json::Value const& _node) const;
Json::Value member(Json::Value const& _node, std::string const& _name) const;
template <typename T, typename... Args>
ASTPointer<T> createASTNode(
langutil::SourceLocation const& _location,
Args&&... _args
);
private:
int64_t m_nextId;
};
} // end namespace

View File

@ -41,6 +41,7 @@
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/ast/ASTJsonImporter.h>
#include <libsolidity/ast/JsonInterfaceImporter.h>
#include <libsolidity/codegen/Compiler.h>
#include <libsolidity/formal/ModelChecker.h>
#include <libsolidity/interface/ABI.h>
@ -276,7 +277,9 @@ bool CompilerStack::parse()
void CompilerStack::loadMissingInterfaces(int64_t _baseNodeID)
{
JsonInterfaceImporter interfaceImporter{_baseNodeID};
vector<ASTPointer<SourceUnit>> importedSources;
for (auto const& sourcePair: m_sources)
{
ASTPointer<SourceUnit> const& source = sourcePair.second.ast;
@ -297,15 +300,17 @@ void CompilerStack::loadMissingInterfaces(int64_t _baseNodeID)
string const& jsonString = result.responseOrErrorMessage;
Json::Value json;
util::jsonParseStrict(jsonString, json, nullptr);
ASTPointer<ContractDefinition> jsonContract = ASTJsonImporter{m_evmVersion}.jsonToContract(json);
auto importedSource = make_shared<SourceUnit>(
_baseNodeID++,
SourceLocation{},
source->licenseString(),
vector<ASTPointer<ASTNode>>{ jsonContract }
);
importedSources.push_back(importedSource);
ASTPointer<SourceUnit> importedSource =
interfaceImporter.importInterfaceAsSourceUnit(
importedContract->location(),
source->licenseString(),
importedContract->name(),
json
);
if (importedSource != nullptr)
importedSources.push_back(importedSource);
}
else
{

View File

@ -292,7 +292,7 @@ std::pair<ContractKind, bool> Parser::parseContractKind()
return std::make_pair(kind, abstract);
}
ASTPointer<ContractDefinition> Parser::parseInterfaceDefinition()
ASTPointer<ASTNode> Parser::parseInterfaceDefinition()
{
// interfaceDefinition
// : 'interface' identifier 'from' StringLiteralFragment

View File

@ -91,7 +91,7 @@ private:
std::pair<ContractKind, bool> parseContractKind();
ASTPointer<ContractDefinition> parseContractDefinition();
std::vector<ASTPointer<InheritanceSpecifier>> parseContractInheritanceList();
ASTPointer<ContractDefinition> parseInterfaceDefinition();
ASTPointer<ASTNode> parseInterfaceDefinition();
std::vector<ASTPointer<ASTNode>> parseContractBody();
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
Visibility parseVisibilitySpecifier();

View File

@ -0,0 +1,7 @@
interface I from "interface_imported_I.json";
contract C {
function f() public pure {
}
}
// ----

View File

@ -0,0 +1,142 @@
[
{
"state_mutability": "view",
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"type": "function"
},
{
"state_mutability": "view",
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "supply",
"type": "uint256"
}
],
"type": "function"
},
{
"state_mutability": "payable",
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"type": "function"
},
{
"state_mutability": "view",
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "balance",
"type": "uint256"
}
],
"type": "function"
},
{
"state_mutability": "payable",
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_from",
"type": "address"
},
{
"indexed": true,
"name": "_to",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
}
]