From 7971f5e83d3aaf8169cfc53abbabd1411b924027 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 28 Jan 2015 08:50:53 +0100 Subject: [PATCH 1/2] JSON compiler. --- libsolidity/ASTJsonConverter.cpp | 17 ++++- libsolidity/ASTJsonConverter.h | 5 +- libsolidity/Compiler.h | 4 +- libsolidity/CompilerContext.h | 4 +- libsolidity/CompilerStack.cpp | 7 +- libsolidity/CompilerStack.h | 3 +- solc/CMakeLists.txt | 7 ++ solc/jsonCompiler.cpp | 124 +++++++++++++++++++++++++++++++ 8 files changed, 161 insertions(+), 10 deletions(-) create mode 100644 solc/jsonCompiler.cpp diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ASTJsonConverter.cpp index c30e4ca2b..be89de924 100644 --- a/libsolidity/ASTJsonConverter.cpp +++ b/libsolidity/ASTJsonConverter.cpp @@ -78,10 +78,16 @@ ASTJsonConverter::ASTJsonConverter(ASTNode const& _ast): m_ast(&_ast) void ASTJsonConverter::print(ostream& _stream) { - m_ast->accept(*this); + process(); _stream << m_astJson; } +Json::Value const& ASTJsonConverter::json() +{ + process(); + return m_astJson; +} + bool ASTJsonConverter::visit(ImportDirective const& _node) { addJsonNode("Import", { make_pair("file", _node.getIdentifier())}); @@ -460,9 +466,16 @@ void ASTJsonConverter::endVisit(Literal const&) { } +void ASTJsonConverter::process() +{ + if (!processed) + m_ast->accept(*this); + processed = true; +} + string ASTJsonConverter::getType(Expression const& _expression) { - return (_expression.getType()) ? _expression.getType()->toString() : "Unknown"; + return (_expression.getType()) ? _expression.getType()->toString() : "Unknown"; } } diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ASTJsonConverter.h index 30a92e66c..56502ab3c 100644 --- a/libsolidity/ASTJsonConverter.h +++ b/libsolidity/ASTJsonConverter.h @@ -44,6 +44,7 @@ public: ASTJsonConverter(ASTNode const& _ast); /// Output the json representation of the AST to _stream. void print(std::ostream& _stream); + Json::Value const& json(); bool visit(ImportDirective const& _node) override; bool visit(ContractDefinition const& _node) override; @@ -114,6 +115,7 @@ public: void endVisit(Literal const&) override; private: + void process(); void addKeyValue(Json::Value& _obj, std::string const& _key, std::string const& _val); void addJsonNode(std::string const& _nodeName, std::initializer_list> _list, @@ -123,8 +125,9 @@ private: { solAssert(!m_jsonNodePtrs.empty(), "Uneven json nodes stack. Internal error."); m_jsonNodePtrs.pop(); - }; + } + bool processed = false; Json::Value m_astJson; std::stack m_jsonNodePtrs; std::string m_source; diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index d476ec684..c3c3b9dcc 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -43,9 +43,9 @@ public: bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} /// @arg _sourceCodes is the map of input files to source code strings /// @arg _inJsonFromat shows whether the out should be in Json format - void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const + Json::Value streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const { - m_context.streamAssembly(_stream, _sourceCodes, _inJsonFormat); + return m_context.streamAssembly(_stream, _sourceCodes, _inJsonFormat); } /// @returns Assembly items of the normal compiler context eth::AssemblyItems const& getAssemblyItems() const { return m_context.getAssembly().getItems(); } diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 34a3f97cd..0ca6369dd 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -123,9 +123,9 @@ public: eth::Assembly const& getAssembly() const { return m_asm; } /// @arg _sourceCodes is the map of input files to source code strings /// @arg _inJsonFormat shows whether the out should be in Json format - void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const + Json::Value streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const { - m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat); + return m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat); } bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); } diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index d6274e2c7..a2a178317 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -184,13 +184,16 @@ dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const return dev::sha3(getRuntimeBytecode(_contractName)); } -void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const +Json::Value CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const { Contract const& contract = getContract(_contractName); if (contract.compiler) - contract.compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat); + return contract.compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat); else + { _outStream << "Contract not fully implemented" << endl; + return Json::Value(); + } } string const& CompilerStack::getInterface(string const& _contractName) const diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 2e7c217d5..6f90a846e 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -104,7 +105,7 @@ public: /// @arg _sourceCodes is the map of input files to source code strings /// @arg _inJsonFromat shows whether the out should be in Json format /// Prerequisite: Successful compilation. - void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const; + Json::Value streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const; /// Returns a string representing the contract interface in JSON. /// Prerequisite: Successful call to parse or compile. diff --git a/solc/CMakeLists.txt b/solc/CMakeLists.txt index d3a39dbc8..177823963 100644 --- a/solc/CMakeLists.txt +++ b/solc/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_policy(SET CMP0015 NEW) set(CMAKE_AUTOMOC OFF) aux_source_directory(. SRC_LIST) +list(REMOVE_ITEM SRC_LIST "./jsonCompiler.cpp") include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ..) @@ -18,3 +19,9 @@ target_link_libraries(${EXECUTABLE} solidity) install( TARGETS ${EXECUTABLE} DESTINATION bin ) +if (ETH_STATIC) + add_library(soljson STATIC jsonCompiler.cpp ${HEADERS}) +else() + add_library(soljson SHARED jsonCompiler.cpp ${HEADERS}) +endif() +target_link_libraries(soljson solidity) diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp new file mode 100644 index 000000000..7475483c3 --- /dev/null +++ b/solc/jsonCompiler.cpp @@ -0,0 +1,124 @@ +/* + 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 . +*/ +/** + * @author Christian + * @date 2014 + * JSON interface for the solidity compiler to be used from Javascript. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace dev; +using namespace solidity; + +string formatError(Exception const& _exception, string const& _name, CompilerStack const& _compiler) +{ + ostringstream errorOutput; + SourceReferenceFormatter::printExceptionInformation(errorOutput, _exception, _name, _compiler); + + Json::Value output(Json::objectValue); + output["error"] = errorOutput.str(); + return Json::FastWriter().write(output); +} + +string compile(string _input, bool optimize) +{ + StringMap sources; + sources[""] = _input; + + Json::Value output(Json::objectValue); + CompilerStack compiler; + try + { + compiler.compile(_input, optimize); + } + catch (ParserError const& exception) + { + return formatError(exception, "Parser error", compiler); + } + catch (DeclarationError const& exception) + { + return formatError(exception, "Declaration error", compiler); + } + catch (TypeError const& exception) + { + return formatError(exception, "Type error", compiler); + } + catch (CompilerError const& exception) + { + return formatError(exception, "Compiler error", compiler); + } + catch (InternalCompilerError const& exception) + { + return formatError(exception, "Internal compiler error", compiler); + } + catch (Exception const& exception) + { + output["error"] = "Exception during compilation: " + boost::diagnostic_information(exception); + return Json::FastWriter().write(output); + } + catch (...) + { + output["error"] = "Unknown exception during compilation."; + return Json::FastWriter().write(output); + } + + output["contracts"] = Json::Value(Json::objectValue); + for (string const& contractName: compiler.getContractNames()) + { + Json::Value contractData(Json::objectValue); + contractData["solidity_interface"] = compiler.getSolidityInterface(contractName); + contractData["interface"] = compiler.getInterface(contractName); + contractData["bytecode"] = toHex(compiler.getBytecode(contractName)); + contractData["opcodes"] = eth::disassemble(compiler.getBytecode(contractName)); + ostringstream unused; + contractData["assembly"] = compiler.streamAssembly(unused, contractName, sources); + output["contracts"][contractName] = contractData; + } + + output["sources"] = Json::Value(Json::objectValue); + output["sources"][""] = Json::Value(Json::objectValue); + output["sources"][""]["AST"] = ASTJsonConverter(compiler.getAST("")).json(); + + return Json::FastWriter().write(output); +} + +static string outputBuffer; + +extern "C" +{ +extern char const* compileJSON(char const* _input, bool optimize) +{ + outputBuffer = compile(_input, optimize); + return outputBuffer.c_str(); +} +} From 31903df90998dd0b8af54b07470d5c97b40a62f4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 22 Apr 2015 11:33:02 +0200 Subject: [PATCH 2/2] Style fixes. --- solc/jsonCompiler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp index 7475483c3..3079df69f 100644 --- a/solc/jsonCompiler.cpp +++ b/solc/jsonCompiler.cpp @@ -50,7 +50,7 @@ string formatError(Exception const& _exception, string const& _name, CompilerSta return Json::FastWriter().write(output); } -string compile(string _input, bool optimize) +string compile(string _input, bool _optimize) { StringMap sources; sources[""] = _input; @@ -59,7 +59,7 @@ string compile(string _input, bool optimize) CompilerStack compiler; try { - compiler.compile(_input, optimize); + compiler.compile(_input, _optimize); } catch (ParserError const& exception) { @@ -116,9 +116,9 @@ static string outputBuffer; extern "C" { -extern char const* compileJSON(char const* _input, bool optimize) +extern char const* compileJSON(char const* _input, bool _optimize) { - outputBuffer = compile(_input, optimize); + outputBuffer = compile(_input, _optimize); return outputBuffer.c_str(); } }