Browse Source

Project refactor. Introduce the Serpent library.

cl-refactor
Gav Wood 11 years ago
parent
commit
25183afd7c
  1. 18
      CMakeLists.txt
  2. 2
      alethzero/MainWin.h
  3. 8
      eth/CommonJS.h
  4. 2
      eth/EthStubServer.cpp
  5. 4
      eth/main.cpp
  6. 6
      exp/main.cpp
  7. 10
      libethcore/BlockInfo.cpp
  8. 4
      libethcore/BlockInfo.h
  9. 2
      libethcore/CMakeLists.txt
  10. 1
      libethcore/CommonEth.cpp
  11. 4
      libethcore/CommonEth.h
  12. 0
      libethcore/CryptoHeaders.h
  13. 8
      libethcore/Dagger.cpp
  14. 1
      libethcore/Dagger.h
  15. 2
      libethcore/Exceptions.h
  16. 4
      libethcore/FileSystem.cpp
  17. 0
      libethcore/FileSystem.h
  18. 2
      libethcore/MemoryDB.cpp
  19. 8
      libethcore/MemoryDB.h
  20. 2
      libethcore/OverlayDB.cpp
  21. 4
      libethcore/OverlayDB.h
  22. 5
      libethcore/SHA3.cpp
  23. 61
      libethcore/SHA3.h
  24. 0
      libethcore/TrieCommon.cpp
  25. 4
      libethcore/TrieCommon.h
  26. 5
      libethcore/TrieDB.cpp
  27. 5
      libethcore/TrieDB.h
  28. 10
      libethcore/UPnP.cpp
  29. 0
      libethcore/UPnP.h
  30. 51
      libethential/CMakeLists.txt
  31. 2
      libethential/Common.cpp
  32. 0
      libethential/Common.h
  33. 0
      libethential/CommonData.cpp
  34. 0
      libethential/CommonData.h
  35. 0
      libethential/CommonIO.cpp
  36. 0
      libethential/CommonIO.h
  37. 0
      libethential/Exceptions.h
  38. 25
      libethential/FixedHash.cpp
  39. 28
      libethential/FixedHash.h
  40. 0
      libethential/Log.cpp
  41. 0
      libethential/Log.h
  42. 0
      libethential/RLP.cpp
  43. 8
      libethential/RLP.h
  44. 2
      libethential/vector_ref.h
  45. 5
      libethereum/AddressState.h
  46. 6
      libethereum/BlockChain.cpp
  47. 2
      libethereum/BlockChain.h
  48. 1
      libethereum/CMakeLists.txt
  49. 2
      libethereum/Client.cpp
  50. 2
      libethereum/Client.h
  51. 2
      libethereum/Defaults.cpp
  52. 2
      libethereum/Defaults.h
  53. 2
      libethereum/Executive.h
  54. 4
      libethereum/PeerNetwork.h
  55. 4
      libethereum/PeerServer.cpp
  56. 2
      libethereum/PeerSession.cpp
  57. 2
      libethereum/PeerSession.h
  58. 2
      libethereum/State.cpp
  59. 6
      libethereum/State.h
  60. 4
      libethereum/Transaction.cpp
  61. 3
      libethereum/Transaction.h
  62. 2
      libethereum/TransactionQueue.cpp
  63. 2
      libethereum/TransactionQueue.h
  64. 3
      libevm/CMakeLists.txt
  65. 2
      libevm/ExtVMFace.h
  66. 2
      libevm/FeeStructure.h
  67. 5
      libevm/VM.h
  68. 51
      libevmface/CMakeLists.txt
  69. 2
      libevmface/Instruction.cpp
  70. 4
      libevmface/Instruction.h
  71. 2
      liblll/Assembly.cpp
  72. 5
      liblll/Assembly.h
  73. 11
      liblll/CMakeLists.txt
  74. 4
      liblll/CodeFragment.cpp
  75. 4
      liblll/CodeFragment.h
  76. 2
      liblll/Compiler.h
  77. 2
      liblll/Parser.h
  78. 4
      libqethereum/QEthereum.cpp
  79. 2
      libqethereum/QEthereum.h
  80. 10
      libserpent/CMakeLists.txt
  81. 98
      libserpent/bignum.cpp
  82. 30
      libserpent/bignum.h
  83. 407
      libserpent/compiler.cpp
  84. 43
      libserpent/compiler.h
  85. 11
      libserpent/example.cpp
  86. 23
      libserpent/funcs.cpp
  87. 29
      libserpent/funcs.h
  88. 70
      libserpent/lllparser.cpp
  89. 13
      libserpent/lllparser.h
  90. 91
      libserpent/opcodes.h
  91. 387
      libserpent/parser.cpp
  92. 13
      libserpent/parser.h
  93. 466
      libserpent/rewriter.cpp
  94. 13
      libserpent/rewriter.h
  95. 111
      libserpent/tokenize.cpp
  96. 14
      libserpent/tokenize.h
  97. 256
      libserpent/util.cpp
  98. 106
      libserpent/util.h
  99. 4
      lllc/CMakeLists.txt
  100. 6
      lllc/main.cpp

18
CMakeLists.txt

@ -5,11 +5,8 @@ set(CMAKE_AUTOMOC ON)
cmake_policy(SET CMP0015 NEW)
# Default HEADLESS to 0.
set(HEADLESS CACHE BOOL 0)
#if ("x${HEADLESS}" STREQUAL "x")
# set(HEADLESS 0)
#endif ()
set(LANGUAGES CACHE BOOL 0)
if ("x${PARANOIA}" STREQUAL "x")
if ("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")
@ -35,6 +32,10 @@ if (VMTRACE)
add_definitions(-DETH_VMTRACE)
endif ()
if (LANGUAGES)
add_definitions(-DETH_LANGUAGES)
endif ()
# Default TARGET_PLATFORM to "linux".
set(TARGET_PLATFORM CACHE STRING "linux")
if ("x${TARGET_PLATFORM}" STREQUAL "x")
@ -271,16 +272,18 @@ endif()
# Generate header file containing useful build information
add_custom_target(BuildInfo.h ALL COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/BuildInfo.sh ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BUILD_TYPE} ${ETH_BUILD_PLATFORM})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
link_directories(/usr/local/lib)
include_directories(/usr/local/include)
endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
add_subdirectory(libethential)
add_subdirectory(libevmface)
add_subdirectory(liblll)
add_subdirectory(libserpent)
if (NOT LANGUAGES)
add_subdirectory(secp256k1)
add_subdirectory(libethsupport)
add_subdirectory(libethcore)
add_subdirectory(liblll)
add_subdirectory(libevm)
add_subdirectory(libethereum)
add_subdirectory(test)
@ -298,6 +301,7 @@ if (NOT HEADLESS)
add_subdirectory(alethzero)
add_subdirectory(walleth)
endif ()
endif ()
enable_testing()
add_test(NAME alltests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testeth)

2
alethzero/MainWin.h

@ -26,7 +26,7 @@
#include <QtCore/QAbstractListModel>
#include <QtCore/QMutex>
#include <QtWidgets/QMainWindow>
#include <libethsupport/RLP.h>
#include <libethential/RLP.h>
#include <libethcore/CommonEth.h>
#include <libethereum/State.h>
#include <libqethereum/QEthereum.h>

8
eth/CommonJS.h

@ -23,10 +23,10 @@
#pragma once
#include <string>
#include <libethsupport/Common.h>
#include <libethsupport/CommonIO.h>
#include <libethsupport/CommonData.h>
#include <libethsupport/FixedHash.h>
#include <libethential/Common.h>
#include <libethential/CommonIO.h>
#include <libethential/CommonData.h>
#include <libethential/FixedHash.h>
#include <libethcore/CommonEth.h>
namespace eth

2
eth/EthStubServer.cpp

@ -22,7 +22,7 @@
#if ETH_JSONRPC
#include "EthStubServer.h"
#include <libethcore/Instruction.h>
#include <libevmface/Instruction.h>
#include <liblll/Compiler.h>
#include <libethereum/Client.h>
#include "CommonJS.h"

4
eth/main.cpp

@ -26,8 +26,8 @@
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libethsupport/FileSystem.h>
#include <libethcore/Instruction.h>
#include <libethcore/FileSystem.h>
#include <libevmface/Instruction.h>
#include <libethereum/Defaults.h>
#include <libethereum/Client.h>
#include <libethereum/PeerNetwork.h>

6
exp/main.cpp

@ -20,9 +20,9 @@
* Ethereum client.
*/
#include <libethsupport/Log.h>
#include <libethsupport/Common.h>
#include <libethsupport/CommonData.h>
#include <libethential/Log.h>
#include <libethential/Common.h>
#include <libethential/CommonData.h>
#include "BuildInfo.h"
using namespace std;
using namespace eth;

10
libethcore/BlockInfo.cpp

@ -19,9 +19,11 @@
* @date 2014
*/
#include <libethsupport/Common.h>
#include <libethsupport/RLP.h>
#include <libethsupport/TrieDB.h>
#if !ETH_LANGUAGES
#include <libethential/Common.h>
#include <libethential/RLP.h>
#include <libethcore/TrieDB.h>
#include "Dagger.h"
#include "Exceptions.h"
#include "BlockInfo.h"
@ -189,3 +191,5 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const
throw InvalidNumber();
}
}
#endif

4
libethcore/BlockInfo.h

@ -21,8 +21,8 @@
#pragma once
#include <libethsupport/Common.h>
#include <libethsupport/RLP.h>
#include <libethential/Common.h>
#include <libethential/RLP.h>
#include "CommonEth.h"
namespace eth

2
libethcore/CMakeLists.txt

@ -21,7 +21,7 @@ include_directories(..)
include_directories(${MINIUPNPC_ID})
include_directories(${LEVELDB_ID})
target_link_libraries(${EXECUTABLE} ethsupport)
target_link_libraries(${EXECUTABLE} ethential)
target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS})
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})

1
libethcore/CommonEth.cpp

@ -22,6 +22,7 @@
#include "CommonEth.h"
#include <random>
#include <secp256k1/secp256k1.h>
#include <libethcore/SHA3.h>
#include "Exceptions.h"
using namespace std;
using namespace eth;

4
libethcore/CommonEth.h

@ -23,8 +23,8 @@
#pragma once
#include <libethsupport/Common.h>
#include <libethsupport/FixedHash.h>
#include <libethential/Common.h>
#include <libethential/FixedHash.h>
namespace eth
{

0
libethsupport/CryptoHeaders.h → libethcore/CryptoHeaders.h

8
libethcore/Dagger.cpp

@ -19,12 +19,14 @@
* @date 2014
*/
#if !ETH_LANGUAGES
#include <boost/detail/endian.hpp>
#include <chrono>
#include <array>
#include <random>
#include <libethsupport/CryptoHeaders.h>
#include <libethsupport/Common.h>
#include <libethcore/CryptoHeaders.h>
#include <libethential/Common.h>
#include "Dagger.h"
using namespace std;
using namespace std::chrono;
@ -179,3 +181,5 @@ h256 Dagger::eval(h256 const& _root, u256 const& _nonce)
#endif
}
#endif

1
libethcore/Dagger.h

@ -23,6 +23,7 @@
#pragma once
#include <libethcore/SHA3.h>
#include "CommonEth.h"
#define FAKE_DAGGER 1

2
libethcore/Exceptions.h

