Browse Source

Moving all Interface and Documentation functionality to own class

- Creating the Interface Handler class which will take care of the
  parsing of Natspec comments and of interfacing with and outputing to
  JSON files.

- Will also handle the ABI interface creation
cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
4613214098
  1. 90
      libsolidity/CompilerStack.cpp
  2. 26
      libsolidity/CompilerStack.h
  3. 88
      libsolidity/InterfaceHandler.cpp
  4. 74
      libsolidity/InterfaceHandler.h
  5. 5
      solc/main.cpp
  6. 2
      test/solidityJSONInterfaceTest.cpp
  7. 4
      test/solidityNatspecJSON.cpp

90
libsolidity/CompilerStack.cpp

@ -27,8 +27,7 @@
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/CompilerStack.h>
#include <jsonrpc/json/json.h>
#include <libsolidity/InterfaceHandler.h>
using namespace std;
@ -37,6 +36,8 @@ namespace dev
namespace solidity
{
CompilerStack::CompilerStack():m_interfaceHandler(make_shared<InterfaceHandler>()){}
void CompilerStack::setSource(string const& _sourceCode)
{
reset();
@ -83,84 +84,33 @@ void CompilerStack::streamAssembly(ostream& _outStream)
m_compiler->streamAssembly(_outStream);
}
string const& CompilerStack::getInterface()
{
Json::StyledWriter writer;
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
if (m_interface.empty())
{
Json::Value methods(Json::arrayValue);
vector<FunctionDefinition const*> exportedFunctions = m_contractASTNode->getInterfaceFunctions();
for (FunctionDefinition const* f: exportedFunctions)
{
Json::Value method;
Json::Value inputs(Json::arrayValue);
Json::Value outputs(Json::arrayValue);
auto streamVariables = [](vector<ASTPointer<VariableDeclaration>> const& _vars)
{
Json::Value params(Json::arrayValue);
for (ASTPointer<VariableDeclaration> const& var: _vars)
{
Json::Value input;
input["name"] = var->getName();
input["type"] = var->getType()->toString();
params.append(input);
}
return params;
};
method["name"] = f->getName();
method["inputs"] = streamVariables(f->getParameters());
method["outputs"] = streamVariables(f->getReturnParameters());
methods.append(method);
}
m_interface = writer.write(methods);
}
return m_interface;
}
string const& CompilerStack::getUserDocumentation()
std::string const* CompilerStack::getJsonDocumentation(enum documentation_type _type)
{
Json::StyledWriter writer;
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
if (m_userDocumentation.empty())
auto createOrReturnDoc = [&, this](std::unique_ptr<string>& _doc)
{
Json::Value doc;
Json::Value methods(Json::objectValue);
for (FunctionDefinition const* f: m_contractASTNode->getInterfaceFunctions())
if(!_doc)
{
Json::Value user;
auto strPtr = f->getDocumentation();
if (strPtr)
{
user["notice"] = Json::Value(*strPtr);
methods[f->getName()] = user;
}
_doc = m_interfaceHandler->getDocumentation(m_contractASTNode, _type);
}
doc["methods"] = methods;
m_userDocumentation = writer.write(doc);
}
return m_userDocumentation;
}
string const& CompilerStack::getDevDocumentation()
{
Json::StyledWriter writer;
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
};
if (m_devDocumentation.empty())
switch (_type)
{
// TODO
case NATSPEC_USER:
createOrReturnDoc(m_userDocumentation);
return m_userDocumentation.get();
case NATSPEC_DEV:
createOrReturnDoc(m_devDocumentation);
return m_devDocumentation.get();
case ABI_INTERFACE:
createOrReturnDoc(m_interface);
return m_interface.get();
}
return m_devDocumentation;
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal error"));
return nullptr;
}
bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize)

26
libsolidity/CompilerStack.h