@ -1,6 +1,6 @@
#pragma once
#include <libethsupport/Exceptions.h>
#include <libethential/Exceptions.h>
namespace eth
{

4
libethsupport/FileSystem.cpp → libethcore/FileSystem.cpp

@ -22,8 +22,8 @@
*/
#include "FileSystem.h"
#include "Common.h"
#include "Log.h"
#include <libethential/Common.h>
#include <libethential/Log.h>
#ifdef _WIN32
#include <shlobj.h>

0
libethsupport/FileSystem.h → libethcore/FileSystem.h

2
libethsupport/MemoryDB.cpp → libethcore/MemoryDB.cpp

@ -19,7 +19,7 @@
* @date 2014
*/
#include "Common.h"
#include <libethential/Common.h>
#include "MemoryDB.h"
using namespace std;
using namespace eth;

8
libethsupport/MemoryDB.h → libethcore/MemoryDB.h

@ -22,10 +22,10 @@
#pragma once
#include <map>
#include "Common.h"
#include "FixedHash.h"
#include "RLP.h"
#include "Log.h"
#include <libethential/Common.h>
#include <libethential/FixedHash.h>
#include <libethential/Log.h>
#include <libethential/RLP.h>
namespace eth
{

2
libethsupport/OverlayDB.cpp → libethcore/OverlayDB.cpp

@ -19,7 +19,7 @@
* @date 2014
*/
#include "Common.h"
#include <libethential/Common.h>
#include "OverlayDB.h"
using namespace std;
using namespace eth;

4
libethsupport/OverlayDB.h → libethcore/OverlayDB.h

@ -22,9 +22,9 @@
#pragma once
#include <memory>
#include "Common.h"
#include <libethential/Common.h>
#include <libethential/Log.h>
#include "MemoryDB.h"
#include "Log.h"
namespace ldb = leveldb;
namespace eth

5
libethsupport/FixedHash.cpp → libethcore/SHA3.cpp

@ -14,12 +14,12 @@
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file FixedHash.cpp
/** @file SHA3.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "FixedHash.h"
#include "SHA3.h"
#include "CryptoHeaders.h"
using namespace std;
@ -65,3 +65,4 @@ h256 eth::sha3(bytesConstRef _input)
sha3(_input, bytesRef(&ret[0], 32));
return ret;
}

61
libethcore/SHA3.h

@ -0,0 +1,61 @@
/*
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/>.
*/
/** @file FixedHash.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* The FixedHash fixed-size "hash" container type.
*/
#pragma once
#include <string>
#include <libethential/FixedHash.h>
#include <libethential/vector_ref.h>
namespace eth
{
// SHA-3 convenience routines.
/// Calculate SHA3-256 hash of the given input and load it into the given output.
void sha3(bytesConstRef _input, bytesRef _output);
/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data.
std::string sha3(std::string const& _input, bool _isNibbles);
/// Calculate SHA3-256 hash of the given input, returning as a byte array.
bytes sha3Bytes(bytesConstRef _input);
/// Calculate SHA3-256 hash of the given input (presented as a binary string), returning as a byte array.
inline bytes sha3Bytes(std::string const& _input) { return sha3Bytes((std::string*)&_input); }
/// Calculate SHA3-256 hash of the given input, returning as a byte array.
inline bytes sha3Bytes(bytes const& _input) { return sha3Bytes((bytes*)&_input); }
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
h256 sha3(bytesConstRef _input);
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_input)); }
/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash.
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); }
extern h256 EmptySHA3;
}

0
libethsupport/TrieCommon.cpp → libethcore/TrieCommon.cpp

4
libethsupport/TrieCommon.h → libethcore/TrieCommon.h

@ -21,8 +21,8 @@
#pragma once
#include "Common.h"
#include "RLP.h"
#include <libethential/Common.h>
#include <libethential/RLP.h>
namespace eth
{

5
libethsupport/TrieDB.cpp → libethcore/TrieDB.cpp

@ -19,7 +19,7 @@
* @date 2014
*/
#include "Common.h"
#include <libethential/Common.h>
#include "TrieDB.h"
using namespace std;
using namespace eth;
@ -27,6 +27,9 @@ using namespace eth;
namespace eth
{
#if !ETH_LANGUAGES
const h256 c_shaNull = sha3(rlp(""));
#endif
}

5
libethsupport/TrieDB.h → libethcore/TrieDB.h

@ -23,10 +23,11 @@
#include <map>
#include <memory>
#include "Common.h"
#include <libethential/Common.h>
#include <libethential/Log.h>
#include <libethcore/SHA3.h>
#include "MemoryDB.h"
#include "OverlayDB.h"
#include "Log.h"
#include "TrieCommon.h"
namespace ldb = leveldb;

10
libethsupport/UPnP.cpp → libethcore/UPnP.cpp

@ -20,14 +20,16 @@
* @date 2014
*/
#if !ETH_LANGUAGES
#include <stdio.h>
#include <string.h>
#include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
#include "Exceptions.h"
#include "Common.h"
#include "Log.h"
#include <libethential/Exceptions.h>
#include <libethential/Common.h>
#include <libethential/Log.h>
#include "UPnP.h"
using namespace std;
using namespace eth;
@ -167,3 +169,5 @@ void UPnP::removeRedirect(int port)
UPNP_DeletePortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, "TCP", NULL);
m_reg.erase(port);
}
#endif

0
libethsupport/UPnP.h → libethcore/UPnP.h

51
libethential/CMakeLists.txt

@ -0,0 +1,51 @@
cmake_policy(SET CMP0015 NEW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
set(EXECUTABLE ethential)
if(APPLE)
# set(CMAKE_INSTALL_PREFIX ../lib)
add_library(${EXECUTABLE} SHARED ${SRC_LIST})
else()
add_library(${EXECUTABLE} ${SRC_LIST})
endif()
file(GLOB HEADERS "*.h")
include_directories(..)
target_link_libraries(${EXECUTABLE} ethential)
target_link_libraries(${EXECUTABLE} gmp)
if(${TARGET_PLATFORM} STREQUAL "w64")
include_directories(/usr/x86_64-w64-mingw32/include/cryptopp)
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
target_link_libraries(${EXECUTABLE} iphlpapi)
target_link_libraries(${EXECUTABLE} ws2_32)
target_link_libraries(${EXECUTABLE} mswsock)
target_link_libraries(${EXECUTABLE} shlwapi)
elseif (APPLE)
# Latest mavericks boost libraries only come with -mt
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
elseif (UNIX)
target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY})
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
else ()
target_link_libraries(${EXECUTABLE} boost_thread)
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
endif ()
if (UNIX)
FIND_PACKAGE(Boost 1.53 REQUIRED COMPONENTS thread date_time system filesystem program_options signals serialization chrono unit_test_framework locale)
endif()
message("Installation path: ${CMAKE_INSTALL_PREFIX}")
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

2
libethsupport/Common.cpp → libethential/Common.cpp

@ -27,6 +27,6 @@ using namespace eth;
namespace eth
{
char const* EthVersion = "0.5.11";
char const* EthVersion = "0.5.12";
}

0
libethsupport/Common.h → libethential/Common.h

0
libethsupport/CommonData.cpp → libethential/CommonData.cpp

0
libethsupport/CommonData.h → libethential/CommonData.h

0
libethsupport/CommonIO.cpp → libethential/CommonIO.cpp

0
libethsupport/CommonIO.h → libethential/CommonIO.h

0
libethsupport/Exceptions.h → libethential/Exceptions.h

25
libethential/FixedHash.cpp

@ -0,0 +1,25 @@
/*
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/>.
*/
/** @file FixedHash.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "FixedHash.h"
using namespace std;
using namespace eth;

28
libethsupport/FixedHash.h → libethential/FixedHash.h

@ -197,34 +197,6 @@ inline h160 left160(h256 const& _t)
return ret;
}
// SHA-3 convenience routines.
/// Calculate SHA3-256 hash of the given input and load it into the given output.
void sha3(bytesConstRef _input, bytesRef _output);
/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data.
std::string sha3(std::string const& _input, bool _isNibbles);
/// Calculate SHA3-256 hash of the given input, returning as a byte array.
bytes sha3Bytes(bytesConstRef _input);
/// Calculate SHA3-256 hash of the given input (presented as a binary string), returning as a byte array.
inline bytes sha3Bytes(std::string const& _input) { return sha3Bytes((std::string*)&_input); }
/// Calculate SHA3-256 hash of the given input, returning as a byte array.
inline bytes sha3Bytes(bytes const& _input) { return sha3Bytes((bytes*)&_input); }
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
h256 sha3(bytesConstRef _input);
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_input)); }
/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash.
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); }
extern h256 EmptySHA3;
}
namespace std

0
libethsupport/Log.cpp → libethential/Log.cpp

0
libethsupport/Log.h → libethential/Log.h

0
libethsupport/RLP.cpp → libethential/RLP.cpp

8
libethsupport/RLP.h → libethential/RLP.h

@ -28,10 +28,10 @@
#include <exception>
#include <iostream>
#include <iomanip>
#include "vector_ref.h"
#include "Common.h"
#include "Exceptions.h"
#include "FixedHash.h"
#include <libethential/vector_ref.h>
#include <libethential/Common.h>
#include <libethential/Exceptions.h>
#include <libethential/FixedHash.h>
namespace eth
{

2
libethsupport/vector_ref.h → libethential/vector_ref.h

@ -54,7 +54,7 @@ public:
_T const& operator[](size_t _i) const { assert(m_data); assert(_i < m_count); return m_data[_i]; }
bool operator==(vector_ref<_T> const& _cmp) const { return m_data == _cmp.m_data && m_count == _cmp.m_count; }
bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(); }
bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); }
operator leveldb::Slice() const { return leveldb::Slice((char const*)m_data, m_count * sizeof(_T)); }

5
libethereum/AddressState.h

@ -21,8 +21,9 @@
#pragma once
#include <libethsupport/Common.h>
#include <libethsupport/RLP.h>
#include <libethential/Common.h>
#include <libethential/RLP.h>
#include <libethcore/SHA3.h>
namespace eth
{

6
libethereum/BlockChain.cpp

@ -22,9 +22,9 @@
#include "BlockChain.h"
#include <boost/filesystem.hpp>
#include <libethsupport/Common.h>
#include <libethsupport/RLP.h>
#include <libethsupport/FileSystem.h>
#include <libethential/Common.h>
#include <libethential/RLP.h>
#include <libethcore/FileSystem.h>
#include <libethcore/Exceptions.h>
#include <libethcore/Dagger.h>
#include <libethcore/BlockInfo.h>

2
libethereum/BlockChain.h

@ -22,7 +22,7 @@
#pragma once
#include <mutex>
#include <libethsupport/Log.h>
#include <libethential/Log.h>
#include <libethcore/CommonEth.h>
#include <libethcore/BlockInfo.h>
#include "AddressState.h"

1
libethereum/CMakeLists.txt

@ -23,7 +23,6 @@ include_directories(${LEVELDB_ID})
target_link_libraries(${EXECUTABLE} evm)
target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} ethsupport)
target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS})
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})

2
libethereum/Client.cpp

@ -24,7 +24,7 @@
#include <chrono>
#include <thread>
#include <boost/filesystem.hpp>
#include <libethsupport/Common.h>
#include <libethential/Common.h>
#include "Defaults.h"
#include "PeerServer.h"
using namespace std;

2
libethereum/Client.h

@ -25,7 +25,7 @@
#include <mutex>
#include <list>
#include <atomic>
#include <libethsupport/Common.h>
#include <libethential/Common.h>
#include <libethcore/Dagger.h>
#include "BlockChain.h"
#include "TransactionQueue.h"

2
libethereum/Defaults.cpp

@ -21,7 +21,7 @@
#include "Defaults.h"
#include <libethsupport/FileSystem.h>
#include <libethcore/FileSystem.h>
using namespace std;
using namespace eth;

2
libethereum/Defaults.h

@ -21,7 +21,7 @@
#pragma once
#include <libethsupport/Common.h>
#include <libethential/Common.h>
namespace eth
{

2
libethereum/Executive.h

@ -21,7 +21,7 @@
#pragma once
#include <libethsupport/Log.h>
#include <libethential/Log.h>
#include <libethcore/CommonEth.h>
#include "Transaction.h"

4
libethereum/PeerNetwork.h

@ -27,8 +27,8 @@
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <chrono>
#include <libethsupport/Common.h>
#include <libethsupport/Log.h>
#include <libethential/Common.h>
#include <libethential/Log.h>
namespace ba = boost::asio;
namespace bi = boost::asio::ip;

4
libethereum/PeerServer.cpp

@ -34,8 +34,8 @@
#include <set>
#include <chrono>
#include <thread>
#include <libethsupport/Common.h>
#include <libethsupport/UPnP.h>
#include <libethential/Common.h>
#include <libethcore/UPnP.h>
#include <libethcore/Exceptions.h>
#include "BlockChain.h"
#include "TransactionQueue.h"

2
libethereum/PeerSession.cpp

@ -22,7 +22,7 @@
#include "PeerSession.h"
#include <chrono>
#include <libethsupport/Common.h>
#include <libethential/Common.h>
#include <libethcore/Exceptions.h>
#include "BlockChain.h"
#include "PeerServer.h"

2
libethereum/PeerSession.h

@ -25,7 +25,7 @@
#include <set>
#include <memory>
#include <utility>
#include <libethsupport/RLP.h>
#include <libethential/RLP.h>
#include <libethcore/CommonEth.h>
#include "PeerNetwork.h"

2
libethereum/State.cpp

@ -25,7 +25,7 @@
#include <time.h>
#include <random>
#include <secp256k1/secp256k1.h>
#include <libethcore/Instruction.h>
#include <libevmface/Instruction.h>
#include <libethcore/Exceptions.h>
#include <libethcore/Dagger.h>
#include <libevm/VM.h>

6
libethereum/State.h

@ -24,9 +24,9 @@
#include <array>
#include <map>
#include <unordered_map>
#include <libethsupport/Common.h>
#include <libethsupport/RLP.h>
#include <libethsupport/TrieDB.h>
#include <libethential/Common.h>
#include <libethential/RLP.h>
#include <libethcore/TrieDB.h>
#include <libethcore/Exceptions.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/Dagger.h>

4
libethereum/Transaction.cpp

@ -20,8 +20,8 @@
*/
#include <secp256k1/secp256k1.h>
#include <libethsupport/vector_ref.h>
#include <libethsupport/Log.h>
#include <libethential/vector_ref.h>
#include <libethential/Log.h>
#include <libethcore/Exceptions.h>
#include "Transaction.h"
using namespace std;

3
libethereum/Transaction.h

@ -21,7 +21,8 @@
#pragma once
#include <libethsupport/RLP.h>
#include <libethential/RLP.h>
#include <libethcore/SHA3.h>
#include <libethcore/CommonEth.h>
namespace eth

2
libethereum/TransactionQueue.cpp

@ -21,7 +21,7 @@
#include "TransactionQueue.h"
#include <libethsupport/Log.h>
#include <libethential/Log.h>
#include <libethcore/Exceptions.h>
#include "Transaction.h"
using namespace std;

2
libethereum/TransactionQueue.h

@ -21,7 +21,7 @@
#pragma once
#include <libethsupport/Common.h>
#include <libethential/Common.h>
#include "Transaction.h"
namespace eth

3
libevm/CMakeLists.txt

@ -22,7 +22,8 @@ include_directories(${MINIUPNPC_ID})
include_directories(${LEVELDB_ID})
target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} ethsupport)
target_link_libraries(${EXECUTABLE} evmface)
target_link_libraries(${EXECUTABLE} ethential)
target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS})
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})

2
libevm/ExtVMFace.h

@ -21,7 +21,7 @@
#pragma once
#include <libethsupport/Common.h>
#include <libethential/Common.h>
#include <libethcore/CommonEth.h>
#include <libethcore/BlockInfo.h>

2
libevm/FeeStructure.h

@ -21,7 +21,7 @@
#pragma once
#include <libethsupport/Common.h>
#include <libethential/Common.h>
namespace eth
{

5
libevm/VM.h

@ -22,9 +22,10 @@
#pragma once
#include <unordered_map>
#include <libethsupport/Exceptions.h>
#include <libethential/Exceptions.h>
#include <libethcore/CommonEth.h>
#include <libethcore/Instruction.h>
#include <libevmface/Instruction.h>
#include <libethcore/SHA3.h>
#include <libethcore/BlockInfo.h>
#include "FeeStructure.h"
#include "ExtVMFace.h"

51
libevmface/CMakeLists.txt

@ -0,0 +1,51 @@
cmake_policy(SET CMP0015 NEW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
set(EXECUTABLE evmface)
if(APPLE)
# set(CMAKE_INSTALL_PREFIX ../lib)
add_library(${EXECUTABLE} SHARED ${SRC_LIST})
else()
add_library(${EXECUTABLE} ${SRC_LIST})
endif()
file(GLOB HEADERS "*.h")
include_directories(..)
target_link_libraries(${EXECUTABLE} ethential)
target_link_libraries(${EXECUTABLE} gmp)
if(${TARGET_PLATFORM} STREQUAL "w64")
include_directories(/usr/x86_64-w64-mingw32/include/cryptopp)
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
target_link_libraries(${EXECUTABLE} iphlpapi)
target_link_libraries(${EXECUTABLE} ws2_32)
target_link_libraries(${EXECUTABLE} mswsock)
target_link_libraries(${EXECUTABLE} shlwapi)
elseif (APPLE)
# Latest mavericks boost libraries only come with -mt
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
elseif (UNIX)
target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY})
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
else ()
target_link_libraries(${EXECUTABLE} boost_thread)
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
endif ()
if (UNIX)
FIND_PACKAGE(Boost 1.53 REQUIRED COMPONENTS thread date_time system filesystem program_options signals serialization chrono unit_test_framework locale)
endif()
message("Installation path: ${CMAKE_INSTALL_PREFIX}")
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

2
libethcore/Instruction.cpp → libevmface/Instruction.cpp

@ -21,7 +21,7 @@
#include "Instruction.h"
#include "CommonEth.h"
#include <libethential/Common.h>
using namespace std;
using namespace eth;

4
libethcore/Instruction.h → libevmface/Instruction.h

@ -21,8 +21,8 @@
#pragma once
#include <libethsupport/Common.h>
#include "Exceptions.h"
#include <libethential/Common.h>
#include <libethential/Exceptions.h>
namespace boost { namespace spirit { class utree; } }
namespace sp = boost::spirit;

2
liblll/Assembly.cpp

@ -21,7 +21,7 @@
#include "Assembly.h"
#include <libethsupport/Log.h>
#include <libethential/Log.h>
#include <libethcore/CommonEth.h>
using namespace std;

5
liblll/Assembly.h

@ -23,8 +23,9 @@
#include <iostream>
#include <sstream>
#include <libethsupport/Common.h>
#include <libethcore/Instruction.h>
#include <libethential/Common.h>
#include <libevmface/Instruction.h>
#include <libethcore/SHA3.h>
#include "Exceptions.h"
namespace eth

11
liblll/CMakeLists.txt

@ -18,17 +18,10 @@ endif()
file(GLOB HEADERS "*.h")
include_directories(..)
include_directories(${MINIUPNPC_ID})
include_directories(${LEVELDB_ID})
target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} ethsupport)
target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS})
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
target_link_libraries(${EXECUTABLE} ethential)
target_link_libraries(${EXECUTABLE} evmface)
target_link_libraries(${EXECUTABLE} gmp)
if(${TARGET_PLATFORM} STREQUAL "w64")
include_directories(/usr/x86_64-w64-mingw32/include/cryptopp)
target_link_libraries(${EXECUTABLE} cryptopp)

4
liblll/CodeFragment.cpp

@ -24,8 +24,8 @@
#include <boost/algorithm/string.hpp>
#include <boost/spirit/include/support_utree.hpp>
#include <libethsupport/Log.h>
#include <libethcore/Instruction.h>
#include <libethential/Log.h>
#include <libevmface/Instruction.h>
#include <libethcore/CommonEth.h>
#include "CompilerState.h"
using namespace std;

4
liblll/CodeFragment.h

@ -21,8 +21,8 @@
#pragma once
#include <libethsupport/Common.h>
#include <libethcore/Instruction.h>
#include <libethential/Common.h>
#include <libevmface/Instruction.h>
#include "Assembly.h"
#include "Exceptions.h"

2
liblll/Compiler.h

@ -23,7 +23,7 @@
#include <string>
#include <vector>
#include <libethsupport/Common.h>
#include <libethential/Common.h>
namespace eth
{

2
liblll/Parser.h

@ -23,7 +23,7 @@
#include <string>
#include <vector>
#include <libethsupport/Common.h>
#include <libethential/Common.h>
namespace boost { namespace spirit { class utree; } }
namespace sp = boost::spirit;

4
libqethereum/QEthereum.cpp

@ -1,9 +1,9 @@
#include <QtQml/QtQml>
#include <QtCore/QtCore>
#include <QtWebKitWidgets/QWebFrame>
#include <libethsupport/FileSystem.h>
#include <libethcore/FileSystem.h>
#include <libethcore/Dagger.h>
#include <libethcore/Instruction.h>
#include <libevmface/Instruction.h>
#include <liblll/Compiler.h>
#include <libethereum/Client.h>
#include <libethereum/PeerServer.h>

2
libqethereum/QEthereum.h

@ -2,7 +2,7 @@
#include <QtCore/QAbstractListModel>
#include <QtQml/QtQml>
#include <libethsupport/CommonIO.h>
#include <libethential/CommonIO.h>
#include <libethcore/CommonEth.h>
namespace eth {

10
libethsupport/CMakeLists.txt → libserpent/CMakeLists.txt

@ -4,7 +4,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
set(EXECUTABLE ethsupport)
set(EXECUTABLE serpent)
if(APPLE)
# set(CMAKE_INSTALL_PREFIX ../lib)
@ -18,12 +18,10 @@ endif()
file(GLOB HEADERS "*.h")
include_directories(..)
include_directories(${MINIUPNPC_ID})
include_directories(${LEVELDB_ID})
target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS})
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
target_link_libraries(${EXECUTABLE} ethential)
target_link_libraries(${EXECUTABLE} evmface)
target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} gmp)

98
libserpent/bignum.cpp

@ -0,0 +1,98 @@
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "bignum.h"
//Integer to string conversion
std::string intToDecimal(int branch) {
if (branch < 10) return nums.substr(branch, 1);
else return intToDecimal(branch / 10) + nums.substr(branch % 10,1);
}
//Add two strings representing decimal values
std::string decimalAdd(std::string a, std::string b) {
std::string o = a;
while (b.length() < a.length()) b = "0" + b;
while (o.length() < b.length()) o = "0" + o;
bool carry = false;
for (int i = o.length() - 1; i >= 0; i--) {
o[i] = o[i] + b[i] - '0';
if (carry) o[i]++;
if (o[i] > '9') {
o[i] -= 10;
carry = true;
}
else carry = false;
}
if (carry) o = "1" + o;
return o;
}
//Helper function for decimalMul
std::string decimalDigitMul(std::string a, int dig) {
if (dig == 0) return "0";
else return decimalAdd(a, decimalDigitMul(a, dig - 1));
}
//Multiply two strings representing decimal values
std::string decimalMul(std::string a, std::string b) {
std::string o = "0";
for (unsigned i = 0; i < b.length(); i++) {
std::string n = decimalDigitMul(a, b[i] - '0');
if (n != "0") {
for (unsigned j = i + 1; j < b.length(); j++) n += "0";
}
o = decimalAdd(o, n);
}
return o;
}
//Is a greater than b? Flag allows equality
bool decimalGt(std::string a, std::string b, bool eqAllowed) {
if (a == b) return eqAllowed;
return (a.length() > b.length()) || (a.length() >= b.length() && a > b);
}
//Subtract the two strings representing decimal values
std::string decimalSub(std::string a, std::string b) {
if (b == "0") return a;
if (b == a) return "0";
while (b.length() < a.length()) b = "0" + b;
std::string c = b;
for (unsigned i = 0; i < c.length(); i++) c[i] = '0' + ('9' - c[i]);
std::string o = decimalAdd(decimalAdd(a, c).substr(1), "1");
while (o.size() > 1 && o[0] == '0') o = o.substr(1);
return o;
}
//Divide the two strings representing decimal values
std::string decimalDiv(std::string a, std::string b) {
std::string c = b;
if (decimalGt(c, a)) return "0";
int zeroes = -1;
while (decimalGt(a, c, true)) {
zeroes += 1;
c = c + "0";
}
c = c.substr(0, c.size() - 1);
std::string quot = "0";
while (decimalGt(a, c, true)) {
a = decimalSub(a, c);
quot = decimalAdd(quot, "1");
}
for (int i = 0; i < zeroes; i++) quot += "0";
return decimalAdd(quot, decimalDiv(a, b));
}
//Modulo the two strings representing decimal values
std::string decimalMod(std::string a, std::string b) {
return decimalSub(a, decimalMul(decimalDiv(a, b), b));
}
//String to int conversion
int decimalToInt(std::string a) {
if (a.size() == 0) return 0;
else return (a[a.size() - 1] - '0')
+ decimalToInt(a.substr(0,a.size()-1)) * 10;
}

30
libserpent/bignum.h