@ -35,6 +35,14 @@ class Scanner;
class ContractDefinition;
class Compiler;
class GlobalContext;
class InterfaceHandler;
enum documentation_type : unsigned short
{
NATSPEC_USER = 1,
NATSPEC_DEV,
ABI_INTERFACE
};
/**
* Easy to use and self-contained Solidity compiler with as few header dependencies as possible.
@ -44,7 +52,7 @@ class GlobalContext;
class CompilerStack
{
public:
CompilerStack() {}
CompilerStack();
void reset() { *this = CompilerStack(); }
void setSource(std::string const& _sourceCode);
void parse();
@ -62,12 +70,11 @@ public:
/// Returns a string representing the contract interface in JSON.
/// Prerequisite: Successful call to parse or compile.
std::string const& getInterface();
/// Returns a string representing the contract's user documentation in JSON.
/// Prerequisite: Successful call to parse or compile.
std::string const& getUserDocumentation();
/// Returns a string representing the contract's developer documentation in JSON.
/// Returns a string representing the contract's documentation in JSON.
/// Prerequisite: Successful call to parse or compile.
std::string const& getDevDocumentation();
/// @param type The type of the documentation to get.
/// Can be one of 3 types defined at @c documentation_type
std::string const* getJsonDocumentation(enum documentation_type type);
/// Returns the previously used scanner, useful for counting lines during error reporting.
Scanner const& getScanner() const { return *m_scanner; }
@ -82,10 +89,11 @@ private:
std::shared_ptr<GlobalContext> m_globalContext;
std::shared_ptr<ContractDefinition> m_contractASTNode;
bool m_parseSuccessful;
std::string m_interface;
std::string m_userDocumentation;
std::string m_devDocumentation;
std::unique_ptr<std::string> m_interface;
std::unique_ptr<std::string> m_userDocumentation;
std::unique_ptr<std::string> m_devDocumentation;
std::shared_ptr<Compiler> m_compiler;
std::shared_ptr<InterfaceHandler> m_interfaceHandler;
bytes m_bytecode;
};

88
libsolidity/InterfaceHandler.cpp

@ -0,0 +1,88 @@
#include <libsolidity/InterfaceHandler.h>
#include <libsolidity/AST.h>
#include <libsolidity/CompilerStack.h>
namespace dev {
namespace solidity {
InterfaceHandler::InterfaceHandler()
{
}
std::unique_ptr<std::string> InterfaceHandler::getDocumentation(std::shared_ptr<ContractDefinition> _contractDef,
enum documentation_type _type)
{
switch(_type)
{
case NATSPEC_USER:
return getUserDocumentation(_contractDef);
case NATSPEC_DEV:
return getDevDocumentation(_contractDef);
case ABI_INTERFACE:
return getABIInterface(_contractDef);
}
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal error"));
return nullptr;
}
std::unique_ptr<std::string> InterfaceHandler::getABIInterface(std::shared_ptr<ContractDefinition> _contractDef)
{
Json::Value methods(Json::arrayValue);
std::vector<FunctionDefinition const*> exportedFunctions = _contractDef->getInterfaceFunctions();
for (FunctionDefinition const* f: exportedFunctions)
{
Json::Value method;
Json::Value inputs(Json::arrayValue);
Json::Value outputs(Json::arrayValue);
auto streamVariables = [](std::vector<ASTPointer<VariableDeclaration>> const& _vars)
{
Json::Value params(Json::arrayValue);
for (ASTPointer<VariableDeclaration> const& var: _vars)
{
Json::Value input;
input["name"] = var->getName();
input["type"] = var->getType()->toString();
params.append(input);
}
return params;
};
method["name"] = f->getName();
method["inputs"] = streamVariables(f->getParameters());
method["outputs"] = streamVariables(f->getReturnParameters());
methods.append(method);
}
return std::unique_ptr<std::string>(new std::string(m_writer.write(methods)));
}
std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(std::shared_ptr<ContractDefinition> _contractDef)
{
Json::Value doc;
Json::Value methods(Json::objectValue);
for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions())
{
Json::Value user;
auto strPtr = f->getDocumentation();
if (strPtr)
{
user["notice"] = Json::Value(*strPtr);
methods[f->getName()] = user;
}
}
doc["methods"] = methods;
return std::unique_ptr<std::string>(new std::string(m_writer.write(doc)));
}
std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(std::shared_ptr<ContractDefinition> _contractDef)
{
//TODO
return nullptr;
}
} //solidity NS
} // dev NS

74
libsolidity/InterfaceHandler.h

@ -0,0 +1,74 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum 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.
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Lefteris <lefteris@ethdev.com>
* @date 2014
* Takes the parsed AST and produces the Natspec
* documentation and the ABI interface
* https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format
*
* Can generally deal with JSON files
*/
#pragma once
#include <string>
#include <memory>
#include <jsonrpc/json/json.h>
namespace dev {
namespace solidity {
// Forward declarations
class ContractDefinition;
enum documentation_type: unsigned short;
class InterfaceHandler
{
public:
InterfaceHandler();
/// Get the given type of documentation
/// @param _contractDef The contract definition
/// @param _type The type of the documentation. Can be one of the
/// types provided by @c documentation_type
/// @return A unique pointer contained string with the json
/// representation of provided type
std::unique_ptr<std::string> getDocumentation(std::shared_ptr<ContractDefinition> _contractDef,
enum documentation_type _type);
/// Get the ABI Interface of the contract
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// representation of the contract's ABI Interface
std::unique_ptr<std::string> getABIInterface(std::shared_ptr<ContractDefinition> _contractDef);
/// Get the User documentation of the contract
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// representation of the contract's user documentation
std::unique_ptr<std::string> getUserDocumentation(std::shared_ptr<ContractDefinition> _contractDef);
/// Get the Developer's documentation of the contract
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// representation of the contract's developer documentation
std::unique_ptr<std::string> getDevDocumentation(std::shared_ptr<ContractDefinition> _contractDef);
private:
Json::StyledWriter m_writer;
};
} //solidity NS
} // dev NS