@ -0,0 +1,30 @@
#ifndef ETHSERP_BIGNUM
#define ETHSERP_BIGNUM
const std::string nums = "0123456789";
const std::string tt256 =
"115792089237316195423570985008687907853269984665640564039457584007913129639936"
;
const std::string tt255 =
"57896044618658097711785492504343953926634992332820282019728792003956564819968"
;
std::string intToDecimal(int branch);
std::string decimalAdd(std::string a, std::string b);
std::string decimalMul(std::string a, std::string b);
std::string decimalSub(std::string a, std::string b);
std::string decimalDiv(std::string a, std::string b);
std::string decimalMod(std::string a, std::string b);
bool decimalGt(std::string a, std::string b, bool eqAllowed=false);
int decimalToInt(std::string a);
#endif

407
libserpent/compiler.cpp

@ -0,0 +1,407 @@
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
#include "bignum.h"
#include "opcodes.h"
struct programAux {
std::map<std::string, std::string> vars;
bool allocUsed;
bool calldataUsed;
int step;
int labelLength;
};
struct programData {
programAux aux;
Node code;
};
programAux Aux() {
programAux o;
o.allocUsed = false;
o.calldataUsed = false;
o.step = 0;
return o;
}
programData pd(programAux aux = Aux(), Node code=token("_")) {
programData o;
o.aux = aux;
o.code = code;
return o;
}
Node multiToken(Node nodes[], int len, Metadata met) {
std::vector<Node> out;
for (int i = 0; i < len; i++) {
out.push_back(nodes[i]);
}
return astnode("_", out, met);
}
Node finalize(programData c);
// Turns LLL tree into tree of code fragments
programData opcodeify(Node node, programAux aux=Aux()) {
std::string symb = "_"+mkUniqueToken();
Metadata m = node.metadata;
// Numbers
if (node.type == TOKEN) {
return pd(aux, nodeToNumeric(node));
}
else if (node.val == "ref" || node.val == "get" || node.val == "set") {
std::string varname = node.args[0].val;
if (!aux.vars.count(varname)) {
aux.vars[varname] = intToDecimal(aux.vars.size() * 32);
}
if (varname == "msg.data") aux.calldataUsed = true;
// Set variable
if (node.val == "set") {
programData sub = opcodeify(node.args[1], aux);
Node nodelist[] = {
sub.code,
token(aux.vars[varname], m),
token("MSTORE", m),
};
return pd(sub.aux, multiToken(nodelist, 3, m));
}
// Get variable
else if (node.val == "get") {
Node nodelist[] =
{ token(aux.vars[varname], m), token("MLOAD", m) };
return pd(aux, multiToken(nodelist, 2, m));
}
// Refer variable
else return pd(aux, token(aux.vars[varname], m));
}
// Code blocks
if (node.val == "lll" && node.args.size() == 2) {
if (node.args[1].val != "0") aux.allocUsed = true;
std::vector<Node> o;
o.push_back(finalize(opcodeify(node.args[0])));
programData sub = opcodeify(node.args[1], aux);
Node code = astnode("____CODE", o, m);
Node nodelist[] = {
token("$begincode"+symb+".endcode"+symb, m), token("DUP", m),
sub.code,
token("$begincode"+symb, m), token("CODECOPY", m),
token("$endcode"+symb, m), token("JUMP", m),
token("~begincode"+symb, m), code, token("~endcode"+symb, m)
};
return pd(sub.aux, multiToken(nodelist, 10, m));
}
std::vector<Node> subs;
for (unsigned i = 0; i < node.args.size(); i++) {
programData sub = opcodeify(node.args[i], aux);
aux = sub.aux;
subs.push_back(sub.code);
}
// Seq of multiple statements
if (node.val == "seq") {
return pd(aux, astnode("_", subs, m));
}
// 2-part conditional (if gets rewritten to unless in rewrites)
else if (node.val == "unless" && node.args.size() == 2) {
Node nodelist[] = {
subs[0],
token("$endif"+symb, m), token("JUMPI", m),
subs[1],
token("~endif"+symb, m)
};
return pd(aux, multiToken(nodelist, 5, m));
}
// 3-part conditional
else if (node.val == "if" && node.args.size() == 3) {
Node nodelist[] = {
subs[0],
token("NOT", m), token("$else"+symb, m), token("JUMPI", m),
subs[1],
token("$endif"+symb, m), token("JUMP", m), token("~else"+symb, m),
subs[2],
token("~endif"+symb, m)
};
return pd(aux, multiToken(nodelist, 10, m));
}
// While (rewritten to this in rewrites)
else if (node.val == "until") {
Node nodelist[] = {
token("~beg"+symb, m),
subs[0],
token("$end"+symb, m), token("JUMPI", m),
subs[1],
token("$beg"+symb, m), token("JUMP", m), token("~end"+symb, m)
};
return pd(aux, multiToken(nodelist, 8, m));
}
// Memory allocations
else if (node.val == "alloc") {
aux.allocUsed = true;
Node nodelist[] = {
subs[0],
token("MSIZE", m), token("SWAP", m), token("MSIZE", m),
token("ADD", m), token("1", m), token("SWAP", m), token("SUB", m),
token("0", m), token("SWAP", m), token("MSTORE8", m)
};
return pd(aux, multiToken(nodelist, 11, m));
}
// Array literals
else if (node.val == "array_lit") {
aux.allocUsed = true;
std::vector<Node> nodes;
if (!subs.size()) {
nodes.push_back(token("MSIZE", m));
return pd(aux, astnode("_", nodes, m));
}
nodes.push_back(token("MSIZE", m));
nodes.push_back(token("0", m));
nodes.push_back(token("MSIZE", m));
nodes.push_back(token(intToDecimal(subs.size() * 32 - 1), m));
nodes.push_back(token("ADD", m));
nodes.push_back(token("MSTORE8", m));
for (unsigned i = 0; i < subs.size(); i++) {
nodes.push_back(token("DUP", m));
nodes.push_back(subs[i]);
nodes.push_back(token("SWAP", m));
if (i > 0) {
nodes.push_back(token(intToDecimal(i * 32), m));
nodes.push_back(token("ADD", m));
}
nodes.push_back(token("MSTORE", m));
}
return pd(aux, astnode("_", nodes, m));
}
// All other functions/operators
else {
std::vector<Node> subs2;
while (subs.size()) {
subs2.push_back(subs.back());
subs.pop_back();
}
subs2.push_back(token(upperCase(node.val), m));
return pd(aux, astnode("_", subs2, m));
}
}
// Adds necessary wrappers to a program
Node finalize(programData c) {
std::vector<Node> bottom;
Metadata m = c.code.metadata;
// If we are using both alloc and variables, we need to pre-zfill
// some memory
if (c.aux.allocUsed && c.aux.vars.size() > 0) {
Node nodelist[] = {
token("0", m),
token(intToDecimal(c.aux.vars.size() * 32 - 1)),
token("MSTORE8", m)
};
bottom.push_back(multiToken(nodelist, 3, m));
}
// If msg.data is being used as an array, then we need to copy it
if (c.aux.calldataUsed) {
Node nodelist[] = {
token("MSIZE", m), token("CALLDATASIZE", m), token("MSIZE", m),
token("0", m), token("CALLDATACOPY", m),
token(c.aux.vars["msg.data"], m), token("MSTORE", m)
};
bottom.push_back(multiToken(nodelist, 7, m));
}
// The actual code
bottom.push_back(c.code);
return astnode("_", bottom, m);
}
//LLL -> code fragment tree
Node buildFragmentTree(Node node) {
return finalize(opcodeify(node));
}
// Builds a dictionary mapping labels to variable names
programAux buildDict(Node program, programAux aux, int labelLength) {
Metadata m = program.metadata;
// Token
if (program.type == TOKEN) {
if (isNumberLike(program)) {
aux.step += 1 + toByteArr(program.val, m).size();
}
else if (program.val[0] == '~') {
aux.vars[program.val.substr(1)] = intToDecimal(aux.step);
}
else if (program.val[0] == '$') {
aux.step += labelLength + 1;
}
else aux.step += 1;
}
// A sub-program (ie. LLL)
else if (program.val == "____CODE") {
programAux auks = Aux();
for (unsigned i = 0; i < program.args.size(); i++) {
auks = buildDict(program.args[i], auks, labelLength);
}
for (std::map<std::string,std::string>::iterator it=auks.vars.begin();
it != auks.vars.end();
it++) {
aux.vars[(*it).first] = (*it).second;
}
aux.step += auks.step;
}
// Normal sub-block
else {
for (unsigned i = 0; i < program.args.size(); i++) {
aux = buildDict(program.args[i], aux, labelLength);
}
}
return aux;
}
// Applies that dictionary
Node substDict(Node program, programAux aux, int labelLength) {
Metadata m = program.metadata;
std::vector<Node> out;
std::vector<Node> inner;
if (program.type == TOKEN) {
if (program.val[0] == '$') {
std::string tokStr = "PUSH"+intToDecimal(labelLength);
out.push_back(token(tokStr, m));
int dotLoc = program.val.find('.');
if (dotLoc == -1) {
std::string val = aux.vars[program.val.substr(1)];
inner = toByteArr(val, m, labelLength);
}
else {
std::string start = aux.vars[program.val.substr(1, dotLoc-1)],
end = aux.vars[program.val.substr(dotLoc + 1)],
dist = decimalSub(end, start);
inner = toByteArr(dist, m, labelLength);
}
out.push_back(astnode("_", inner, m));
}
else if (program.val[0] == '~') { }
else if (isNumberLike(program)) {
inner = toByteArr(program.val, m);
out.push_back(token("PUSH"+intToDecimal(inner.size())));
out.push_back(astnode("_", inner, m));
}
else return program;
}
else {
for (unsigned i = 0; i < program.args.size(); i++) {
Node n = substDict(program.args[i], aux, labelLength);
if (n.type == TOKEN || n.args.size()) out.push_back(n);
}
}
return astnode("_", out, m);
}
// Compiled fragtree -> compiled fragtree without labels
Node dereference(Node program) {
int sz = treeSize(program) * 4;
int labelLength = 1;
while (sz >= 256) { labelLength += 1; sz /= 256; }
programAux aux = buildDict(program, Aux(), labelLength);
return substDict(program, aux, labelLength);
}
// Dereferenced fragtree -> opcodes
std::vector<Node> flatten(Node derefed) {
std::vector<Node> o;
if (derefed.type == TOKEN) {
o.push_back(derefed);
}
else {
for (unsigned i = 0; i < derefed.args.size(); i++) {
std::vector<Node> oprime = flatten(derefed.args[i]);
for (unsigned j = 0; j < oprime.size(); j++) o.push_back(oprime[j]);
}
}
return o;
}
// Opcodes -> bin
std::string serialize(std::vector<Node> codons) {
std::string o;
for (unsigned i = 0; i < codons.size(); i++) {
int v;
if (isNumberLike(codons[i])) {
v = decimalToInt(codons[i].val);
}
else if (codons[i].val.substr(0,4) == "PUSH") {
v = 95 + decimalToInt(codons[i].val.substr(4));
}
else {
v = opcode(codons[i].val);
}
o += (char)v;
}
return o;
}
// Bin -> opcodes
std::vector<Node> deserialize(std::string ser) {
std::vector<Node> o;
int backCount = 0;
for (unsigned i = 0; i < ser.length(); i++) {
unsigned char v = (unsigned char)ser[i];
std::string oper = op((int)v);
if (oper != "" && backCount <= 0) o.push_back(token(oper));
else if (v >= 96 && v < 128 && backCount <= 0) {
o.push_back(token("PUSH"+intToDecimal(v - 95)));
}
else o.push_back(token(intToDecimal(v)));
if (v >= 96 && v < 128 && backCount <= 0) {
backCount = v - 95;
}
else backCount--;
}
return o;
}
// Fragtree -> bin
std::string assemble(Node fragTree) {
return serialize(flatten(dereference(fragTree)));
}
// Fragtree -> tokens
std::vector<Node> prettyAssemble(Node fragTree) {
return flatten(dereference(fragTree));
}
// LLL -> bin
std::string compileLLL(Node program) {
return assemble(buildFragmentTree(program));
}
// LLL -> tokens
std::vector<Node> prettyCompileLLL(Node program) {
return prettyAssemble(buildFragmentTree(program));
}
// Converts a list of integer values to binary transaction data
std::string encodeDatalist(std::vector<std::string> vals) {
std::string o;
for (unsigned i = 0; i < vals.size(); i++) {
std::vector<Node> n = toByteArr(strToNumeric(vals[i]), Metadata(), 32);
for (unsigned j = 0; j < n.size(); j++) {
int v = decimalToInt(n[j].val);
o += (char)v;
}
}
return o;
}
// Converts binary transaction data into a list of integer values
std::vector<std::string> decodeDatalist(std::string ser) {
std::vector<std::string> out;
for (unsigned i = 0; i < ser.length(); i+= 32) {
std::string o = "0";
for (unsigned j = i; j < i + 32; j++) {
int vj = (int)(unsigned char)ser[j];
o = decimalAdd(decimalMul(o, "256"), intToDecimal(vj));
}
out.push_back(o);
}
return out;
}

43
libserpent/compiler.h

@ -0,0 +1,43 @@
#ifndef ETHSERP_COMPILER
#define ETHSERP_COMPILER
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
// Compiled fragtree -> compiled fragtree without labels
Node dereference(Node program);
// LLL -> fragtree
Node buildFragmentTree(Node program);
// Dereferenced fragtree -> opcodes
std::vector<Node> flatten(Node derefed);
// opcodes -> bin
std::string serialize(std::vector<Node> codons);
// Fragtree -> bin
std::string assemble(Node fragTree);
// Fragtree -> opcodes
std::vector<Node> prettyAssemble(Node fragTree);
// LLL -> bin
std::string compileLLL(Node program);
// LLL -> opcodes
std::vector<Node> prettyCompileLLL(Node program);
// bin -> opcodes
std::vector<Node> deserialize(std::string ser);
// Converts a list of integer values to binary transaction data
std::string encodeDatalist(std::vector<std::string> vals);
// Converts binary transaction data into a list of integer values
std::vector<std::string> decodeDatalist(std::string ser);
#endif

11
libserpent/example.cpp

@ -0,0 +1,11 @@
#include <libserpent/funcs.h>
#include <libserpent/bignum.h>
#include <iostream>
using namespace std;
int main() {
cout << printAST(compileToLLL(get_file_contents("examples/namecoin.se"))) << "\n";
cout << decimalSub("10234", "10234") << "\n";
cout << decimalSub("10234", "10233") << "\n";
}

23
libserpent/funcs.cpp

@ -0,0 +1,23 @@
#include <stdio.h>
#include <iostream>
#include <vector>
#include "funcs.h"
#include "bignum.h"
#include "util.h"
#include "parser.h"
#include "lllparser.h"
#include "compiler.h"
#include "rewriter.h"
#include "tokenize.h"
Node compileToLLL(std::string input) {
return rewrite(parseSerpent(input));
}
std::string compile(std::string input) {
return compileLLL(compileToLLL(input));
}
std::vector<Node> prettyCompile(std::string input) {
return prettyCompileLLL(compileToLLL(input));
}

29
libserpent/funcs.h

@ -0,0 +1,29 @@
#include <stdio.h>
#include <iostream>
#include <vector>
#include "bignum.h"
#include "util.h"
#include "parser.h"
#include "lllparser.h"
#include "compiler.h"
#include "rewriter.h"
#include "tokenize.h"
// Function listing:
//
// parseSerpent (serpent -> AST) std::string -> Node
// parseLLL (LLL -> AST) std::string -> Node
// rewrite (apply rewrite rules) Node -> Node
// compileToLLL (serpent -> LLL) std::string -> Node
// compileLLL (LLL -> EVMhex) Node -> std::string
// prettyCompileLLL (LLL -> EVMasm) Node -> std::vector<Node>
// prettyCompile (serpent -> EVMasm) std::string -> std::vector>Node>
// compile (serpent -> EVMhex) std::string -> std::string
// get_file_contents (filename -> file) std::string -> std::string
// exists (does file exist?) std::string -> bool
Node compileToLLL(std::string input);
std::string compile(std::string input);
std::vector<Node> prettyCompile(std::string input);

70
libserpent/lllparser.cpp

@ -0,0 +1,70 @@
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
#include "lllparser.h"
#include "tokenize.h"
struct _parseOutput {
Node node;
int newpos;
};
// Helper, returns subtree and position of start of next node
_parseOutput _parse(std::vector<Node> inp, int pos) {
Metadata met = inp[pos].metadata;
_parseOutput o;
// Bracket: keep grabbing tokens until we get to the
// corresponding closing bracket
if (inp[pos].val == "(" || inp[pos].val == "[") {
std::string fun, rbrack;
std::vector<Node> args;
pos += 1;
if (inp[pos].val == "[") {
fun = "access";
rbrack = "]";
}
else rbrack = ")";
// First argument is the function
while (inp[pos].val != ")") {
_parseOutput po = _parse(inp, pos);
if (fun.length() == 0 && po.node.type == 1) {
std::cerr << "Error: first arg must be function\n";
fun = po.node.val;
}
else if (fun.length() == 0) {
fun = po.node.val;
}
else {
args.push_back(po.node);
}
pos = po.newpos;
}
o.newpos = pos + 1;
o.node = astnode(fun, args, met);
}
// Normal token, return it and advance to next token
else {
o.newpos = pos + 1;
o.node = token(inp[pos].val, met);
}
return o;
}
// stream of tokens -> lisp parse tree
Node parseLLLTokenStream(std::vector<Node> inp) {
_parseOutput o = _parse(inp, 0);
return o.node;
}
// Parses LLL
Node parseLLL(std::string s, bool allowFileRead) {
std::string input = s;
std::string file = "main";
if (exists(s) && allowFileRead) {
file = s;
input = get_file_contents(s);
}
return parseLLLTokenStream(tokenize(s, Metadata(file, 0, 0)));
}

13
libserpent/lllparser.h

@ -0,0 +1,13 @@
#ifndef ETHSERP_LLLPARSER
#define ETHSERP_LLLPARSER
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
// LLL text -> parse tree
Node parseLLL(std::string s, bool allowFileRead=false);
#endif

91
libserpent/opcodes.h

@ -0,0 +1,91 @@
#ifndef ETHSERP_OPCODES
#define ETHSERP_OPCODES
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
std::map<std::string, int> opcodes;
std::map<int, std::string> reverseOpcodes;
// Fetches everything EXCEPT PUSH1..32
std::pair<std::string, int> _opcode(std::string ops, int opi) {
if (!opcodes.size()) {
opcodes["STOP"] = 0x00;
opcodes["ADD"] = 0x01;
opcodes["MUL"] = 0x02;
opcodes["SUB"] = 0x03;
opcodes["DIV"] = 0x04;
opcodes["SDIV"] = 0x05;
opcodes["MOD"] = 0x06;
opcodes["SMOD"] = 0x07;
opcodes["EXP"] = 0x08;
opcodes["NEG"] = 0x09;
opcodes["LT"] = 0x0a;
opcodes["GT"] = 0x0b;
opcodes["SLT"] = 0x0c;
opcodes["SGT"] = 0x0d;
opcodes["EQ"] = 0x0e;
opcodes["NOT"] = 0x0f;
opcodes["AND"] = 0x10;
opcodes["OR"] = 0x11;
opcodes["XOR"] = 0x12;
opcodes["BYTE"] = 0x13;
opcodes["SHA3"] = 0x20;
opcodes["ADDRESS"] = 0x30;
opcodes["BALANCE"] = 0x31;
opcodes["ORIGIN"] = 0x32;
opcodes["CALLER"] = 0x33;
opcodes["CALLVALUE"] = 0x34;
opcodes["CALLDATALOAD"] = 0x35;
opcodes["CALLDATASIZE"] = 0x36;
opcodes["CALLDATACOPY"] = 0x37;
opcodes["CODESIZE"] = 0x38;
opcodes["CODECOPY"] = 0x39;
opcodes["GASPRICE"] = 0x3a;
opcodes["PREVHASH"] = 0x40;
opcodes["COINBASE"] = 0x41;
opcodes["TIMESTAMP"] = 0x42;
opcodes["NUMBER"] = 0x43;
opcodes["DIFFICULTY"] = 0x44;
opcodes["GASLIMIT"] = 0x45;
opcodes["POP"] = 0x50;
opcodes["DUP"] = 0x51;
opcodes["SWAP"] = 0x52;
opcodes["MLOAD"] = 0x53;
opcodes["MSTORE"] = 0x54;
opcodes["MSTORE8"] = 0x55;
opcodes["SLOAD"] = 0x56;
opcodes["SSTORE"] = 0x57;
opcodes["JUMP"] = 0x58;
opcodes["JUMPI"] = 0x59;
opcodes["PC"] = 0x5a;
opcodes["MSIZE"] = 0x5b;
opcodes["GAS"] = 0x5c;
opcodes["CREATE"] = 0xf0;
opcodes["CALL"] = 0xf1;
opcodes["RETURN"] = 0xf2;
opcodes["SUICIDE"] = 0xff;
for (std::map<std::string, int>::iterator it=opcodes.begin();
it != opcodes.end();
it++) {
reverseOpcodes[(*it).second] = (*it).first;
}
}
std::string op;
int opcode;
op = reverseOpcodes.count(opi) ? reverseOpcodes[opi] : "";
opcode = opcodes.count(ops) ? opcodes[ops] : -1;
return std::pair<std::string, int>(op, opcode);
}
int opcode(std::string op) {
return _opcode(op, 0).second;
}
std::string op(int opcode) {
return _opcode("", opcode).first;
}
#endif

387
libserpent/parser.cpp