5
solc/main.cpp

@ -135,8 +135,9 @@ int main(int argc, char** argv)
cout << "Opcodes:" << endl;
cout << eth::disassemble(compiler.getBytecode()) << endl;
cout << "Binary: " << toHex(compiler.getBytecode()) << endl;
cout << "Interface specification: " << compiler.getInterface() << endl;
cout << "Natspec user documentation: " << compiler.getUserDocumentation() << endl;
cout << "Interface specification: " << compiler.getJsonDocumentation(ABI_INTERFACE) << endl;
cout << "Natspec user documentation: " << compiler.getJsonDocumentation(NATSPEC_USER) << endl;
cout << "Natspec developer documentation: " << compiler.getJsonDocumentation(NATSPEC_DEV) << endl;
return 0;
}

2
test/solidityJSONInterfaceTest.cpp

@ -50,7 +50,7 @@ public:
msg += *extra;
BOOST_FAIL(msg);
}
std::string generatedInterfaceString = m_compilerStack.getInterface();
std::string generatedInterfaceString = *m_compilerStack.getJsonDocumentation(ABI_INTERFACE);
Json::Value generatedInterface;
m_reader.parse(generatedInterfaceString, generatedInterface);
Json::Value expectedInterface;

4
test/solidityNatspecJSON.cpp

@ -55,9 +55,9 @@ public:
}
if (_userDocumentation)
generatedDocumentationString = m_compilerStack.getUserDocumentation();
generatedDocumentationString = *m_compilerStack.getJsonDocumentation(NATSPEC_USER);
else
generatedDocumentationString = m_compilerStack.getDevDocumentation();
generatedDocumentationString = *m_compilerStack.getJsonDocumentation(NATSPEC_DEV);
Json::Value generatedDocumentation;
m_reader.parse(generatedDocumentationString, generatedDocumentation);
Json::Value expectedDocumentation;

Loading…
Cancel
Save