@ -0,0 +1,387 @@
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
#include "parser.h"
#include "tokenize.h"
// Extended BEDMAS precedence order
int precedence(Node tok) {
std::string v = tok.val;
if (v == "!" || v == "not") return 0;
else if (v=="^" || v == "**") return 1;
else if (v=="*" || v=="/" || v=="@/" || v=="%" || v=="@%") return 2;
else if (v=="+" || v=="-") return 3;
else if (v=="<" || v==">" || v=="<=" || v==">=") return 4;
else if (v=="@<" || v=="@>" || v=="@<=" || v=="@>=") return 4;
else if (v=="&" || v=="|" || v=="xor" || v=="==") return 5;
else if (v=="&&" || v=="and") return 6;
else if (v=="||" || v=="or") return 7;
else if (v=="=") return 10;
else if (v=="+=" || v=="-=" || v=="*=" || v=="/=" || v=="%=") return 10;
else if (v=="@/=" || v=="@%=") return 10;
else return -1;
}
// Token classification for shunting-yard purposes
int toktype(Node tok) {
if (tok.type == ASTNODE) return COMPOUND;
std::string v = tok.val;
if (v == "(" || v == "[") return LPAREN;
else if (v == ")" || v == "]") return RPAREN;
else if (v == ",") return COMMA;
else if (v == ":") return COLON;
else if (v == "!" || v == "not") return UNARY_OP;
else if (precedence(tok) >= 0) return BINARY_OP;
if (tok.val[0] != '"' && tok.val[0] != '\'') {
for (unsigned i = 0; i < tok.val.length(); i++) {
if (chartype(tok.val[i]) == SYMB) {
err("Invalid symbol: "+tok.val, tok.metadata);
}
}
}
return ALPHANUM;
}
// Converts to reverse polish notation
std::vector<Node> shuntingYard(std::vector<Node> tokens) {
std::vector<Node> iq;
for (int i = tokens.size() - 1; i >= 0; i--) {
iq.push_back(tokens[i]);
}
std::vector<Node> oq;
std::vector<Node> stack;
Node prev, tok;
int prevtyp, toktyp;
while (iq.size()) {
prev = tok;
prevtyp = toktyp;
tok = iq.back();
toktyp = toktype(tok);
iq.pop_back();
// Alphanumerics go straight to output queue
if (toktyp == ALPHANUM) {
oq.push_back(tok);
}
// Left parens go on stack and output queue
else if (toktyp == LPAREN) {
if (prevtyp != ALPHANUM && prevtyp != RPAREN) {
oq.push_back(token("id", tok.metadata));
}
Node fun = oq.back();
oq.pop_back();
oq.push_back(tok);
oq.push_back(fun);
stack.push_back(tok);
}
// If rparen, keep moving from stack to output queue until lparen
else if (toktyp == RPAREN) {
while (stack.size() && toktype(stack.back()) != LPAREN) {
oq.push_back(stack.back());
stack.pop_back();
}
if (stack.size()) stack.pop_back();
oq.push_back(tok);
}
// If binary op, keep popping from stack while higher bedmas precedence
else if (toktyp == UNARY_OP || toktyp == BINARY_OP) {
if (tok.val == "-" && prevtyp != ALPHANUM && prevtyp != RPAREN) {
oq.push_back(token("0", tok.metadata));
}
int prec = precedence(tok);
while (stack.size()
&& toktype(stack.back()) == BINARY_OP
&& precedence(stack.back()) <= prec) {
oq.push_back(stack.back());
stack.pop_back();
}
stack.push_back(tok);
}
// Comma and colon mean finish evaluating the argument
else if (toktyp == COMMA || toktyp == COLON) {
while (stack.size() && toktype(stack.back()) != LPAREN) {
oq.push_back(stack.back());
stack.pop_back();
}
if (toktyp == COLON) oq.push_back(tok);
}
}
while (stack.size()) {
oq.push_back(stack.back());
stack.pop_back();
}
return oq;
}
// Converts reverse polish notation into tree
Node treefy(std::vector<Node> stream) {
std::vector<Node> iq;
for (int i = stream.size() -1; i >= 0; i--) {
iq.push_back(stream[i]);
}
std::vector<Node> oq;
while (iq.size()) {
Node tok = iq.back();
iq.pop_back();
int typ = toktype(tok);
// If unary, take node off end of oq and wrap it with the operator
// If binary, do the same with two nodes
if (typ == UNARY_OP || typ == BINARY_OP) {
std::vector<Node> args;
int rounds = (typ == BINARY_OP) ? 2 : 1;
for (int i = 0; i < rounds; i++) {
if (oq.size() == 0) {
err("Line malformed, not enough args for "+tok.val,
tok.metadata);
}
args.push_back(oq.back());
oq.pop_back();
}
std::vector<Node> args2;
while (args.size()) {
args2.push_back(args.back());
args.pop_back();
}
oq.push_back(astnode(tok.val, args2, tok.metadata));
}
// If rparen, keep grabbing until we get to an lparen
else if (toktype(tok) == RPAREN) {
std::vector<Node> args;
while (1) {
args.push_back(oq.back());
oq.pop_back();
if (!oq.size()) err("Bracket without matching", tok.metadata);
if (toktype(oq.back()) == LPAREN) break;
}
oq.pop_back();
// We represent a[b] as (access a b)
if (tok.val == "]") args.push_back(token("access", tok.metadata));
std::string fun = args.back().val;
args.pop_back();
// We represent [1,2,3] as (array_lit 1 2 3)
if (fun == "access" && args.size() && args.back().val == "id") {
fun = "array_lit";
args.pop_back();
}
std::vector<Node> args2;
while (args.size()) {
args2.push_back(args.back());
args.pop_back();
}
// When evaluating 2 + (3 * 5), the shunting yard algo turns that
// into 2 ( id 3 5 * ) +, effectively putting "id" as a dummy
// function where the algo was expecting a function to call the
// thing inside the brackets. This reverses that step
if (fun == "id" && args2.size()) {
oq.push_back(args2[0]);
}
else {
oq.push_back(astnode(fun, args2, tok.metadata));
}
}
else oq.push_back(tok);
// This is messy, but has to be done. Import/inset other files here
std::string v = oq.back().val;
if ((v == "inset" || v == "import" || v == "create")
&& oq.back().args.size() == 1
&& oq.back().args[0].type == TOKEN) {
int lastSlashPos = tok.metadata.file.rfind("/");
std::string root;
if (lastSlashPos >= 0)
root = tok.metadata.file.substr(0, lastSlashPos) + "/";
else
root = "";
std::string filename = oq.back().args[0].val;
filename = filename.substr(1, filename.length() - 2);
if (!exists(root + filename))
err("File does not exist: "+root + filename, tok.metadata);
oq.back().args.pop_back();
oq.back().args.push_back(parseSerpent(root + filename));
}
// Useful for debugging
// for (int i = 0; i < oq.size(); i++) {
// std::cerr << printSimple(oq[i]) << " ";
// }
// std::cerr << "\n";
}
// Output must have one argument
if (oq.size() == 0) {
err("Output blank", Metadata());
}
else if (oq.size() > 1) {
err("Multiple expressions or unclosed bracket", oq[1].metadata);
}
return oq[0];
}
// Parses one line of serpent
Node parseSerpentTokenStream(std::vector<Node> s) {
return treefy(shuntingYard(s));
}
// Count spaces at beginning of line
int spaceCount(std::string s) {
unsigned pos = 0;
while (pos < s.length() && (s[pos] == ' ' || s[pos] == '\t'))
pos++;
return pos;
}
// Is this a command that takes an argument on the same line?
bool bodied(std::string tok) {
return tok == "if" || tok == "elif" || tok == "while";
}
// Is this a command that takes an argument as a child block?
bool childBlocked(std::string tok) {
return tok == "if" || tok == "elif" || tok == "else"
|| tok == "code" || tok == "shared" || tok == "init"
|| tok == "while";
}
// Are the two commands meant to continue each other?
bool bodiedContinued(std::string prev, std::string tok) {
return (prev == "if" && tok == "elif")
|| (prev == "elif" && tok == "else")
|| (prev == "elif" && tok == "elif")
|| (prev == "if" && tok == "else")
|| (prev == "init" && tok == "code")
|| (prev == "shared" && tok == "code")
|| (prev == "shared" && tok == "init");
}
// Is a line of code empty?
bool isLineEmpty(std::string line) {
std::vector<Node> tokens = tokenize(line);
if (!tokens.size() || tokens[0].val == "#" || tokens[0].val == "//")
return true;
return false;
}
// Parse lines of serpent (helper function)
Node parseLines(std::vector<std::string> lines, Metadata metadata, int sp) {
std::vector<Node> o;
int origLine = metadata.ln;
unsigned i = 0;
while (i < lines.size()) {
metadata.ln = origLine + i;
std::string main = lines[i];
if (isLineEmpty(main)) {
i += 1;
continue;
}
int spaces = spaceCount(main);
if (spaces != sp) {
err("Indent mismatch", metadata);
}
// Tokenize current line
std::vector<Node> tokens = tokenize(main.substr(sp), metadata);
// Remove extraneous tokens, including if / elif
std::vector<Node> tokens2;
for (unsigned j = 0; j < tokens.size(); j++) {
if (tokens[j].val == "#" || tokens[j].val == "//") break;
if (j >= 1 || !bodied(tokens[j].val)) {
tokens2.push_back(tokens[j]);
}
}
if (tokens2.size() > 0 && tokens2.back().val == ":")
tokens2.pop_back();
// Parse current line
Node out = parseSerpentTokenStream(tokens2);
// Parse child block
int childIndent = 999999;
std::vector<std::string> childBlock;
while (1) {
i++;
if (i >= lines.size())
break;
bool ile = isLineEmpty(lines[i]);
if (!ile) {
int spaces = spaceCount(lines[i]);
if (spaces <= sp) break;
childBlock.push_back(lines[i]);
if (spaces < childIndent) childIndent = spaces;
}
else childBlock.push_back("");
}
// Child block empty?
bool cbe = true;
for (unsigned i = 0; i < childBlock.size(); i++) {
if (childBlock[i].length() > 0) { cbe = false; break; }
}
// Bring back if / elif into AST
if (bodied(tokens[0].val)) {
std::vector<Node> args;
args.push_back(out);
out = astnode(tokens[0].val, args, out.metadata);
}
// Add child block to AST
if (childBlocked(tokens[0].val)) {
if (cbe)
err("Expected indented child block!", out.metadata);
out.type = ASTNODE;
metadata.ln += 1;
out.args.push_back(parseLines(childBlock, metadata, childIndent));
metadata.ln -= 1;
}
else if (!cbe)
err("Did not expect indented child block!", out.metadata);
if (o.size() == 0 || o.back().type == TOKEN) {
o.push_back(out);
continue;
}
// This is a little complicated. Basically, the idea here is to build
// constructions like [if [< x 5] [a] [elif [< x 10] [b] [else [c]]]]
std::vector<Node> u;
u.push_back(o.back());
if (bodiedContinued(o.back().val, out.val)) {
while (1) {
if (!bodiedContinued(u.back().val, out.val)) {
u.pop_back();
break;
}
if (!u.back().args.size()
|| !bodiedContinued(u.back().val, u.back().args.back().val)) {
break;
}
u.push_back(u.back().args.back());
}
u.back().args.push_back(out);
while (u.size() > 1) {
Node v = u.back();
u.pop_back();
u.back().args.pop_back();
u.back().args.push_back(v);
}
o.pop_back();
o.push_back(u[0]);
}
else o.push_back(out);
}
if (o.size() == 1)
return o[0];
else if (o.size())
return astnode("seq", o, o[0].metadata);
else
return astnode("seq", o, Metadata());
}
// Parses serpent code
Node parseSerpent(std::string s) {
std::string input = s;
std::string file = "main";
if (exists(s)) {
file = s;
input = get_file_contents(s);
}
return parseLines(splitLines(input), Metadata(file, 0, 0), 0);
}
using namespace std;

13
libserpent/parser.h

@ -0,0 +1,13 @@
#ifndef ETHSERP_PARSER
#define ETHSERP_PARSER
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
// Serpent text -> parse tree
Node parseSerpent(std::string s);
#endif

466
libserpent/rewriter.cpp

@ -0,0 +1,466 @@
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
#include "lllparser.h"
#include "bignum.h"
std::string valid[][3] = {
{ "if", "2", "3" },
{ "unless", "2", "2" },
{ "while", "2", "2" },
{ "until", "2", "2" },
{ "code", "1", "2" },
{ "init", "2", "2" },
{ "shared", "2", "3" },
{ "alloc", "1", "1" },
{ "array", "1", "1" },
{ "call", "2", "4" },
{ "create", "1", "4" },
{ "msg", "4", "6" },
{ "getch", "2", "2" },
{ "setch", "3", "3" },
{ "sha3", "1", "2" },
{ "return", "1", "2" },
{ "inset", "1", "1" },
{ "import", "1", "1" },
{ "array_lit", "0", tt256 },
{ "seq", "0", tt256 },
{ "---END---", "", "" } //Keep this line at the end of the list
};
std::string macros[][2] = {
{
"(+= $a $b)",
"(set $a (+ $a $b))"
},
{
"(*= $a $b)",
"(set $a (* $a $b))"
},
{
"(-= $a $b)",
"(set $a (- $a $b))"
},
{
"(/= $a $b)",
"(set $a (/ $a $b))"
},
{
"(%= $a $b)",
"(set $a (% $a $b))"
},
{
"(^= $a $b)",
"(set $a (^ $a $b))"
},
{
"(@/= $a $b)",
"(set $a (@/ $a $b))"
},
{
"(@%= $a $b)",
"(set $a (@% $a $b))"
},
{
"(if $cond $do (else $else))",
"(if $cond $do $else)"
},
{
"(code $code)",
"$code"
},
{
"(access msg.data $ind)",
"(calldataload (mul 32 $ind))"
},
{
"(array $len)",
"(alloc (mul 32 $len))"
},
{
"(while $cond $do)",
"(until (not $cond) $do)",
},
{
"(while (not $cond) $do)",
"(until $cond $do)",
},
{
"(if $cond $do)",
"(unless (not $cond) $do)",
},
{
"(if (not $cond) $do)",
"(unless $cond $do)",
},
{
"(access contract.storage $ind)",
"(sload $ind)"
},
{
"(access $var $ind)",
"(mload (add $var (mul 32 $ind)))"
},
{
"(set (access contract.storage $ind) $val)",
"(sstore $ind $val)"
},
{
"(set (access $var $ind) $val)",
"(mstore (add $var (mul 32 $ind)) $val)"
},
{
"(getch $var $ind)",
"(mod (mload (add $var $ind)) 256)"
},
{
"(setch $var $ind $val)",
"(mstore8 (add $var $ind) $val)",
},
{
"(send $to $value)",
"(call (sub (gas) 25) $to $value 0 0 0 0)"
},
{
"(send $gas $to $value)",
"(call $gas $to $value 0 0 0 0)"
},
{
"(sha3 $x)",
"(seq (set $1 $x) (sha3 (ref $1) 32))"
},
{
"(id $0)",
"$0"
},
{
"(return $x)",
"(seq (set $1 $x) (~return (ref $1) 32))"
},
{
"(return $start $len)",
"(~return $start (mul 32 $len))"
},
{
"(&& $x $y)",
"(if $x $y 0)"
},
{
"(|| $x $y)",
"(seq (set $1 $x) (if (get $1) (get $1) $y))"
},
{
"(>= $x $y)",
"(not (slt $x $y))"
},
{
"(<= $x $y)",
"(not (sgt $x $y))"
},
{
"(@>= $x $y)",
"(not (lt $x $y))"
},
{
"(@<= $x $y)",
"(not (gt $x $y))"
},
{
"(create $code)",
"(create 0 $code)"
},
{
"(create $endowment $code)",
"(seq (set $1 (msize)) (create $endowment (get $1) (lll (outer $code) (msize))))"
},
{
"(call $f $dataval)",
"(msg (sub (gas) 45) $f 0 $dataval)"
},
{
"(call $f $inp $inpsz)",
"(msg (sub (gas) 25) $f 0 $inp $inpsz)"
},
{
"(call $f $inp $inpsz $outsz)",
"(seq (set $1 $outsz) (set $2 (alloc (mul 32 (get $1)))) (pop (call (sub (gas) (add 25 (get $1))) $f 0 $inp (mul 32 $inpsz) (ref $2) (mul 32 (get $1)))) (get $2))"
},
{
"(msg $gas $to $val $inp $inpsz)",
"(seq (call $gas $to $val $inp (mul 32 $inpsz) (ref $1) 32) (get $1))"
},
{
"(msg $gas $to $val $dataval)",
"(seq (set $1 $dataval) (call $gas $to $val (ref $1) 32 (ref $2) 32) (get $2))"
},
{
"(msg $gas $to $val $inp $inpsz $outsz)",
"(seq (set $1 (mul 32 $outsz)) (set $2 (alloc (get $1))) (pop (call $gas $to $val $inp (mul 32 $inpsz) (ref $2) (get $1))) (get $2))"
},
{
"(outer (init $init $code))",
"(seq $init (~return 0 (lll $code 0)))"
},
{
"(outer (shared $shared (init $init (code $code))))",
"(seq $shared $init (~return 0 (lll (seq $shared $code) 0)))"
},
{
"(outer $code)",
"(~return 0 (lll $code 0))"
},
{
"(seq (seq) $x)",
"$x"
},
{
"(inset $x)",
"$x"
},
{
"(create $val (import $code))",
"(seq (set $1 (msize)) (create $val (get $1) (lll $code (get $1))))"
},
{
"(create (import $x))",
"(seq (set $1 (msize)) (create $val (get $1) (lll $code (get $1))))"
},
{
"(create $x)",
"(seq (set $1 (msize)) (create $val (get $1) (lll $code (get $1))))"
},
{ "msg.datasize", "(div (calldatasize) 32)" },
{ "msg.sender", "(caller)" },
{ "msg.value", "(callvalue)" },
{ "tx.gasprice", "(gasprice)" },
{ "tx.origin", "(origin)" },
{ "tx.gas", "(gas)" },
{ "contract.balance", "(balance)" },
{ "contract.address", "(address)" },
{ "block.prevhash", "(prevhash)" },
{ "block.coinbase", "(coinbase)" },
{ "block.timestamp", "(timestamp)" },
{ "block.number", "(number)" },
{ "block.difficulty", "(difficulty)" },
{ "block.gaslimit", "(gaslimit)" },
{ "stop", "(stop)" },
{ "---END---", "" } //Keep this line at the end of the list
};
std::vector<std::vector<Node> > nodeMacros;
std::string synonyms[][2] = {
{ "|", "or" },
{ "or", "||" },
{ "&", "and" },
{ "and", "&&" },
{ "elif", "if" },
{ "!", "not" },
{ "string", "alloc" },
{ "+", "add" },
{ "-", "sub" },
{ "*", "mul" },
{ "/", "sdiv" },
{ "^", "exp" },
{ "**", "exp" },
{ "%", "smod" },
{ "@/", "div" },
{ "@%", "mod" },
{ "@<", "lt" },
{ "@>", "gt" },
{ "<", "slt" },
{ ">", "sgt" },
{ "=", "set" },
{ "==", "eq" },
{ "---END---", "" } //Keep this line at the end of the list
};
struct matchResult {
bool success;
std::map<std::string, Node> map;
};
// Returns two values. First, a boolean to determine whether the node matches
// the pattern, second, if the node does match then a map mapping variables
// in the pattern to nodes
matchResult match(Node p, Node n) {
matchResult o;
o.success = false;
if (p.type == TOKEN) {
if (p.val == n.val) o.success = true;
else if (p.val[0] == '$') {
o.success = true;
o.map[p.val.substr(1)] = n;
}
}
else if (n.type==TOKEN || p.val!=n.val || p.args.size()!=n.args.size()) {
}
else {
for (unsigned i = 0; i < p.args.size(); i++) {
matchResult oPrime = match(p.args[i], n.args[i]);
if (!oPrime.success) {
o.success = false;
return o;
}
for (std::map<std::string, Node>::iterator it = oPrime.map.begin();
it != oPrime.map.end();
it++) {
o.map[(*it).first] = (*it).second;
}
}
o.success = true;
}
return o;
}
// Fills in the pattern with a dictionary mapping variable names to
// nodes (these dicts are generated by match). Match and subst together
// create a full pattern-matching engine.
Node subst(Node pattern,
std::map<std::string, Node> dict,
std::string varflag,
Metadata metadata) {
if (pattern.type == TOKEN && pattern.val[0] == '$') {
if (dict.count(pattern.val.substr(1))) {
return dict[pattern.val.substr(1)];
}
else {
return token(varflag + pattern.val.substr(1), metadata);
}
}
else if (pattern.type == TOKEN) {
return pattern;
}
else {
std::vector<Node> args;
for (unsigned i = 0; i < pattern.args.size(); i++) {
args.push_back(subst(pattern.args[i], dict, varflag, metadata));
}
return astnode(pattern.val, args, metadata);
}
}
// Recursively applies rewrite rules
Node apply_rules(Node node) {
// If the rewrite rules have not yet been parsed, parse them
if (!nodeMacros.size()) {
for (int i = 0; i < 9999; i++) {
std::vector<Node> o;
if (macros[i][0] == "---END---") break;
o.push_back(parseLLL(macros[i][0]));
o.push_back(parseLLL(macros[i][1]));
nodeMacros.push_back(o);
}
}
// Main code
unsigned pos = 0;
std::string prefix = "_temp"+mkUniqueToken()+"_";
while(1) {
if (synonyms[pos][0] == "---END---") {
break;
}
else if (node.type == ASTNODE && node.val == synonyms[pos][0]) {
node.val = synonyms[pos][1];
}
pos++;
}
for (pos = 0; pos < nodeMacros.size(); pos++) {
Node pattern = nodeMacros[pos][0];
matchResult mr = match(pattern, node);
if (mr.success) {
Node pattern2 = nodeMacros[pos][1];
node = subst(pattern2, mr.map, prefix, node.metadata);
}
}
if (node.type == ASTNODE && node.val != "ref" && node.val != "get") {
unsigned i = 0;
if (node.val == "set") i = 1;
for (i = i; i < node.args.size(); i++) {
node.args[i] = apply_rules(node.args[i]);
}
}
else if (node.type == TOKEN && !isNumberLike(node)) {
std::vector<Node> args;
args.push_back(node);
node = astnode("get", args, node.metadata);
}
// This allows people to use ~x as a way of having functions with the same
// name and arity as macros; the idea is that ~x is a "final" form, and
// should not be remacroed, but it is converted back at the end
if (node.type == ASTNODE && node.val[0] == '~')
node.val = node.val.substr(1);
return node;
}
Node optimize(Node inp) {
if (inp.type == TOKEN) return tryNumberize(inp);
for (unsigned i = 0; i < inp.args.size(); i++) {
inp.args[i] = optimize(inp.args[i]);
}
if (inp.args.size() == 2
&& inp.args[0].type == TOKEN
&& inp.args[1].type == TOKEN) {
std::string o;
if (inp.val == "add") {
o = decimalMod(decimalAdd(inp.args[0].val, inp.args[1].val), tt256);
}
else if (inp.val == "sub") {
if (decimalGt(inp.args[0].val, inp.args[1].val, true))
o = decimalSub(inp.args[0].val, inp.args[1].val);
}
else if (inp.val == "mul") {
o = decimalMod(decimalMul(inp.args[0].val, inp.args[1].val), tt256);
}
else if (inp.val == "div" && inp.args[1].val != "0") {
o = decimalDiv(inp.args[0].val, inp.args[1].val);
}
else if (inp.val == "sdiv" && inp.args[1].val != "0"
&& decimalGt(tt255, inp.args[0].val)
&& decimalGt(tt255, inp.args[1].val)) {
o = decimalDiv(inp.args[0].val, inp.args[1].val);
}
else if (inp.val == "mod" && inp.args[1].val != "0") {
o = decimalMod(inp.args[0].val, inp.args[1].val);
}
else if (inp.val == "smod" && inp.args[1].val != "0"
&& decimalGt(tt255, inp.args[0].val)
&& decimalGt(tt255, inp.args[1].val)) {
o = decimalMod(inp.args[0].val, inp.args[1].val);
}
if (o.length()) return token(o, inp.metadata);
}
return inp;
}
Node validate(Node inp) {
if (inp.type == ASTNODE) {
int i = 0;
while(valid[i][0] != "---END---") {
if (inp.val == valid[i][0]) {
if (decimalGt(valid[i][1], intToDecimal(inp.args.size()))) {
err("Too few arguments for "+inp.val, inp.metadata);
}
if (decimalGt(intToDecimal(inp.args.size()), valid[i][2])) {
err("Too many arguments for "+inp.val, inp.metadata);
}
}
i++;
}
}
for (unsigned i = 0; i < inp.args.size(); i++) validate(inp.args[i]);
return inp;
}
Node preprocess(Node inp) {
std::vector<Node> args;
args.push_back(inp);
return astnode("outer", args, inp.metadata);
}
Node rewrite(Node inp) {
return optimize(apply_rules(validate(preprocess(inp))));
}
using namespace std;

13
libserpent/rewriter.h

@ -0,0 +1,13 @@
#ifndef ETHSERP_REWRITER
#define ETHSERP_REWRITER
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
// Applies rewrite rules
Node rewrite(Node inp);
#endif

111
libserpent/tokenize.cpp

@ -0,0 +1,111 @@
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
// These appear as independent tokens even if inside a stream of symbols
const std::string atoms[] = { "#", "//", "(", ")", "[", "]", "{", "}" };
const int numAtoms = 8;
// Is the char alphanumeric, a space, a bracket, a quote, a symbol?
int chartype(char c) {
if (c >= '0' && c <= '9') return ALPHANUM;
else if (c >= 'a' && c <= 'z') return ALPHANUM;
else if (c >= 'A' && c <= 'Z') return ALPHANUM;
else if (std::string("~._$").find(c) != std::string::npos) return ALPHANUM;
else if (c == '\t' || c == ' ' || c == '\n') return SPACE;
else if (std::string("()[]{}").find(c) != std::string::npos) return BRACK;
else if (c == '"') return DQUOTE;
else if (c == '\'') return SQUOTE;
else return SYMB;
}
// "y = f(45,124)/3" -> [ "y", "f", "(", "45", ",", "124", ")", "/", "3"]
std::vector<Node> tokenize(std::string inp, Metadata metadata) {
int curtype = SPACE;
unsigned pos = 0;
int lastNewline = 0;
metadata.ch = 0;
std::string cur;
std::vector<Node> out;
inp += " ";
while (pos < inp.length()) {
int headtype = chartype(inp[pos]);
// Are we inside a quote?
if (curtype == SQUOTE || curtype == DQUOTE) {
// Close quote
if (headtype == curtype) {
cur += inp[pos];
out.push_back(token(cur, metadata));
cur = "";
metadata.ch = pos - lastNewline;
curtype = SPACE;
pos += 1;
}
// eg. \xc3
else if (inp.length() >= pos + 4 && inp.substr(pos, 2) == "\\x") {
cur += (std::string("0123456789abcdef").find(inp[pos+2]) * 16
+ std::string("0123456789abcdef").find(inp[pos+3]));
pos += 4;
}
// Newline
else if (inp.substr(pos, 2) == "\\n") {
cur += '\n';
pos += 2;
}
// Backslash escape
else if (inp.length() >= pos + 2 && inp[pos] == '\\') {
cur += inp[pos + 1];
pos += 2;
}
// Normal character
else {
cur += inp[pos];
pos += 1;
}
}
else {
// Handle atoms ( '//', '#', brackets )
for (int i = 0; i < numAtoms; i++) {
int split = cur.length() - atoms[i].length();
if (split >= 0 && cur.substr(split) == atoms[i]) {
if (split > 0) {
out.push_back(token(cur.substr(0, split), metadata));
}
metadata.ch += split;
out.push_back(token(cur.substr(split), metadata));
metadata.ch = pos - lastNewline;
cur = "";
curtype = SPACE;
}
}
// Special case the minus sign
if (cur.length() > 1 && cur[cur.length() - 1] == '-') {
out.push_back(token(cur.substr(0, cur.length() - 1), metadata));
out.push_back(token("-", metadata));
cur = "";
}
// Boundary between different char types
if (headtype != curtype) {
if (curtype != SPACE && cur != "") {
out.push_back(token(cur, metadata));
}
metadata.ch = pos - lastNewline;
cur = "";
}
cur += inp[pos];
curtype = headtype;
pos += 1;
}
if (inp[pos] == '\n') {
lastNewline = pos;
metadata.ch = 0;
metadata.ln += 1;
}
}
return out;
}

14
libserpent/tokenize.h

@ -0,0 +1,14 @@
#ifndef ETHSERP_TOKENIZE
#define ETHSERP_TOKENIZE
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
int chartype(char c);
std::vector<Node> tokenize(std::string inp, Metadata meta=Metadata());
#endif

256
libserpent/util.cpp

@ -0,0 +1,256 @@
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
#include "bignum.h"
#include <fstream>
#include <cerrno>
//Token or value node constructor
Node token(std::string val, Metadata met) {
Node o;
o.type = 0;
o.val = val;
o.metadata = met;
return o;
}
//AST node constructor
Node astnode(std::string val, std::vector<Node> args, Metadata met) {
Node o;
o.type = 1;
o.val = val;
o.args = args;
o.metadata = met;
return o;
}
// Print token list
std::string printTokens(std::vector<Node> tokens) {
std::string s = "";
for (unsigned i = 0; i < tokens.size(); i++) {
s += tokens[i].val + " ";
}
return s;
}
// Prints a lisp AST on one line
std::string printSimple(Node ast) {
if (ast.type == TOKEN) return ast.val;
std::string o = "(" + ast.val;
std::vector<std::string> subs;
for (unsigned i = 0; i < ast.args.size(); i++) {
o += " " + printSimple(ast.args[i]);
}
return o + ")";
}
// Number of tokens in a tree
int treeSize(Node prog) {
if (prog.type == TOKEN) return 1;
int o = 0;
for (unsigned i = 0; i < prog.args.size(); i++) o += treeSize(prog.args[i]);
return o;
}
// Pretty-prints a lisp AST
std::string printAST(Node ast, bool printMetadata) {
if (ast.type == TOKEN) return ast.val;
std::string o = "(";
if (printMetadata) {
o += ast.metadata.file + " ";
o += intToDecimal(ast.metadata.ln) + " ";
o += intToDecimal(ast.metadata.ch) + ": ";
}
o += ast.val;
std::vector<std::string> subs;
for (unsigned i = 0; i < ast.args.size(); i++) {
subs.push_back(printAST(ast.args[i], printMetadata));
}
unsigned k = 0;
std::string out = " ";
// As many arguments as possible go on the same line as the function,
// except when seq is used
while (k < subs.size() && o != "(seq") {
if (subs[k].find("\n") != std::string::npos || (out + subs[k]).length() >= 80) break;
out += subs[k] + " ";
k += 1;
}
// All remaining arguments go on their own lines
if (k < subs.size()) {
o += out + "\n";
std::vector<std::string> subsSliceK;
for (unsigned i = k; i < subs.size(); i++) subsSliceK.push_back(subs[i]);
o += indentLines(joinLines(subsSliceK));
o += "\n)";
}
else {
o += out.substr(0, out.size() - 1) + ")";
}
return o;
}
// Splits text by line
std::vector<std::string> splitLines(std::string s) {
unsigned pos = 0;
int lastNewline = 0;
std::vector<std::string> o;
while (pos < s.length()) {
if (s[pos] == '\n') {
o.push_back(s.substr(lastNewline, pos - lastNewline));
lastNewline = pos + 1;
}
pos = pos + 1;
}
o.push_back(s.substr(lastNewline));
return o;
}
// Inverse of splitLines
std::string joinLines(std::vector<std::string> lines) {
std::string o = "\n";
for (unsigned i = 0; i < lines.size(); i++) {
o += lines[i] + "\n";
}
return o.substr(1, o.length() - 2);
}
// Indent all lines by 4 spaces
std::string indentLines(std::string inp) {
std::vector<std::string> lines = splitLines(inp);
for (unsigned i = 0; i < lines.size(); i++) lines[i] = " "+lines[i];
return joinLines(lines);
}
// Converts string to simple numeric format
std::string strToNumeric(std::string inp) {
std::string o = "0";
if (inp == "") {
o = "";
}
else if ((inp[0] == '"' && inp[inp.length()-1] == '"')
|| (inp[0] == '\'' && inp[inp.length()-1] == '\'')) {
for (unsigned i = 1; i < inp.length() - 1; i++) {
o = decimalAdd(decimalMul(o,"256"), intToDecimal(inp[i]));
}
}
else if (inp.substr(0,2) == "0x") {
for (unsigned i = 2; i < inp.length(); i++) {
int dig = std::string("0123456789abcdef").find(inp[i]);
if (dig < 0) return "";
o = decimalAdd(decimalMul(o,"16"), intToDecimal(dig));
}
}
else {
bool isPureNum = true;
for (unsigned i = 0; i < inp.length(); i++) {
isPureNum = isPureNum && inp[i] >= '0' && inp[i] <= '9';
}
o = isPureNum ? inp : "";
}
return o;
}
// Does the node contain a number (eg. 124, 0xf012c, "george")
bool isNumberLike(Node node) {
if (node.type == ASTNODE) return false;
return strToNumeric(node.val) != "";
}
//Normalizes number representations
Node nodeToNumeric(Node node) {
std::string o = strToNumeric(node.val);
return token(o == "" ? node.val : o, node.metadata);
}
Node tryNumberize(Node node) {
if (node.type == TOKEN && isNumberLike(node)) return nodeToNumeric(node);
return node;
}
//Converts a value to an array of byte number nodes
std::vector<Node> toByteArr(std::string val, Metadata metadata, int minLen) {
std::vector<Node> o;
int L = 0;
while (val != "0" || L < minLen) {
o.push_back(token(decimalMod(val, "256"), metadata));
val = decimalDiv(val, "256");
L++;
}
std::vector<Node> o2;
for (int i = o.size() - 1; i >= 0; i--) o2.push_back(o[i]);
return o2;
}
int counter = 0;
//Makes a unique token
std::string mkUniqueToken() {
counter++;
return intToDecimal(counter);
}
//Does a file exist? http://stackoverflow.com/questions/12774207
bool exists(std::string fileName) {
std::ifstream infile(fileName.c_str());
return infile.good();
}
//Reads a file: http://stackoverflow.com/questions/2602013
std::string get_file_contents(std::string filename)
{
std::ifstream in(filename.c_str(), std::ios::in | std::ios::binary);
if (in)
{
std::string contents;
in.seekg(0, std::ios::end);
contents.resize(in.tellg());
in.seekg(0, std::ios::beg);
in.read(&contents[0], contents.size());
in.close();
return(contents);
}
throw(errno);
}
//Report error
void err(std::string errtext, Metadata met) {
std::string err = "Error (file \"" + met.file + "\", line " +
intToDecimal(met.ln) + ", char " + intToDecimal(met.ch) +
"): " + errtext;
std::cerr << err << "\n";
throw(err);
}
//Bin to hex
std::string binToHex(std::string inp) {
std::string o = "";
for (unsigned i = 0; i < inp.length(); i++) {
unsigned char v = inp[i];
o += std::string("0123456789abcdef").substr(v/16, 1)
+ std::string("0123456789abcdef").substr(v%16, 1);
}
return o;
}
//Hex to bin
std::string hexToBin(std::string inp) {
std::string o = "";
for (unsigned i = 0; i+1 < inp.length(); i+=2) {
char v = (char)(std::string("0123456789abcdef").find(inp[i]) * 16 +
std::string("0123456789abcdef").find(inp[i+1]));
o += v;
}
return o;
}
//Lower to upper
std::string upperCase(std::string inp) {
std::string o = "";
for (unsigned i = 0; i < inp.length(); i++) {
if (inp[i] >= 97 && inp[i] <= 122) o += inp[i] - 32;
else o += inp[i];
}
return o;
}

106
libserpent/util.h

@ -0,0 +1,106 @@
#ifndef ETHSERP_UTIL
#define ETHSERP_UTIL
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include <fstream>
#include <cerrno>
const int TOKEN = 0,
ASTNODE = 1,
SPACE = 2,
BRACK = 3,
SQUOTE = 4,
DQUOTE = 5,
SYMB = 6,
ALPHANUM = 7,
LPAREN = 8,
RPAREN = 9,
COMMA = 10,
COLON = 11,
UNARY_OP = 12,
BINARY_OP = 13,
COMPOUND = 14;
// Stores metadata about each token
class Metadata {
public:
Metadata(std::string File="main", int Ln=0, int Ch=0) {
file = File;
ln = Ln;
ch = Ch;
}
std::string file;
int ln;
int ch;
};
std::string mkUniqueToken();
// type can be TOKEN or ASTNODE
struct Node {
int type;
std::string val;
std::vector<Node> args;
Metadata metadata;
};
Node token(std::string val, Metadata met=Metadata());
Node astnode(std::string val, std::vector<Node> args, Metadata met=Metadata());
// Number of tokens in a tree
int treeSize(Node prog);
// Print token list
std::string printTokens(std::vector<Node> tokens);
// Prints a lisp AST on one line
std::string printSimple(Node ast);
// Pretty-prints a lisp AST
std::string printAST(Node ast, bool printMetadata=false);
// Splits text by line
std::vector<std::string> splitLines(std::string s);
// Inverse of splitLines
std::string joinLines(std::vector<std::string> lines);
// Indent all lines by 4 spaces
std::string indentLines(std::string inp);
// Converts string to simple numeric format
std::string strToNumeric(std::string inp);
// Does the node contain a number (eg. 124, 0xf012c, "george")
bool isNumberLike(Node node);
//Normalizes number representations
Node nodeToNumeric(Node node);
//If a node is numeric, normalize its representation
Node tryNumberize(Node node);
//Converts a value to an array of byte number nodes
std::vector<Node> toByteArr(std::string val, Metadata metadata, int minLen=1);
//Reads a file
std::string get_file_contents(std::string filename);
//Does a file exist?
bool exists(std::string fileName);
//Report error
void err(std::string errtext, Metadata met);
//Bin to hex
std::string binToHex(std::string inp);
//Hex to bin
std::string hexToBin(std::string inp);
//Lower to upper
std::string upperCase(std::string inp);
#endif

4
lllc/CMakeLists.txt

@ -3,9 +3,6 @@ cmake_policy(SET CMP0015 NEW)
aux_source_directory(. SRC_LIST)
include_directories(..)
#link_directories(../libethsupport)
#link_directories(../libethcore)
#link_directories(../liblll)
set(EXECUTABLE lllc)
@ -47,7 +44,6 @@ endif ()
target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} ethsupport)
target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS})
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
target_link_libraries(${EXECUTABLE} gmp)

6
lllc/main.cpp

@ -23,9 +23,9 @@
#include <fstream>
#include <iostream>
#include <liblll/Compiler.h>
#include <libethsupport/CommonIO.h>
#include <libethsupport/CommonData.h>
#include <libethcore/Instruction.h>
#include <libethential/CommonIO.h>
#include <libethential/CommonData.h>
#include <libevmface/Instruction.h>
#include "BuildInfo.h"
using namespace std;
using namespace eth;

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save