mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #2802 from ethereum/develop
Merge develop into release for 0.4.16
This commit is contained in:
		
						commit
						d7661dd974
					
				@ -8,19 +8,20 @@ include(EthPolicy)
 | 
				
			|||||||
eth_policy()
 | 
					eth_policy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# project name and version should be set after cmake_policy CMP0048
 | 
					# project name and version should be set after cmake_policy CMP0048
 | 
				
			||||||
set(PROJECT_VERSION "0.4.15")
 | 
					set(PROJECT_VERSION "0.4.16")
 | 
				
			||||||
project(solidity VERSION ${PROJECT_VERSION})
 | 
					project(solidity VERSION ${PROJECT_VERSION})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					option(SOLC_LINK_STATIC "Link solc executable statically on supported platforms" OFF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Let's find our dependencies
 | 
					# Let's find our dependencies
 | 
				
			||||||
include(EthDependencies)
 | 
					include(EthDependencies)
 | 
				
			||||||
include(deps/jsoncpp.cmake)
 | 
					include(deps/jsoncpp.cmake)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					find_package(Threads)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Figure out what compiler and system are we using
 | 
					# Figure out what compiler and system are we using
 | 
				
			||||||
include(EthCompilerSettings)
 | 
					include(EthCompilerSettings)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Include helper macros
 | 
					 | 
				
			||||||
include(EthExecutableHelper)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Include utils
 | 
					# Include utils
 | 
				
			||||||
include(EthUtils)
 | 
					include(EthUtils)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										30
									
								
								Changelog.md
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								Changelog.md
									
									
									
									
									
								
							@ -1,3 +1,33 @@
 | 
				
			|||||||
 | 
					### 0.4.16 (2017-08-24)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Features:
 | 
				
			||||||
 | 
					 * ABI JSON: Include new field ``stateMutability`` with values ``pure``, ``view``,
 | 
				
			||||||
 | 
					   ``nonpayable`` and ``payable``.
 | 
				
			||||||
 | 
					 * Analyzer: Experimental partial support for Z3 SMT checker ("SMTChecker").
 | 
				
			||||||
 | 
					 * Build System: Shared libraries (``libdevcore``, ``libevmasm``, ``libsolidity``
 | 
				
			||||||
 | 
					   and ``liblll``) are no longer produced during the build process.
 | 
				
			||||||
 | 
					 * Code generator: Experimental new implementation of ABI encoder that can
 | 
				
			||||||
 | 
					   encode arbitrarily nested arrays ("ABIEncoderV2")
 | 
				
			||||||
 | 
					 * Metadata: Store experimental flag in metadata CBOR.
 | 
				
			||||||
 | 
					 * Parser: Display previous visibility specifier in error if multiple are found.
 | 
				
			||||||
 | 
					 * Parser: Introduce ``pure`` and ``view`` keyword for functions,
 | 
				
			||||||
 | 
					   ``constant`` remains an alias for ``view`` and pureness is not enforced yet,
 | 
				
			||||||
 | 
					   so use with care.
 | 
				
			||||||
 | 
					 * Static Analyzer: Warn about large storage structures.
 | 
				
			||||||
 | 
					 * Syntax Checker: Support ``pragma experimental <feature>;`` to turn on
 | 
				
			||||||
 | 
					   experimental features.
 | 
				
			||||||
 | 
					 * Type Checker: More detailed error message for invalid overrides.
 | 
				
			||||||
 | 
					 * Type Checker: Warn about shifting a literal.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Bugfixes:
 | 
				
			||||||
 | 
					 * Assembly Parser: Be more strict about number literals.
 | 
				
			||||||
 | 
					 * Assembly Parser: Limit maximum recursion depth.
 | 
				
			||||||
 | 
					 * Parser: Enforce commas between array and tuple elements.
 | 
				
			||||||
 | 
					 * Parser: Limit maximum recursion depth.
 | 
				
			||||||
 | 
					 * Type Checker: Crash fix related to ``using``.
 | 
				
			||||||
 | 
					 * Type Checker: Disallow constructors in libraries.
 | 
				
			||||||
 | 
					 * Type Checker: Reject the creation of interface contracts using the ``new`` statement.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 0.4.15 (2017-08-08)
 | 
					### 0.4.15 (2017-08-08)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Features:
 | 
					Features:
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										10
									
								
								circle.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								circle.yml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					version: 2
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  build:
 | 
				
			||||||
 | 
					    branches:
 | 
				
			||||||
 | 
					      ignore:
 | 
				
			||||||
 | 
					        - /.*/
 | 
				
			||||||
 | 
					    docker:
 | 
				
			||||||
 | 
					      - image: trzeci/emscripten:sdk-tag-1.37.18-64bit
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - checkout
 | 
				
			||||||
@ -1,161 +0,0 @@
 | 
				
			|||||||
#.rst:
 | 
					 | 
				
			||||||
# CMakeParseArguments
 | 
					 | 
				
			||||||
# -------------------
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords>
 | 
					 | 
				
			||||||
# <multi_value_keywords> args...)
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions
 | 
					 | 
				
			||||||
# for parsing the arguments given to that macro or function.  It
 | 
					 | 
				
			||||||
# processes the arguments and defines a set of variables which hold the
 | 
					 | 
				
			||||||
# values of the respective options.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# The <options> argument contains all options for the respective macro,
 | 
					 | 
				
			||||||
# i.e.  keywords which can be used when calling the macro without any
 | 
					 | 
				
			||||||
# value following, like e.g.  the OPTIONAL keyword of the install()
 | 
					 | 
				
			||||||
# command.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# The <one_value_keywords> argument contains all keywords for this macro
 | 
					 | 
				
			||||||
# which are followed by one value, like e.g.  DESTINATION keyword of the
 | 
					 | 
				
			||||||
# install() command.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# The <multi_value_keywords> argument contains all keywords for this
 | 
					 | 
				
			||||||
# macro which can be followed by more than one value, like e.g.  the
 | 
					 | 
				
			||||||
# TARGETS or FILES keywords of the install() command.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the
 | 
					 | 
				
			||||||
# keywords listed in <options>, <one_value_keywords> and
 | 
					 | 
				
			||||||
# <multi_value_keywords> a variable composed of the given <prefix>
 | 
					 | 
				
			||||||
# followed by "_" and the name of the respective keyword.  These
 | 
					 | 
				
			||||||
# variables will then hold the respective value from the argument list.
 | 
					 | 
				
			||||||
# For the <options> keywords this will be TRUE or FALSE.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# All remaining arguments are collected in a variable
 | 
					 | 
				
			||||||
# <prefix>_UNPARSED_ARGUMENTS, this can be checked afterwards to see
 | 
					 | 
				
			||||||
# whether your macro was called with unrecognized parameters.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# As an example here a my_install() macro, which takes similar arguments
 | 
					 | 
				
			||||||
# as the real install() command:
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# ::
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#    function(MY_INSTALL)
 | 
					 | 
				
			||||||
#      set(options OPTIONAL FAST)
 | 
					 | 
				
			||||||
#      set(oneValueArgs DESTINATION RENAME)
 | 
					 | 
				
			||||||
#      set(multiValueArgs TARGETS CONFIGURATIONS)
 | 
					 | 
				
			||||||
#      cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}"
 | 
					 | 
				
			||||||
#                            "${multiValueArgs}" ${ARGN} )
 | 
					 | 
				
			||||||
#      ...
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Assume my_install() has been called like this:
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# ::
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#    my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# After the cmake_parse_arguments() call the macro will have set the
 | 
					 | 
				
			||||||
# following variables:
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# ::
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#    MY_INSTALL_OPTIONAL = TRUE
 | 
					 | 
				
			||||||
#    MY_INSTALL_FAST = FALSE (this option was not used when calling my_install()
 | 
					 | 
				
			||||||
#    MY_INSTALL_DESTINATION = "bin"
 | 
					 | 
				
			||||||
#    MY_INSTALL_RENAME = "" (was not used)
 | 
					 | 
				
			||||||
#    MY_INSTALL_TARGETS = "foo;bar"
 | 
					 | 
				
			||||||
#    MY_INSTALL_CONFIGURATIONS = "" (was not used)
 | 
					 | 
				
			||||||
#    MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL"
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# You can then continue and process these variables.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Keywords terminate lists of values, e.g.  if directly after a
 | 
					 | 
				
			||||||
# one_value_keyword another recognized keyword follows, this is
 | 
					 | 
				
			||||||
# interpreted as the beginning of the new option.  E.g.
 | 
					 | 
				
			||||||
# my_install(TARGETS foo DESTINATION OPTIONAL) would result in
 | 
					 | 
				
			||||||
# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION
 | 
					 | 
				
			||||||
# would be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#=============================================================================
 | 
					 | 
				
			||||||
# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Distributed under the OSI-approved BSD License (the "License");
 | 
					 | 
				
			||||||
# see accompanying file Copyright.txt for details.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
 | 
					 | 
				
			||||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | 
					 | 
				
			||||||
# See the License for more information.
 | 
					 | 
				
			||||||
#=============================================================================
 | 
					 | 
				
			||||||
# (To distribute this file outside of CMake, substitute the full
 | 
					 | 
				
			||||||
#  License text for the above reference.)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if(__CMAKE_PARSE_ARGUMENTS_INCLUDED)
 | 
					 | 
				
			||||||
  return()
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames)
 | 
					 | 
				
			||||||
  # first set all result variables to empty/FALSE
 | 
					 | 
				
			||||||
  foreach(arg_name ${_singleArgNames} ${_multiArgNames})
 | 
					 | 
				
			||||||
    set(${prefix}_${arg_name})
 | 
					 | 
				
			||||||
  endforeach()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  foreach(option ${_optionNames})
 | 
					 | 
				
			||||||
    set(${prefix}_${option} FALSE)
 | 
					 | 
				
			||||||
  endforeach()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  set(${prefix}_UNPARSED_ARGUMENTS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  set(insideValues FALSE)
 | 
					 | 
				
			||||||
  set(currentArgName)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # now iterate over all arguments and fill the result variables
 | 
					 | 
				
			||||||
  foreach(currentArg ${ARGN})
 | 
					 | 
				
			||||||
    list(FIND _optionNames "${currentArg}" optionIndex)  # ... then this marks the end of the arguments belonging to this keyword
 | 
					 | 
				
			||||||
    list(FIND _singleArgNames "${currentArg}" singleArgIndex)  # ... then this marks the end of the arguments belonging to this keyword
 | 
					 | 
				
			||||||
    list(FIND _multiArgNames "${currentArg}" multiArgIndex)  # ... then this marks the end of the arguments belonging to this keyword
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(${optionIndex} EQUAL -1  AND  ${singleArgIndex} EQUAL -1  AND  ${multiArgIndex} EQUAL -1)
 | 
					 | 
				
			||||||
      if(insideValues)
 | 
					 | 
				
			||||||
        if("${insideValues}" STREQUAL "SINGLE")
 | 
					 | 
				
			||||||
          set(${prefix}_${currentArgName} ${currentArg})
 | 
					 | 
				
			||||||
          set(insideValues FALSE)
 | 
					 | 
				
			||||||
        elseif("${insideValues}" STREQUAL "MULTI")
 | 
					 | 
				
			||||||
          list(APPEND ${prefix}_${currentArgName} ${currentArg})
 | 
					 | 
				
			||||||
        endif()
 | 
					 | 
				
			||||||
      else()
 | 
					 | 
				
			||||||
        list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg})
 | 
					 | 
				
			||||||
      endif()
 | 
					 | 
				
			||||||
    else()
 | 
					 | 
				
			||||||
      if(NOT ${optionIndex} EQUAL -1)
 | 
					 | 
				
			||||||
        set(${prefix}_${currentArg} TRUE)
 | 
					 | 
				
			||||||
        set(insideValues FALSE)
 | 
					 | 
				
			||||||
      elseif(NOT ${singleArgIndex} EQUAL -1)
 | 
					 | 
				
			||||||
        set(currentArgName ${currentArg})
 | 
					 | 
				
			||||||
        set(${prefix}_${currentArgName})
 | 
					 | 
				
			||||||
        set(insideValues "SINGLE")
 | 
					 | 
				
			||||||
      elseif(NOT ${multiArgIndex} EQUAL -1)
 | 
					 | 
				
			||||||
        set(currentArgName ${currentArg})
 | 
					 | 
				
			||||||
        set(${prefix}_${currentArgName})
 | 
					 | 
				
			||||||
        set(insideValues "MULTI")
 | 
					 | 
				
			||||||
      endif()
 | 
					 | 
				
			||||||
    endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  endforeach()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # propagate the result variables to the caller:
 | 
					 | 
				
			||||||
  foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames})
 | 
					 | 
				
			||||||
    set(${prefix}_${arg_name}  ${${prefix}_${arg_name}} PARENT_SCOPE)
 | 
					 | 
				
			||||||
  endforeach()
 | 
					 | 
				
			||||||
  set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
endfunction()
 | 
					 | 
				
			||||||
@ -22,6 +22,18 @@ if(CCACHE_FOUND)
 | 
				
			|||||||
	message("Using ccache")
 | 
						message("Using ccache")
 | 
				
			||||||
endif(CCACHE_FOUND)
 | 
					endif(CCACHE_FOUND)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include(CheckCXXCompilerFlag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					check_cxx_compiler_flag(-fstack-protector-strong have_stack_protector_strong)
 | 
				
			||||||
 | 
					if (have_stack_protector_strong)
 | 
				
			||||||
 | 
						add_compile_options(-fstack-protector-strong)
 | 
				
			||||||
 | 
					else()
 | 
				
			||||||
 | 
						check_cxx_compiler_flag(-fstack-protector have_stack_protector)
 | 
				
			||||||
 | 
						if(have_stack_protector)
 | 
				
			||||||
 | 
							add_compile_options(-fstack-protector)
 | 
				
			||||||
 | 
						endif()
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
 | 
					if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# Use ISO C++11 standard language.
 | 
						# Use ISO C++11 standard language.
 | 
				
			||||||
@ -63,13 +75,6 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
 | 
				
			|||||||
	# Applying -fpermissive to a C command-line (ie. secp256k1) gives a build error.
 | 
						# Applying -fpermissive to a C command-line (ie. secp256k1) gives a build error.
 | 
				
			||||||
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
 | 
						set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# Build everything as shared libraries (.so files)
 | 
					 | 
				
			||||||
	add_definitions(-DSHAREDLIB)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# If supported for the target machine, emit position-independent code, suitable for dynamic
 | 
					 | 
				
			||||||
	# linking and avoiding any limit on the size of the global offset table.
 | 
					 | 
				
			||||||
	add_compile_options(-fPIC)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# Configuration-specific compiler settings.
 | 
						# Configuration-specific compiler settings.
 | 
				
			||||||
	set(CMAKE_CXX_FLAGS_DEBUG          "-O0 -g -DETH_DEBUG")
 | 
						set(CMAKE_CXX_FLAGS_DEBUG          "-O0 -g -DETH_DEBUG")
 | 
				
			||||||
	set(CMAKE_CXX_FLAGS_MINSIZEREL     "-Os -DNDEBUG")
 | 
						set(CMAKE_CXX_FLAGS_MINSIZEREL     "-Os -DNDEBUG")
 | 
				
			||||||
@ -86,14 +91,6 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
 | 
				
			|||||||
			message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.")
 | 
								message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.")
 | 
				
			||||||
		endif ()
 | 
							endif ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Strong stack protection was only added in GCC 4.9.
 | 
					 | 
				
			||||||
		# Use it if we have the option to do so.
 | 
					 | 
				
			||||||
		# See https://lwn.net/Articles/584225/
 | 
					 | 
				
			||||||
		if (GCC_VERSION VERSION_GREATER 4.9 OR GCC_VERSION VERSION_EQUAL 4.9)
 | 
					 | 
				
			||||||
			add_compile_options(-fstack-protector-strong)
 | 
					 | 
				
			||||||
			add_compile_options(-fstack-protector)
 | 
					 | 
				
			||||||
		endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Until https://github.com/ethereum/solidity/issues/2479 is handled
 | 
							# Until https://github.com/ethereum/solidity/issues/2479 is handled
 | 
				
			||||||
		# disable all implicit fallthrough warnings in the codebase for GCC > 7.0
 | 
							# disable all implicit fallthrough warnings in the codebase for GCC > 7.0
 | 
				
			||||||
		if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
 | 
							if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
 | 
				
			||||||
@ -103,31 +100,6 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
 | 
				
			|||||||
	# Additional Clang-specific compiler settings.
 | 
						# Additional Clang-specific compiler settings.
 | 
				
			||||||
	elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
 | 
						elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		add_compile_options(-fstack-protector)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Enable strong stack protection only on Mac and only for OS X Yosemite
 | 
					 | 
				
			||||||
		# or newer (AppleClang 7.0+).  We should be able to re-enable this setting
 | 
					 | 
				
			||||||
		# on non-Apple Clang as well, if we can work out what expression to use for
 | 
					 | 
				
			||||||
		# the version detection.
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		# The fact that the version-reporting for AppleClang loses the original
 | 
					 | 
				
			||||||
		# Clang versioning is rather annoying.  Ideally we could just have
 | 
					 | 
				
			||||||
		# a single cross-platform "if version >= 3.4.1" check.
 | 
					 | 
				
			||||||
		#
 | 
					 | 
				
			||||||
		# There is debug text in the else clause below, to help us work out what
 | 
					 | 
				
			||||||
		# such an expression should be, if we can get this running on a Trusty box
 | 
					 | 
				
			||||||
		# with Clang.  Greg Colvin previously replicated the issue there too.
 | 
					 | 
				
			||||||
		#
 | 
					 | 
				
			||||||
		# See https://github.com/ethereum/webthree-umbrella/issues/594
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (APPLE)
 | 
					 | 
				
			||||||
			if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
 | 
					 | 
				
			||||||
				add_compile_options(-fstack-protector-strong)
 | 
					 | 
				
			||||||
			endif()
 | 
					 | 
				
			||||||
		else()
 | 
					 | 
				
			||||||
			message(WARNING "CMAKE_CXX_COMPILER_VERSION = ${CMAKE_CXX_COMPILER_VERSION}")
 | 
					 | 
				
			||||||
		endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# A couple of extra warnings suppressions which we seemingly
 | 
							# A couple of extra warnings suppressions which we seemingly
 | 
				
			||||||
		# need when building with Clang.
 | 
							# need when building with Clang.
 | 
				
			||||||
		#
 | 
							#
 | 
				
			||||||
@ -198,7 +170,6 @@ elseif (DEFINED MSVC)
 | 
				
			|||||||
	add_compile_options(/wd4800)					# disable forcing value to bool 'true' or 'false' (performance warning) (4800)
 | 
						add_compile_options(/wd4800)					# disable forcing value to bool 'true' or 'false' (performance warning) (4800)
 | 
				
			||||||
	add_compile_options(-D_WIN32_WINNT=0x0600)		# declare Windows Vista API requirement
 | 
						add_compile_options(-D_WIN32_WINNT=0x0600)		# declare Windows Vista API requirement
 | 
				
			||||||
	add_compile_options(-DNOMINMAX)					# undefine windows.h MAX && MIN macros cause it cause conflicts with std::min && std::max functions
 | 
						add_compile_options(-DNOMINMAX)					# undefine windows.h MAX && MIN macros cause it cause conflicts with std::min && std::max functions
 | 
				
			||||||
	add_compile_options(-DMINIUPNP_STATICLIB)		# define miniupnp static library
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# Always use Release variant of C++ runtime.
 | 
						# Always use Release variant of C++ runtime.
 | 
				
			||||||
	# We don't want to provide Debug variants of all dependencies. Some default
 | 
						# We don't want to provide Debug variants of all dependencies. Some default
 | 
				
			||||||
@ -218,12 +189,6 @@ elseif (DEFINED MSVC)
 | 
				
			|||||||
	# stack size 16MB
 | 
						# stack size 16MB
 | 
				
			||||||
	set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216")
 | 
						set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# windows likes static
 | 
					 | 
				
			||||||
	if (NOT ETH_STATIC)
 | 
					 | 
				
			||||||
		message("Forcing static linkage for MSVC.")
 | 
					 | 
				
			||||||
		set(ETH_STATIC 1)
 | 
					 | 
				
			||||||
	endif ()
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
# If you don't have GCC, Clang or VC++ then you are on your own.  Good luck!
 | 
					# If you don't have GCC, Clang or VC++ then you are on your own.  Good luck!
 | 
				
			||||||
else ()
 | 
					else ()
 | 
				
			||||||
	message(WARNING "Your compiler is not tested, if you run into any issues, we'd welcome any patches.")
 | 
						message(WARNING "Your compiler is not tested, if you run into any issues, we'd welcome any patches.")
 | 
				
			||||||
@ -262,9 +227,3 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
 | 
				
			|||||||
		endif ()
 | 
							endif ()
 | 
				
			||||||
	endif ()
 | 
						endif ()
 | 
				
			||||||
endif ()
 | 
					endif ()
 | 
				
			||||||
 | 
					 | 
				
			||||||
if(ETH_STATIC)
 | 
					 | 
				
			||||||
	set(BUILD_SHARED_LIBS OFF)
 | 
					 | 
				
			||||||
else()
 | 
					 | 
				
			||||||
	set(BUILD_SHARED_LIBS ON)
 | 
					 | 
				
			||||||
endif(ETH_STATIC)
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -43,62 +43,9 @@ find_program(CTEST_COMMAND ctest)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## use multithreaded boost libraries, with -mt suffix
 | 
					## use multithreaded boost libraries, with -mt suffix
 | 
				
			||||||
set(Boost_USE_MULTITHREADED ON)
 | 
					set(Boost_USE_MULTITHREADED ON)
 | 
				
			||||||
 | 
					option(Boost_USE_STATIC_LIBS "Link Boost statically" ON)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 | 
					find_package(Boost 1.54.0 QUIET REQUIRED COMPONENTS regex filesystem unit_test_framework program_options system)
 | 
				
			||||||
 | 
					 | 
				
			||||||
# use static boost libraries *.lib
 | 
					 | 
				
			||||||
	set(Boost_USE_STATIC_LIBS ON)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
elseif (APPLE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# use static boost libraries *.a
 | 
					 | 
				
			||||||
	set(Boost_USE_STATIC_LIBS ON)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
elseif (UNIX)
 | 
					 | 
				
			||||||
# use dynamic boost libraries *.dll
 | 
					 | 
				
			||||||
	set(Boost_USE_STATIC_LIBS OFF)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set(STATIC_LINKING FALSE CACHE BOOL "Build static binaries")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (STATIC_LINKING)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set(Boost_USE_STATIC_LIBS ON)
 | 
					 | 
				
			||||||
	set(Boost_USE_STATIC_RUNTIME ON)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set(OpenSSL_USE_STATIC_LIBS ON)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (MSVC)
 | 
					 | 
				
			||||||
		# TODO - Why would we need .a on Windows?  Maybe some Cygwin-ism.
 | 
					 | 
				
			||||||
		# When I work through Windows static linkage, I will remove this,
 | 
					 | 
				
			||||||
		# if that is possible.
 | 
					 | 
				
			||||||
		set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
 | 
					 | 
				
			||||||
	elseif (APPLE)
 | 
					 | 
				
			||||||
		# At the time of writing, we are still only PARTIALLY statically linked
 | 
					 | 
				
			||||||
		# on OS X, with a mixture of statically linked external libraries where
 | 
					 | 
				
			||||||
		# those are available, and dynamically linked where that is the only
 | 
					 | 
				
			||||||
		# option we have.    Ultimately, the aim would be for everything except
 | 
					 | 
				
			||||||
		# the runtime libraries to be statically linked.
 | 
					 | 
				
			||||||
		#
 | 
					 | 
				
			||||||
		# Still TODO:
 | 
					 | 
				
			||||||
		# - jsoncpp
 | 
					 | 
				
			||||||
		# - json-rpc-cpp
 | 
					 | 
				
			||||||
		# - leveldb (which pulls in snappy, for the dylib at ;east)
 | 
					 | 
				
			||||||
		# - miniupnp
 | 
					 | 
				
			||||||
		# - gmp
 | 
					 | 
				
			||||||
		#
 | 
					 | 
				
			||||||
		# Two further libraries (curl and zlib) ship as dylibs with the platform
 | 
					 | 
				
			||||||
		# but again we could build from source and statically link these too.
 | 
					 | 
				
			||||||
		set(CMAKE_FIND_LIBRARY_SUFFIXES .a .dylib)
 | 
					 | 
				
			||||||
	else()
 | 
					 | 
				
			||||||
		set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set(ETH_STATIC ON)
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
find_package(Boost 1.54.0 QUIET REQUIRED COMPONENTS thread date_time system regex chrono filesystem unit_test_framework program_options random)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
eth_show_dependency(Boost boost)
 | 
					eth_show_dependency(Boost boost)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -108,29 +55,3 @@ if (APPLE)
 | 
				
			|||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include_directories(BEFORE "${PROJECT_BINARY_DIR}/include")
 | 
					include_directories(BEFORE "${PROJECT_BINARY_DIR}/include")
 | 
				
			||||||
 | 
					 | 
				
			||||||
function(eth_use TARGET REQUIRED)
 | 
					 | 
				
			||||||
	if (NOT TARGET ${TARGET})
 | 
					 | 
				
			||||||
		message(FATAL_ERROR "eth_use called for non existing target ${TARGET}")
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (TARGET ${PROJECT_NAME}_BuildInfo.h)
 | 
					 | 
				
			||||||
		add_dependencies(${TARGET} ${PROJECT_NAME}_BuildInfo.h)
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	foreach(MODULE ${ARGN})
 | 
					 | 
				
			||||||
		string(REPLACE "::" ";" MODULE_PARTS "${MODULE}")
 | 
					 | 
				
			||||||
		list(GET MODULE_PARTS 0 MODULE_MAIN)
 | 
					 | 
				
			||||||
		list(LENGTH MODULE_PARTS MODULE_LENGTH)
 | 
					 | 
				
			||||||
		if (MODULE_LENGTH GREATER 1)
 | 
					 | 
				
			||||||
			list(GET MODULE_PARTS 1 MODULE_SUB)
 | 
					 | 
				
			||||||
		endif()
 | 
					 | 
				
			||||||
		# TODO: check if file exists if not, throws FATAL_ERROR with detailed description
 | 
					 | 
				
			||||||
		get_target_property(TARGET_APPLIED ${TARGET} TARGET_APPLIED_${MODULE_MAIN}_${MODULE_SUB})
 | 
					 | 
				
			||||||
		if (NOT TARGET_APPLIED)
 | 
					 | 
				
			||||||
			include(Use${MODULE_MAIN})
 | 
					 | 
				
			||||||
			set_target_properties(${TARGET} PROPERTIES TARGET_APPLIED_${MODULE_MAIN}_${MODULE_SUB} TRUE)
 | 
					 | 
				
			||||||
			eth_apply(${TARGET} ${REQUIRED} ${MODULE_SUB})
 | 
					 | 
				
			||||||
		endif()
 | 
					 | 
				
			||||||
	endforeach()
 | 
					 | 
				
			||||||
endfunction()
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,143 +0,0 @@
 | 
				
			|||||||
#
 | 
					 | 
				
			||||||
# this function requires the following variables to be specified:
 | 
					 | 
				
			||||||
# ETH_VERSION
 | 
					 | 
				
			||||||
# PROJECT_NAME
 | 
					 | 
				
			||||||
# PROJECT_VERSION
 | 
					 | 
				
			||||||
# PROJECT_COPYRIGHT_YEAR
 | 
					 | 
				
			||||||
# PROJECT_VENDOR
 | 
					 | 
				
			||||||
# PROJECT_DOMAIN_SECOND
 | 
					 | 
				
			||||||
# PROJECT_DOMAIN_FIRST
 | 
					 | 
				
			||||||
# SRC_LIST
 | 
					 | 
				
			||||||
# HEADERS
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# params:
 | 
					 | 
				
			||||||
# ICON
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
macro(eth_add_executable EXECUTABLE)
 | 
					 | 
				
			||||||
	set (extra_macro_args ${ARGN})
 | 
					 | 
				
			||||||
	set (options)
 | 
					 | 
				
			||||||
	set (one_value_args ICON)
 | 
					 | 
				
			||||||
	set (multi_value_args UI_RESOURCES WIN_RESOURCES)
 | 
					 | 
				
			||||||
	cmake_parse_arguments (ETH_ADD_EXECUTABLE "${options}" "${one_value_args}" "${multi_value_args}" "${extra_macro_args}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (APPLE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		add_executable(${EXECUTABLE} MACOSX_BUNDLE ${SRC_LIST} ${HEADERS} ${ETH_ADD_EXECUTABLE_UI_RESOURCES})
 | 
					 | 
				
			||||||
		set(PROJECT_VERSION "${ETH_VERSION}")
 | 
					 | 
				
			||||||
		set(MACOSX_BUNDLE_INFO_STRING "${PROJECT_NAME} ${PROJECT_VERSION}")
 | 
					 | 
				
			||||||
		set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_NAME} ${PROJECT_VERSION}")
 | 
					 | 
				
			||||||
		set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_NAME} ${PROJECT_VERSION}")
 | 
					 | 
				
			||||||
		set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}")
 | 
					 | 
				
			||||||
		set(MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT_YEAR} ${PROJECT_VENDOR}")
 | 
					 | 
				
			||||||
		set(MACOSX_BUNDLE_GUI_IDENTIFIER "${PROJECT_DOMAIN_SECOND}.${PROJECT_DOMAIN_FIRST}")
 | 
					 | 
				
			||||||
		set(MACOSX_BUNDLE_BUNDLE_NAME ${EXECUTABLE})
 | 
					 | 
				
			||||||
		set(MACOSX_BUNDLE_ICON_FILE ${ETH_ADD_EXECUTABLE_ICON})
 | 
					 | 
				
			||||||
		set_target_properties(${EXECUTABLE} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/EthereumMacOSXBundleInfo.plist.in")
 | 
					 | 
				
			||||||
		set_source_files_properties(${EXECUTABLE} PROPERTIES MACOSX_PACKAGE_LOCATION MacOS)
 | 
					 | 
				
			||||||
		set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/${MACOSX_BUNDLE_ICON_FILE}.icns" PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	else ()
 | 
					 | 
				
			||||||
		add_executable(${EXECUTABLE} ${ETH_ADD_EXECUTABLE_UI_RESOURCES}  ${ETH_ADD_EXECUTABLE_WIN_RESOURCES} ${SRC_LIST} ${HEADERS})
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
endmacro()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
macro(eth_simple_add_executable EXECUTABLE)
 | 
					 | 
				
			||||||
	add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# Apple does not support statically linked binaries on OS X.   That means
 | 
					 | 
				
			||||||
	# that we can only statically link against our external libraries, but
 | 
					 | 
				
			||||||
	# we cannot statically link against the C++ runtime libraries and other
 | 
					 | 
				
			||||||
	# platform libraries (as is possible on Windows and Alpine Linux) to produce
 | 
					 | 
				
			||||||
	# an entirely transportable binary.
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	# See https://developer.apple.com/library/mac/qa/qa1118/_index.html for more info.
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	# GLIBC also appears not to support static linkage too, which probably means that
 | 
					 | 
				
			||||||
	# Debian and Ubuntu will only be able to do partially-statically linked
 | 
					 | 
				
			||||||
	# executables too, just like OS X.
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	# For OS X, at the time of writing, we are left with the following dynamically
 | 
					 | 
				
			||||||
	# linked dependencies, of which curl and libz might still be fixable:
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	# /usr/lib/libc++.1.dylib
 | 
					 | 
				
			||||||
	# /usr/lib/libSystem.B.dylib
 | 
					 | 
				
			||||||
	# /usr/lib/libcurl.4.dylib
 | 
					 | 
				
			||||||
	# /usr/lib/libz.1.dylib
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	if (STATIC_LINKING AND NOT APPLE)
 | 
					 | 
				
			||||||
		set(CMAKE_EXE_LINKER_FLAGS "-static ${CMAKE_EXE_LINKER_FLAGS}")
 | 
					 | 
				
			||||||
		set_target_properties(${EXECUTABLE} PROPERTIES LINK_SEARCH_START_STATIC 1)
 | 
					 | 
				
			||||||
		set_target_properties(${EXECUTABLE} PROPERTIES LINK_SEARCH_END_STATIC 1)
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
endmacro()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
macro(eth_copy_dll EXECUTABLE DLL)
 | 
					 | 
				
			||||||
	# dlls must be unsubstitud list variable (without ${}) in format
 | 
					 | 
				
			||||||
	# optimized;path_to_dll.dll;debug;path_to_dlld.dll
 | 
					 | 
				
			||||||
	if(DEFINED MSVC)
 | 
					 | 
				
			||||||
		list(GET ${DLL} 1 DLL_RELEASE)
 | 
					 | 
				
			||||||
		list(GET ${DLL} 3 DLL_DEBUG)
 | 
					 | 
				
			||||||
		add_custom_command(TARGET ${EXECUTABLE}
 | 
					 | 
				
			||||||
			PRE_BUILD
 | 
					 | 
				
			||||||
			COMMAND ${CMAKE_COMMAND} ARGS
 | 
					 | 
				
			||||||
			-DDLL_RELEASE="${DLL_RELEASE}"
 | 
					 | 
				
			||||||
			-DDLL_DEBUG="${DLL_DEBUG}"
 | 
					 | 
				
			||||||
			-DCONF="$<CONFIGURATION>"
 | 
					 | 
				
			||||||
			-DDESTINATION="${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
 | 
					 | 
				
			||||||
			-P "${ETH_SCRIPTS_DIR}/copydlls.cmake"
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
endmacro()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
macro(eth_copy_dlls EXECUTABLE)
 | 
					 | 
				
			||||||
	foreach(dll ${ARGN})
 | 
					 | 
				
			||||||
		eth_copy_dll(${EXECUTABLE} ${dll})
 | 
					 | 
				
			||||||
	endforeach(dll)
 | 
					 | 
				
			||||||
endmacro()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
macro(eth_install_executable EXECUTABLE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (APPLE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# TODO - Why is this different than the branch Linux below, which has the RUNTIME keyword too?
 | 
					 | 
				
			||||||
		install(TARGETS ${EXECUTABLE} DESTINATION bin)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	elseif (DEFINED MSVC)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		set(COMPONENT ${EXECUTABLE})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Debug/"
 | 
					 | 
				
			||||||
			DESTINATION .
 | 
					 | 
				
			||||||
			CONFIGURATIONS Debug
 | 
					 | 
				
			||||||
			COMPONENT ${COMPONENT}
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Release/"
 | 
					 | 
				
			||||||
			DESTINATION .
 | 
					 | 
				
			||||||
			CONFIGURATIONS Release
 | 
					 | 
				
			||||||
			COMPONENT ${COMPONENT}
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/"
 | 
					 | 
				
			||||||
			DESTINATION .
 | 
					 | 
				
			||||||
			CONFIGURATIONS RelWithDebInfo
 | 
					 | 
				
			||||||
			COMPONENT ${COMPONENT}
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	else()
 | 
					 | 
				
			||||||
		install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin)
 | 
					 | 
				
			||||||
	endif ()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
endmacro()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
macro (eth_name KEY VALUE)
 | 
					 | 
				
			||||||
	if (NOT (APPLE OR WIN32))
 | 
					 | 
				
			||||||
		string(TOLOWER ${VALUE} LVALUE )
 | 
					 | 
				
			||||||
		set(${KEY} ${LVALUE})
 | 
					 | 
				
			||||||
	else()
 | 
					 | 
				
			||||||
		set(${KEY} ${VALUE})
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
endmacro()
 | 
					 | 
				
			||||||
@ -22,66 +22,6 @@ macro(replace_if_different SOURCE DST)
 | 
				
			|||||||
	endif()
 | 
						endif()
 | 
				
			||||||
endmacro()
 | 
					endmacro()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro(eth_add_test NAME) 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# parse arguments here
 | 
					 | 
				
			||||||
	set(commands)
 | 
					 | 
				
			||||||
	set(current_command "")
 | 
					 | 
				
			||||||
	foreach (arg ${ARGN})
 | 
					 | 
				
			||||||
		if (arg STREQUAL "ARGS")
 | 
					 | 
				
			||||||
			if (current_command)
 | 
					 | 
				
			||||||
				list(APPEND commands ${current_command})
 | 
					 | 
				
			||||||
			endif()
 | 
					 | 
				
			||||||
			set(current_command "")
 | 
					 | 
				
			||||||
		else ()
 | 
					 | 
				
			||||||
			set(current_command "${current_command} ${arg}")
 | 
					 | 
				
			||||||
		endif()
 | 
					 | 
				
			||||||
	endforeach(arg)
 | 
					 | 
				
			||||||
	list(APPEND commands ${current_command})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	message(STATUS "test: ${NAME} | ${commands}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# create tests
 | 
					 | 
				
			||||||
	set(index 0)
 | 
					 | 
				
			||||||
	list(LENGTH commands count)
 | 
					 | 
				
			||||||
	while (index LESS count)
 | 
					 | 
				
			||||||
		list(GET commands ${index} test_arguments)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		set(run_test "--run_test=${NAME}")
 | 
					 | 
				
			||||||
		add_test(NAME "${NAME}.${index}" COMMAND testeth ${run_test} ${test_arguments})
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		math(EXPR index "${index} + 1")
 | 
					 | 
				
			||||||
	endwhile(index LESS count)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# add target to run them
 | 
					 | 
				
			||||||
	add_custom_target("test.${NAME}"
 | 
					 | 
				
			||||||
		DEPENDS testeth
 | 
					 | 
				
			||||||
		WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
 | 
					 | 
				
			||||||
		COMMAND ${CMAKE_COMMAND} -DETH_TEST_NAME="${NAME}" -DCTEST_COMMAND="${CTEST_COMMAND}" -P "${ETH_SCRIPTS_DIR}/runtest.cmake"
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
endmacro()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Creates C resources file from files
 | 
					 | 
				
			||||||
function(eth_add_resources RESOURCE_FILE OUT_FILE ETH_RES_DIR)
 | 
					 | 
				
			||||||
	include("${RESOURCE_FILE}")
 | 
					 | 
				
			||||||
	set(OUTPUT  "${ETH_RESOURCE_LOCATION}/${ETH_RESOURCE_NAME}.hpp")
 | 
					 | 
				
			||||||
	#message(FATAL_ERROR "res:! ${ETH_RESOURCE_LOCATION}")
 | 
					 | 
				
			||||||
	include_directories("${ETH_RESOURCE_LOCATION}")
 | 
					 | 
				
			||||||
	set(${OUT_FILE} "${OUTPUT}"  PARENT_SCOPE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set(filenames "${RESOURCE_FILE}")
 | 
					 | 
				
			||||||
	list(APPEND filenames "${ETH_SCRIPTS_DIR}/resources.cmake")
 | 
					 | 
				
			||||||
	foreach(resource ${ETH_RESOURCES})
 | 
					 | 
				
			||||||
		list(APPEND filenames "${${resource}}")
 | 
					 | 
				
			||||||
	endforeach(resource)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	add_custom_command(OUTPUT ${OUTPUT}
 | 
					 | 
				
			||||||
		COMMAND ${CMAKE_COMMAND} -DETH_RES_FILE="${RESOURCE_FILE}" -DETH_RES_DIR="${ETH_RES_DIR}"  -P "${ETH_SCRIPTS_DIR}/resources.cmake"
 | 
					 | 
				
			||||||
		DEPENDS ${filenames}
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
endfunction()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
macro(eth_default_option O DEF)
 | 
					macro(eth_default_option O DEF)
 | 
				
			||||||
	if (DEFINED ${O})
 | 
						if (DEFINED ${O})
 | 
				
			||||||
		if (${${O}})
 | 
							if (${${O}})
 | 
				
			||||||
@ -94,21 +34,3 @@ macro(eth_default_option O DEF)
 | 
				
			|||||||
	endif()
 | 
						endif()
 | 
				
			||||||
endmacro()
 | 
					endmacro()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# In Windows split repositories build we need to be checking whether or not
 | 
					 | 
				
			||||||
# Debug/Release or both versions were built for the config phase to run smoothly
 | 
					 | 
				
			||||||
macro(eth_check_library_link L)
 | 
					 | 
				
			||||||
	if (${${L}_LIBRARY} AND ${${L}_LIBRARY} EQUAL "${L}_LIBRARY-NOTFOUND")
 | 
					 | 
				
			||||||
		unset(${${L}_LIBRARY})
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
	if (${${L}_LIBRARY_DEBUG} AND ${${L}_LIBRARY_DEBUG} EQUAL "${L}_LIBRARY_DEBUG-NOTFOUND")
 | 
					 | 
				
			||||||
		unset(${${L}_LIBRARY_DEBUG})
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
	if (${${L}_LIBRARY} AND ${${L}_LIBRARY_DEBUG})
 | 
					 | 
				
			||||||
		set(${L}_LIBRARIES optimized ${${L}_LIBRARY} debug ${${L}_LIBRARY_DEBUG})
 | 
					 | 
				
			||||||
	elseif (${${L}_LIBRARY})
 | 
					 | 
				
			||||||
		set(${L}_LIBRARIES ${${L}_LIBRARY})
 | 
					 | 
				
			||||||
	elseif (${${L}_LIBRARY_DEBUG})
 | 
					 | 
				
			||||||
		set(${L}_LIBRARIES ${${L}_LIBRARY_DEBUG})
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
endmacro()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,382 +0,0 @@
 | 
				
			|||||||
#.rst:
 | 
					 | 
				
			||||||
# FindPackageHandleStandardArgs
 | 
					 | 
				
			||||||
# -----------------------------
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name> ...  )
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This function is intended to be used in FindXXX.cmake modules files.
 | 
					 | 
				
			||||||
# It handles the REQUIRED, QUIET and version-related arguments to
 | 
					 | 
				
			||||||
# find_package().  It also sets the <packagename>_FOUND variable.  The
 | 
					 | 
				
			||||||
# package is considered found if all variables <var1>...  listed contain
 | 
					 | 
				
			||||||
# valid results, e.g.  valid filepaths.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# There are two modes of this function.  The first argument in both
 | 
					 | 
				
			||||||
# modes is the name of the Find-module where it is called (in original
 | 
					 | 
				
			||||||
# casing).
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# The first simple mode looks like this:
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# ::
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#     FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name>
 | 
					 | 
				
			||||||
#       (DEFAULT_MSG|"Custom failure message") <var1>...<varN> )
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# If the variables <var1> to <varN> are all valid, then
 | 
					 | 
				
			||||||
# <UPPERCASED_NAME>_FOUND will be set to TRUE.  If DEFAULT_MSG is given
 | 
					 | 
				
			||||||
# as second argument, then the function will generate itself useful
 | 
					 | 
				
			||||||
# success and error messages.  You can also supply a custom error
 | 
					 | 
				
			||||||
# message for the failure case.  This is not recommended.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# The second mode is more powerful and also supports version checking:
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# ::
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#     FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME
 | 
					 | 
				
			||||||
#       [FOUND_VAR <resultVar>]
 | 
					 | 
				
			||||||
#       [REQUIRED_VARS <var1>...<varN>]
 | 
					 | 
				
			||||||
#       [VERSION_VAR   <versionvar>]
 | 
					 | 
				
			||||||
#       [HANDLE_COMPONENTS]
 | 
					 | 
				
			||||||
#       [CONFIG_MODE]
 | 
					 | 
				
			||||||
#       [FAIL_MESSAGE "Custom failure message"] )
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# In this mode, the name of the result-variable can be set either to
 | 
					 | 
				
			||||||
# either <UPPERCASED_NAME>_FOUND or <OriginalCase_Name>_FOUND using the
 | 
					 | 
				
			||||||
# FOUND_VAR option.  Other names for the result-variable are not
 | 
					 | 
				
			||||||
# allowed.  So for a Find-module named FindFooBar.cmake, the two
 | 
					 | 
				
			||||||
# possible names are FooBar_FOUND and FOOBAR_FOUND.  It is recommended
 | 
					 | 
				
			||||||
# to use the original case version.  If the FOUND_VAR option is not
 | 
					 | 
				
			||||||
# used, the default is <UPPERCASED_NAME>_FOUND.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# As in the simple mode, if <var1> through <varN> are all valid,
 | 
					 | 
				
			||||||
# <packagename>_FOUND will be set to TRUE.  After REQUIRED_VARS the
 | 
					 | 
				
			||||||
# variables which are required for this package are listed.  Following
 | 
					 | 
				
			||||||
# VERSION_VAR the name of the variable can be specified which holds the
 | 
					 | 
				
			||||||
# version of the package which has been found.  If this is done, this
 | 
					 | 
				
			||||||
# version will be checked against the (potentially) specified required
 | 
					 | 
				
			||||||
# version used in the find_package() call.  The EXACT keyword is also
 | 
					 | 
				
			||||||
# handled.  The default messages include information about the required
 | 
					 | 
				
			||||||
# version and the version which has been actually found, both if the
 | 
					 | 
				
			||||||
# version is ok or not.  If the package supports components, use the
 | 
					 | 
				
			||||||
# HANDLE_COMPONENTS option to enable handling them.  In this case,
 | 
					 | 
				
			||||||
# find_package_handle_standard_args() will report which components have
 | 
					 | 
				
			||||||
# been found and which are missing, and the <packagename>_FOUND variable
 | 
					 | 
				
			||||||
# will be set to FALSE if any of the required components (i.e.  not the
 | 
					 | 
				
			||||||
# ones listed after OPTIONAL_COMPONENTS) are missing.  Use the option
 | 
					 | 
				
			||||||
# CONFIG_MODE if your FindXXX.cmake module is a wrapper for a
 | 
					 | 
				
			||||||
# find_package(...  NO_MODULE) call.  In this case VERSION_VAR will be
 | 
					 | 
				
			||||||
# set to <NAME>_VERSION and the macro will automatically check whether
 | 
					 | 
				
			||||||
# the Config module was found.  Via FAIL_MESSAGE a custom failure
 | 
					 | 
				
			||||||
# message can be specified, if this is not used, the default message
 | 
					 | 
				
			||||||
# will be displayed.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Example for mode 1:
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# ::
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#     find_package_handle_standard_args(LibXml2  DEFAULT_MSG
 | 
					 | 
				
			||||||
#       LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and
 | 
					 | 
				
			||||||
# LIBXML2_INCLUDE_DIR are valid.  Then also LIBXML2_FOUND is set to
 | 
					 | 
				
			||||||
# TRUE.  If it is not found and REQUIRED was used, it fails with
 | 
					 | 
				
			||||||
# FATAL_ERROR, independent whether QUIET was used or not.  If it is
 | 
					 | 
				
			||||||
# found, success will be reported, including the content of <var1>.  On
 | 
					 | 
				
			||||||
# repeated Cmake runs, the same message won't be printed again.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Example for mode 2:
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# ::
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#     find_package_handle_standard_args(LibXslt
 | 
					 | 
				
			||||||
#       FOUND_VAR LibXslt_FOUND
 | 
					 | 
				
			||||||
#       REQUIRED_VARS LibXslt_LIBRARIES LibXslt_INCLUDE_DIRS
 | 
					 | 
				
			||||||
#       VERSION_VAR LibXslt_VERSION_STRING)
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# In this case, LibXslt is considered to be found if the variable(s)
 | 
					 | 
				
			||||||
# listed after REQUIRED_VAR are all valid, i.e.  LibXslt_LIBRARIES and
 | 
					 | 
				
			||||||
# LibXslt_INCLUDE_DIRS in this case.  The result will then be stored in
 | 
					 | 
				
			||||||
# LibXslt_FOUND .  Also the version of LibXslt will be checked by using
 | 
					 | 
				
			||||||
# the version contained in LibXslt_VERSION_STRING.  Since no
 | 
					 | 
				
			||||||
# FAIL_MESSAGE is given, the default messages will be printed.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Another example for mode 2:
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# ::
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#     find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
 | 
					 | 
				
			||||||
#     find_package_handle_standard_args(Automoc4  CONFIG_MODE)
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# In this case, FindAutmoc4.cmake wraps a call to find_package(Automoc4
 | 
					 | 
				
			||||||
# NO_MODULE) and adds an additional search directory for automoc4.  Here
 | 
					 | 
				
			||||||
# the result will be stored in AUTOMOC4_FOUND.  The following
 | 
					 | 
				
			||||||
# FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper
 | 
					 | 
				
			||||||
# success/error message.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#=============================================================================
 | 
					 | 
				
			||||||
# Copyright 2007-2009 Kitware, Inc.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Distributed under the OSI-approved BSD License (the "License");
 | 
					 | 
				
			||||||
# see accompanying file Copyright.txt for details.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
 | 
					 | 
				
			||||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | 
					 | 
				
			||||||
# See the License for more information.
 | 
					 | 
				
			||||||
#=============================================================================
 | 
					 | 
				
			||||||
# (To distribute this file outside of CMake, substitute the full
 | 
					 | 
				
			||||||
#  License text for the above reference.)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)
 | 
					 | 
				
			||||||
include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# internal helper macro
 | 
					 | 
				
			||||||
macro(_FPHSA_FAILURE_MESSAGE _msg)
 | 
					 | 
				
			||||||
  if (${_NAME}_FIND_REQUIRED)
 | 
					 | 
				
			||||||
    message(FATAL_ERROR "${_msg}")
 | 
					 | 
				
			||||||
  else ()
 | 
					 | 
				
			||||||
    if (NOT ${_NAME}_FIND_QUIETLY)
 | 
					 | 
				
			||||||
      message(STATUS "${_msg}")
 | 
					 | 
				
			||||||
    endif ()
 | 
					 | 
				
			||||||
  endif ()
 | 
					 | 
				
			||||||
endmacro()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# internal helper macro to generate the failure message when used in CONFIG_MODE:
 | 
					 | 
				
			||||||
macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
 | 
					 | 
				
			||||||
  # <name>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
 | 
					 | 
				
			||||||
  if(${_NAME}_CONFIG)
 | 
					 | 
				
			||||||
    _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
 | 
					 | 
				
			||||||
  else()
 | 
					 | 
				
			||||||
    # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
 | 
					 | 
				
			||||||
    # List them all in the error message:
 | 
					 | 
				
			||||||
    if(${_NAME}_CONSIDERED_CONFIGS)
 | 
					 | 
				
			||||||
      set(configsText "")
 | 
					 | 
				
			||||||
      list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
 | 
					 | 
				
			||||||
      math(EXPR configsCount "${configsCount} - 1")
 | 
					 | 
				
			||||||
      foreach(currentConfigIndex RANGE ${configsCount})
 | 
					 | 
				
			||||||
        list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
 | 
					 | 
				
			||||||
        list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
 | 
					 | 
				
			||||||
        set(configsText "${configsText}    ${filename} (version ${version})\n")
 | 
					 | 
				
			||||||
      endforeach()
 | 
					 | 
				
			||||||
      if (${_NAME}_NOT_FOUND_MESSAGE)
 | 
					 | 
				
			||||||
        set(configsText "${configsText}    Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n")
 | 
					 | 
				
			||||||
      endif()
 | 
					 | 
				
			||||||
      _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else()
 | 
					 | 
				
			||||||
      # Simple case: No Config-file was found at all:
 | 
					 | 
				
			||||||
      _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
 | 
					 | 
				
			||||||
    endif()
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
endmacro()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in
 | 
					 | 
				
			||||||
# new extended or in the "old" mode:
 | 
					 | 
				
			||||||
  set(options  CONFIG_MODE  HANDLE_COMPONENTS)
 | 
					 | 
				
			||||||
  set(oneValueArgs  FAIL_MESSAGE  VERSION_VAR  FOUND_VAR)
 | 
					 | 
				
			||||||
  set(multiValueArgs REQUIRED_VARS)
 | 
					 | 
				
			||||||
  set(_KEYWORDS_FOR_EXTENDED_MODE  ${options} ${oneValueArgs} ${multiValueArgs} )
 | 
					 | 
				
			||||||
  list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(${INDEX} EQUAL -1)
 | 
					 | 
				
			||||||
    set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
 | 
					 | 
				
			||||||
    set(FPHSA_REQUIRED_VARS ${ARGN})
 | 
					 | 
				
			||||||
    set(FPHSA_VERSION_VAR)
 | 
					 | 
				
			||||||
  else()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}"  ${_FIRST_ARG} ${ARGN})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(FPHSA_UNPARSED_ARGUMENTS)
 | 
					 | 
				
			||||||
      message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
 | 
					 | 
				
			||||||
    endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(NOT FPHSA_FAIL_MESSAGE)
 | 
					 | 
				
			||||||
      set(FPHSA_FAIL_MESSAGE  "DEFAULT_MSG")
 | 
					 | 
				
			||||||
    endif()
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# now that we collected all arguments, process them
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG")
 | 
					 | 
				
			||||||
    set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # In config-mode, we rely on the variable <package>_CONFIG, which is set by find_package()
 | 
					 | 
				
			||||||
  # when it successfully found the config-file, including version checking:
 | 
					 | 
				
			||||||
  if(FPHSA_CONFIG_MODE)
 | 
					 | 
				
			||||||
    list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
 | 
					 | 
				
			||||||
    list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
 | 
					 | 
				
			||||||
    set(FPHSA_VERSION_VAR ${_NAME}_VERSION)
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(NOT FPHSA_REQUIRED_VARS)
 | 
					 | 
				
			||||||
    message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  string(TOUPPER ${_NAME} _NAME_UPPER)
 | 
					 | 
				
			||||||
  string(TOLOWER ${_NAME} _NAME_LOWER)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(FPHSA_FOUND_VAR)
 | 
					 | 
				
			||||||
    if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$"  OR  FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$")
 | 
					 | 
				
			||||||
      set(_FOUND_VAR ${FPHSA_FOUND_VAR})
 | 
					 | 
				
			||||||
    else()
 | 
					 | 
				
			||||||
      message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.")
 | 
					 | 
				
			||||||
    endif()
 | 
					 | 
				
			||||||
  else()
 | 
					 | 
				
			||||||
    set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # collect all variables which were not found, so they can be printed, so the
 | 
					 | 
				
			||||||
  # user knows better what went wrong (#6375)
 | 
					 | 
				
			||||||
  set(MISSING_VARS "")
 | 
					 | 
				
			||||||
  set(DETAILS "")
 | 
					 | 
				
			||||||
  # check if all passed variables are valid
 | 
					 | 
				
			||||||
  unset(${_FOUND_VAR})
 | 
					 | 
				
			||||||
  foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
 | 
					 | 
				
			||||||
    if(NOT ${_CURRENT_VAR})
 | 
					 | 
				
			||||||
      set(${_FOUND_VAR} FALSE)
 | 
					 | 
				
			||||||
      set(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}")
 | 
					 | 
				
			||||||
    else()
 | 
					 | 
				
			||||||
      set(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]")
 | 
					 | 
				
			||||||
    endif()
 | 
					 | 
				
			||||||
  endforeach()
 | 
					 | 
				
			||||||
  if(NOT "${${_FOUND_VAR}}" STREQUAL "FALSE")
 | 
					 | 
				
			||||||
    set(${_FOUND_VAR} TRUE)
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # component handling
 | 
					 | 
				
			||||||
  unset(FOUND_COMPONENTS_MSG)
 | 
					 | 
				
			||||||
  unset(MISSING_COMPONENTS_MSG)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(FPHSA_HANDLE_COMPONENTS)
 | 
					 | 
				
			||||||
    foreach(comp ${${_NAME}_FIND_COMPONENTS})
 | 
					 | 
				
			||||||
      if(${_NAME}_${comp}_FOUND)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(NOT DEFINED FOUND_COMPONENTS_MSG)
 | 
					 | 
				
			||||||
          set(FOUND_COMPONENTS_MSG "found components: ")
 | 
					 | 
				
			||||||
        endif()
 | 
					 | 
				
			||||||
        set(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      else()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(NOT DEFINED MISSING_COMPONENTS_MSG)
 | 
					 | 
				
			||||||
          set(MISSING_COMPONENTS_MSG "missing components: ")
 | 
					 | 
				
			||||||
        endif()
 | 
					 | 
				
			||||||
        set(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(${_NAME}_FIND_REQUIRED_${comp})
 | 
					 | 
				
			||||||
          set(${_FOUND_VAR} FALSE)
 | 
					 | 
				
			||||||
          set(MISSING_VARS "${MISSING_VARS} ${comp}")
 | 
					 | 
				
			||||||
        endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      endif()
 | 
					 | 
				
			||||||
    endforeach()
 | 
					 | 
				
			||||||
    set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
 | 
					 | 
				
			||||||
    set(DETAILS "${DETAILS}[c${COMPONENT_MSG}]")
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # version handling:
 | 
					 | 
				
			||||||
  set(VERSION_MSG "")
 | 
					 | 
				
			||||||
  set(VERSION_OK TRUE)
 | 
					 | 
				
			||||||
  set(VERSION ${${FPHSA_VERSION_VAR}})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # check with DEFINED here as the requested or found version may be "0"
 | 
					 | 
				
			||||||
  if (DEFINED ${_NAME}_FIND_VERSION)
 | 
					 | 
				
			||||||
    if(DEFINED ${FPHSA_VERSION_VAR})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if(${_NAME}_FIND_VERSION_EXACT)       # exact version required
 | 
					 | 
				
			||||||
        # count the dots in the version string
 | 
					 | 
				
			||||||
        string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${VERSION}")
 | 
					 | 
				
			||||||
        # add one dot because there is one dot more than there are components
 | 
					 | 
				
			||||||
        string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS)
 | 
					 | 
				
			||||||
        if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT)
 | 
					 | 
				
			||||||
          # Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT
 | 
					 | 
				
			||||||
          # is at most 4 here. Therefore a simple lookup table is used.
 | 
					 | 
				
			||||||
          if (${_NAME}_FIND_VERSION_COUNT EQUAL 1)
 | 
					 | 
				
			||||||
            set(_VERSION_REGEX "[^.]*")
 | 
					 | 
				
			||||||
          elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2)
 | 
					 | 
				
			||||||
            set(_VERSION_REGEX "[^.]*\\.[^.]*")
 | 
					 | 
				
			||||||
          elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3)
 | 
					 | 
				
			||||||
            set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*")
 | 
					 | 
				
			||||||
          else ()
 | 
					 | 
				
			||||||
            set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*")
 | 
					 | 
				
			||||||
          endif ()
 | 
					 | 
				
			||||||
          string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${VERSION}")
 | 
					 | 
				
			||||||
          unset(_VERSION_REGEX)
 | 
					 | 
				
			||||||
          if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD)
 | 
					 | 
				
			||||||
            set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
 | 
					 | 
				
			||||||
            set(VERSION_OK FALSE)
 | 
					 | 
				
			||||||
          else ()
 | 
					 | 
				
			||||||
            set(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
 | 
					 | 
				
			||||||
          endif ()
 | 
					 | 
				
			||||||
          unset(_VERSION_HEAD)
 | 
					 | 
				
			||||||
        else ()
 | 
					 | 
				
			||||||
          if (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
 | 
					 | 
				
			||||||
            set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
 | 
					 | 
				
			||||||
            set(VERSION_OK FALSE)
 | 
					 | 
				
			||||||
          else ()
 | 
					 | 
				
			||||||
            set(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
 | 
					 | 
				
			||||||
          endif ()
 | 
					 | 
				
			||||||
        endif ()
 | 
					 | 
				
			||||||
        unset(_VERSION_DOTS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      else()     # minimum version specified:
 | 
					 | 
				
			||||||
        if ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
 | 
					 | 
				
			||||||
          set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"")
 | 
					 | 
				
			||||||
          set(VERSION_OK FALSE)
 | 
					 | 
				
			||||||
        else ()
 | 
					 | 
				
			||||||
          set(VERSION_MSG "(found suitable version \"${VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")")
 | 
					 | 
				
			||||||
        endif ()
 | 
					 | 
				
			||||||
      endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # if the package was not found, but a version was given, add that to the output:
 | 
					 | 
				
			||||||
      if(${_NAME}_FIND_VERSION_EXACT)
 | 
					 | 
				
			||||||
         set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
 | 
					 | 
				
			||||||
      else()
 | 
					 | 
				
			||||||
         set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
 | 
					 | 
				
			||||||
      endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    endif()
 | 
					 | 
				
			||||||
  else ()
 | 
					 | 
				
			||||||
    if(VERSION)
 | 
					 | 
				
			||||||
      set(VERSION_MSG "(found version \"${VERSION}\")")
 | 
					 | 
				
			||||||
    endif()
 | 
					 | 
				
			||||||
  endif ()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(VERSION_OK)
 | 
					 | 
				
			||||||
    set(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]")
 | 
					 | 
				
			||||||
  else()
 | 
					 | 
				
			||||||
    set(${_FOUND_VAR} FALSE)
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # print the result:
 | 
					 | 
				
			||||||
  if (${_FOUND_VAR})
 | 
					 | 
				
			||||||
    FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
 | 
					 | 
				
			||||||
  else ()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(FPHSA_CONFIG_MODE)
 | 
					 | 
				
			||||||
      _FPHSA_HANDLE_FAILURE_CONFIG_MODE()
 | 
					 | 
				
			||||||
    else()
 | 
					 | 
				
			||||||
      if(NOT VERSION_OK)
 | 
					 | 
				
			||||||
        _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})")
 | 
					 | 
				
			||||||
      else()
 | 
					 | 
				
			||||||
        _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}")
 | 
					 | 
				
			||||||
      endif()
 | 
					 | 
				
			||||||
    endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  endif ()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  set(${_FOUND_VAR} ${${_FOUND_VAR}} PARENT_SCOPE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
endfunction()
 | 
					 | 
				
			||||||
@ -1,57 +0,0 @@
 | 
				
			|||||||
#.rst:
 | 
					 | 
				
			||||||
# FindPackageMessage
 | 
					 | 
				
			||||||
# ------------------
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# FIND_PACKAGE_MESSAGE(<name> "message for user" "find result details")
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This macro is intended to be used in FindXXX.cmake modules files.  It
 | 
					 | 
				
			||||||
# will print a message once for each unique find result.  This is useful
 | 
					 | 
				
			||||||
# for telling the user where a package was found.  The first argument
 | 
					 | 
				
			||||||
# specifies the name (XXX) of the package.  The second argument
 | 
					 | 
				
			||||||
# specifies the message to display.  The third argument lists details
 | 
					 | 
				
			||||||
# about the find result so that if they change the message will be
 | 
					 | 
				
			||||||
# displayed again.  The macro also obeys the QUIET argument to the
 | 
					 | 
				
			||||||
# find_package command.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Example:
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# ::
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   if(X11_FOUND)
 | 
					 | 
				
			||||||
#     FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}"
 | 
					 | 
				
			||||||
#       "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]")
 | 
					 | 
				
			||||||
#   else()
 | 
					 | 
				
			||||||
#    ...
 | 
					 | 
				
			||||||
#   endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#=============================================================================
 | 
					 | 
				
			||||||
# Copyright 2008-2009 Kitware, Inc.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Distributed under the OSI-approved BSD License (the "License");
 | 
					 | 
				
			||||||
# see accompanying file Copyright.txt for details.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
 | 
					 | 
				
			||||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | 
					 | 
				
			||||||
# See the License for more information.
 | 
					 | 
				
			||||||
#=============================================================================
 | 
					 | 
				
			||||||
# (To distribute this file outside of CMake, substitute the full
 | 
					 | 
				
			||||||
#  License text for the above reference.)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function(FIND_PACKAGE_MESSAGE pkg msg details)
 | 
					 | 
				
			||||||
  # Avoid printing a message repeatedly for the same find result.
 | 
					 | 
				
			||||||
  if(NOT ${pkg}_FIND_QUIETLY)
 | 
					 | 
				
			||||||
    string(REPLACE "\n" "" details "${details}")
 | 
					 | 
				
			||||||
    set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})
 | 
					 | 
				
			||||||
    if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}")
 | 
					 | 
				
			||||||
      # The message has not yet been printed.
 | 
					 | 
				
			||||||
      message(STATUS "${msg}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # Save the find details in the cache to avoid printing the same
 | 
					 | 
				
			||||||
      # message again.
 | 
					 | 
				
			||||||
      set("${DETAILS_VAR}" "${details}"
 | 
					 | 
				
			||||||
        CACHE INTERNAL "Details about finding ${pkg}")
 | 
					 | 
				
			||||||
    endif()
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
endfunction()
 | 
					 | 
				
			||||||
@ -1,47 +0,0 @@
 | 
				
			|||||||
# Find Solidity
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Find the solidity includes and library
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This module defines
 | 
					 | 
				
			||||||
#  Solidity_XXX_LIBRARIES, the libraries needed to use solidity.
 | 
					 | 
				
			||||||
#  SOLIDITY_INCLUDE_DIRS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
include(EthUtils)
 | 
					 | 
				
			||||||
set(LIBS solidity;lll;solevmasm)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set(Solidity_INCLUDE_DIRS "${SOL_DIR}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# if the project is a subset of main cpp-ethereum project
 | 
					 | 
				
			||||||
# use same pattern for variables as Boost uses
 | 
					 | 
				
			||||||
if ((DEFINED solidity_VERSION) OR (DEFINED cpp-ethereum_VERSION))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	foreach (l ${LIBS})
 | 
					 | 
				
			||||||
		string(TOUPPER ${l} L)
 | 
					 | 
				
			||||||
		set ("Solidity_${L}_LIBRARIES" ${l})
 | 
					 | 
				
			||||||
	endforeach()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
else()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	foreach (l ${LIBS})
 | 
					 | 
				
			||||||
		string(TOUPPER ${l} L)
 | 
					 | 
				
			||||||
		find_library(Solidity_${L}_LIBRARY
 | 
					 | 
				
			||||||
			NAMES ${l}
 | 
					 | 
				
			||||||
			PATHS ${CMAKE_LIBRARY_PATH}
 | 
					 | 
				
			||||||
			PATH_SUFFIXES "lib${l}" "${l}" "lib${l}/Debug" "lib${l}/Release"
 | 
					 | 
				
			||||||
			NO_DEFAULT_PATH
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		set(Solidity_${L}_LIBRARIES ${Solidity_${L}_LIBRARY})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (DEFINED MSVC)
 | 
					 | 
				
			||||||
			find_library(Solidity_${L}_LIBRARY_DEBUG
 | 
					 | 
				
			||||||
				NAMES ${l}
 | 
					 | 
				
			||||||
				PATHS ${CMAKE_LIBRARY_PATH}
 | 
					 | 
				
			||||||
				PATH_SUFFIXES "lib${l}/Debug" 
 | 
					 | 
				
			||||||
				NO_DEFAULT_PATH
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
			eth_check_library_link(Solidity_${L})
 | 
					 | 
				
			||||||
		endif()
 | 
					 | 
				
			||||||
	endforeach()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
							
								
								
									
										7
									
								
								cmake/FindZ3.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								cmake/FindZ3.cmake
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					find_path(Z3_INCLUDE_DIR z3++.h)
 | 
				
			||||||
 | 
					find_library(Z3_LIBRARY NAMES z3 )
 | 
				
			||||||
 | 
					include(FindPackageHandleStandardArgs)
 | 
				
			||||||
 | 
					find_package_handle_standard_args(Z3 DEFAULT_MSG Z3_LIBRARY Z3_INCLUDE_DIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TODO: Create IMPORTED library for Z3.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1,31 +0,0 @@
 | 
				
			|||||||
function(eth_apply TARGET REQUIRED SUBMODULE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# Base is where all dependencies for devcore are
 | 
					 | 
				
			||||||
	if (${SUBMODULE} STREQUAL "base")
 | 
					 | 
				
			||||||
		# if it's ethereum source dir, always build BuildInfo.h before
 | 
					 | 
				
			||||||
		eth_use(${TARGET} ${REQUIRED} Dev::buildinfo)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		target_include_directories(${TARGET} SYSTEM PUBLIC ${Boost_INCLUDE_DIRS})
 | 
					 | 
				
			||||||
		target_link_libraries(${TARGET} ${Boost_THREAD_LIBRARIES})
 | 
					 | 
				
			||||||
		target_link_libraries(${TARGET} ${Boost_RANDOM_LIBRARIES})
 | 
					 | 
				
			||||||
		target_link_libraries(${TARGET} ${Boost_FILESYSTEM_LIBRARIES})
 | 
					 | 
				
			||||||
		target_link_libraries(${TARGET} ${Boost_SYSTEM_LIBRARIES})
 | 
					 | 
				
			||||||
		target_link_libraries(${TARGET} ${Boost_REGEX_LIBRARIES})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (DEFINED MSVC)
 | 
					 | 
				
			||||||
			target_link_libraries(${TARGET} ${Boost_CHRONO_LIBRARIES})
 | 
					 | 
				
			||||||
			target_link_libraries(${TARGET} ${Boost_DATE_TIME_LIBRARIES})
 | 
					 | 
				
			||||||
		endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
 | 
					 | 
				
			||||||
			target_link_libraries(${TARGET} pthread)
 | 
					 | 
				
			||||||
		endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (${SUBMODULE} STREQUAL "soldevcore")
 | 
					 | 
				
			||||||
		eth_use(${TARGET} ${REQUIRED} Dev::base)
 | 
					 | 
				
			||||||
		target_link_libraries(${TARGET} soldevcore)
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
endfunction()
 | 
					 | 
				
			||||||
@ -1,32 +0,0 @@
 | 
				
			|||||||
function(eth_apply TARGET REQUIRED SUBMODULE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set(SOL_DIR "${ETH_CMAKE_DIR}/.." CACHE PATH "The path to the solidity directory")
 | 
					 | 
				
			||||||
	set(SOL_BUILD_DIR_NAME  "build" CACHE STRING "The name of the build directory in solidity repo")
 | 
					 | 
				
			||||||
	set(SOL_BUILD_DIR "${SOL_DIR}/${SOL_BUILD_DIR_NAME}")
 | 
					 | 
				
			||||||
	set(CMAKE_LIBRARY_PATH ${SOL_BUILD_DIR};${CMAKE_LIBRARY_PATH})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	find_package(Solidity)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# Hide confusing blank dependency information when using FindSolidity on itself.
 | 
					 | 
				
			||||||
	if (NOT(${MODULE_MAIN} STREQUAL Solidity))
 | 
					 | 
				
			||||||
		eth_show_dependency(SOLIDITY solidity)
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	target_include_directories(${TARGET} PUBLIC ${Solidity_INCLUDE_DIRS})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (${SUBMODULE} STREQUAL "solevmasm")
 | 
					 | 
				
			||||||
		target_link_libraries(${TARGET} ${Solidity_SOLEVMASM_LIBRARIES} jsoncpp)
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (${SUBMODULE} STREQUAL "lll")
 | 
					 | 
				
			||||||
		eth_use(${TARGET} ${REQUIRED} Solidity::solevmasm)
 | 
					 | 
				
			||||||
		target_link_libraries(${TARGET} ${Solidity_LLL_LIBRARIES})
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (${SUBMODULE} STREQUAL "solidity" OR ${SUBMODULE} STREQUAL "")
 | 
					 | 
				
			||||||
		eth_use(${TARGET} ${REQUIRED} Dev::soldevcore Solidity::solevmasm)
 | 
					 | 
				
			||||||
		target_link_libraries(${TARGET} ${Solidity_SOLIDITY_LIBRARIES})
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	target_compile_definitions(${TARGET} PUBLIC ETH_SOLIDITY)
 | 
					 | 
				
			||||||
endfunction()
 | 
					 | 
				
			||||||
@ -44,7 +44,7 @@ The following elementary types exist:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- `bool`: equivalent to `uint8` restricted to the values 0 and 1
 | 
					- `bool`: equivalent to `uint8` restricted to the values 0 and 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- `fixed<M>x<N>`: signed fixed-point decimal number of `M` bits, `0 < M <= 256`, `M % 8 ==0`, and `0 < N <= 80`, which denotes the value `v` as `v / (10 ** N)`.
 | 
					- `fixed<M>x<N>`: signed fixed-point decimal number of `M` bits, `8 <= M <= 256`, `M % 8 ==0`, and `0 < N <= 80`, which denotes the value `v` as `v / (10 ** N)`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- `ufixed<M>x<N>`: unsigned variant of `fixed<M>x<N>`.
 | 
					- `ufixed<M>x<N>`: unsigned variant of `fixed<M>x<N>`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -293,8 +293,9 @@ The JSON format for a contract's interface is given by an array of function and/
 | 
				
			|||||||
  * `name`: the name of the parameter;
 | 
					  * `name`: the name of the parameter;
 | 
				
			||||||
  * `type`: the canonical type of the parameter.
 | 
					  * `type`: the canonical type of the parameter.
 | 
				
			||||||
- `outputs`: an array of objects similar to `inputs`, can be omitted if function doesn't return anything;
 | 
					- `outputs`: an array of objects similar to `inputs`, can be omitted if function doesn't return anything;
 | 
				
			||||||
- `constant`: `true` if function is :ref:`specified to not modify blockchain state <constant-functions>`);
 | 
					- `constant`: `true` if function is :ref:`specified to not modify blockchain state <view-functions>`);
 | 
				
			||||||
- `payable`: `true` if function accepts ether, defaults to `false`.
 | 
					- `payable`: `true` if function accepts ether, defaults to `false`;
 | 
				
			||||||
 | 
					- `stateMutability`: a string with one of the following values: `pure` (:ref:`specified to not read blockchain state <pure-functions>`), `view` (same as `constant` above), `nonpayable` and `payable` (same as `payable` above).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`type` can be omitted, defaulting to `"function"`.
 | 
					`type` can be omitted, defaulting to `"function"`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -96,6 +96,31 @@ you really know what you are doing.
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Same as above, but accomplish the entire code within inline assembly.
 | 
				
			||||||
 | 
					        function sumPureAsm(uint[] _data) returns (uint o_sum) {
 | 
				
			||||||
 | 
					            assembly {
 | 
				
			||||||
 | 
					               // Load the length (first 32 bytes)
 | 
				
			||||||
 | 
					               let len := mload(_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               // Skip over the length field.
 | 
				
			||||||
 | 
					               //
 | 
				
			||||||
 | 
					               // Keep temporary variable so it can be incremented in place.
 | 
				
			||||||
 | 
					               //
 | 
				
			||||||
 | 
					               // NOTE: incrementing _data would result in an unusable
 | 
				
			||||||
 | 
					               //       _data variable after this assembly block
 | 
				
			||||||
 | 
					               let data := add(_data, 0x20)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               // Iterate until the bound is not met.
 | 
				
			||||||
 | 
					               for
 | 
				
			||||||
 | 
					                   { let end := add(data, len) }
 | 
				
			||||||
 | 
					                   lt(data, end)
 | 
				
			||||||
 | 
					                   { data := add(data, 0x20) }
 | 
				
			||||||
 | 
					               {
 | 
				
			||||||
 | 
					                   o_sum := add(o_sum, mload(data))
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -125,7 +150,7 @@ following list can be used as a reference of its opcodes.
 | 
				
			|||||||
If an opcode takes arguments (always from the top of the stack), they are given in parentheses.
 | 
					If an opcode takes arguments (always from the top of the stack), they are given in parentheses.
 | 
				
			||||||
Note that the order of arguments can be seen to be reversed in non-functional style (explained below).
 | 
					Note that the order of arguments can be seen to be reversed in non-functional style (explained below).
 | 
				
			||||||
Opcodes marked with ``-`` do not push an item onto the stack, those marked with ``*`` are
 | 
					Opcodes marked with ``-`` do not push an item onto the stack, those marked with ``*`` are
 | 
				
			||||||
special and all others push exactly one item onte the stack.
 | 
					special and all others push exactly one item onto the stack.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In the following, ``mem[a...b)`` signifies the bytes of memory starting at position ``a`` up to
 | 
					In the following, ``mem[a...b)`` signifies the bytes of memory starting at position ``a`` up to
 | 
				
			||||||
(excluding) position ``b`` and ``storage[p]`` signifies the storage contents at position ``p``.
 | 
					(excluding) position ``b`` and ``storage[p]`` signifies the storage contents at position ``p``.
 | 
				
			||||||
@ -545,6 +570,20 @@ The following example computes the sum of an area in memory.
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For loops can also be written so that they behave like while loops:
 | 
				
			||||||
 | 
					Simply leave the initialization and post-iteration parts empty.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let x := 0
 | 
				
			||||||
 | 
					        let i := 0
 | 
				
			||||||
 | 
					        for { } lt(i, 0x100) { } {     // while(i < 0x100)
 | 
				
			||||||
 | 
					            x := add(x, mload(i))
 | 
				
			||||||
 | 
					            i := add(i, 0x20)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Functions
 | 
					Functions
 | 
				
			||||||
---------
 | 
					---------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -354,6 +354,10 @@
 | 
				
			|||||||
        "bugs": [], 
 | 
					        "bugs": [], 
 | 
				
			||||||
        "released": "2017-08-08"
 | 
					        "released": "2017-08-08"
 | 
				
			||||||
    }, 
 | 
					    }, 
 | 
				
			||||||
 | 
					    "0.4.16": {
 | 
				
			||||||
 | 
					        "bugs": [], 
 | 
				
			||||||
 | 
					        "released": "2017-08-24"
 | 
				
			||||||
 | 
					    }, 
 | 
				
			||||||
    "0.4.2": {
 | 
					    "0.4.2": {
 | 
				
			||||||
        "bugs": [
 | 
					        "bugs": [
 | 
				
			||||||
            "DelegateCallReturnValue", 
 | 
					            "DelegateCallReturnValue", 
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ variables. Calling a function on a different contract (instance) will perform
 | 
				
			|||||||
an EVM function call and thus switch the context such that state variables are
 | 
					an EVM function call and thus switch the context such that state variables are
 | 
				
			||||||
inaccessible.
 | 
					inaccessible.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. index:: ! contract;creation
 | 
					.. index:: ! contract;creation, constructor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
******************
 | 
					******************
 | 
				
			||||||
Creating Contracts
 | 
					Creating Contracts
 | 
				
			||||||
@ -461,29 +461,53 @@ value types and strings.
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. _constant-functions:
 | 
					.. _view-functions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
******************
 | 
					**************
 | 
				
			||||||
Constant Functions
 | 
					View Functions
 | 
				
			||||||
******************
 | 
					**************
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Functions can be declared constant in which case they promise not to modify the state.
 | 
					Functions can be declared ``view`` in which case they promise not to modify the state.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
::
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pragma solidity ^0.4.0;
 | 
					    pragma solidity ^0.4.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    contract C {
 | 
					    contract C {
 | 
				
			||||||
        function f(uint a, uint b) constant returns (uint) {
 | 
					        function f(uint a, uint b) view returns (uint) {
 | 
				
			||||||
            return a * (b + 42);
 | 
					            return a * (b + 42) + now;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. note::
 | 
					.. note::
 | 
				
			||||||
  Getter methods are marked constant.
 | 
					  ``constant`` is an alias to ``view``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. note::
 | 
				
			||||||
 | 
					  Getter methods are marked ``view``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. warning::
 | 
					.. warning::
 | 
				
			||||||
  The compiler does not enforce yet that a constant method is not modifying state.
 | 
					  The compiler does not enforce yet that a ``view`` method is not modifying state.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. _pure-functions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**************
 | 
				
			||||||
 | 
					Pure Functions
 | 
				
			||||||
 | 
					**************
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Functions can be declared ``pure`` in which case they promise not to read from or modify the state.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pragma solidity ^0.4.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    contract C {
 | 
				
			||||||
 | 
					        function f(uint a, uint b) pure returns (uint) {
 | 
				
			||||||
 | 
					            return a * (b + 42);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. warning::
 | 
				
			||||||
 | 
					  The compiler does not enforce yet that a ``pure`` method is not reading from the state.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. index:: ! fallback function, function;fallback
 | 
					.. index:: ! fallback function, function;fallback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -626,7 +650,7 @@ The use in the JavaScript API would be as follows:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    var abi = /* abi as generated by the compiler */;
 | 
					    var abi = /* abi as generated by the compiler */;
 | 
				
			||||||
    var ClientReceipt = web3.eth.contract(abi);
 | 
					    var ClientReceipt = web3.eth.contract(abi);
 | 
				
			||||||
    var clientReceipt = ClientReceipt.at(0x123 /* address */);
 | 
					    var clientReceipt = ClientReceipt.at("0x1234...ab67" /* address */);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var event = clientReceipt.Deposit();
 | 
					    var event = clientReceipt.Deposit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -658,7 +658,7 @@ Not yet, as this requires two levels of dynamic arrays (``string`` is a dynamic
 | 
				
			|||||||
If you issue a call for an array, it is possible to retrieve the whole array? Or must you write a helper function for that?
 | 
					If you issue a call for an array, it is possible to retrieve the whole array? Or must you write a helper function for that?
 | 
				
			||||||
===========================================================================================================================
 | 
					===========================================================================================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The automatic getter function for a public state variable of array type only returns
 | 
					The automatic :ref:`getter function<getter-functions>`  for a public state variable of array type only returns
 | 
				
			||||||
individual elements. If you want to return the complete array, you have to
 | 
					individual elements. If you want to return the complete array, you have to
 | 
				
			||||||
manually write a function to do that.
 | 
					manually write a function to do that.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -128,7 +128,7 @@ If you still have questions, you can try searching or asking on the
 | 
				
			|||||||
site, or come to our `gitter channel <https://gitter.im/ethereum/solidity/>`_.
 | 
					site, or come to our `gitter channel <https://gitter.im/ethereum/solidity/>`_.
 | 
				
			||||||
Ideas for improving Solidity or this documentation are always welcome!
 | 
					Ideas for improving Solidity or this documentation are always welcome!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
See also `Russian version (русский перевод) <https://github.com/ethereum/wiki/wiki/%D0%A0%D1%83%D0%BA%D0%BE%D0%B2%D0%BE%D0%B4%D1%81%D1%82%D0%B2%D0%BE-%D0%BF%D0%BE-Solidity>`_.
 | 
					See also `Russian version (русский перевод) <https://github.com/ethereum/wiki/wiki/%5BRussian%5D-%D0%A0%D1%83%D0%BA%D0%BE%D0%B2%D0%BE%D0%B4%D1%81%D1%82%D0%B2%D0%BE-%D0%BF%D0%BE-Solidity>`_.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Contents
 | 
					Contents
 | 
				
			||||||
========
 | 
					========
 | 
				
			||||||
 | 
				
			|||||||
@ -135,7 +135,7 @@ Gentoo Linux also provides a solidity package that can be installed using ``emer
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.. code:: bash
 | 
					.. code:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    demerge ev-lang/solidity
 | 
					    emerge dev-lang/solidity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. _building-from-source:
 | 
					.. _building-from-source:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -230,6 +230,7 @@ Or, on Windows:
 | 
				
			|||||||
Command-Line Build
 | 
					Command-Line Build
 | 
				
			||||||
------------------
 | 
					------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Solidity project uses CMake to configure the build.
 | 
				
			||||||
Building Solidity is quite similar on Linux, macOS and other Unices:
 | 
					Building Solidity is quite similar on Linux, macOS and other Unices:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code:: bash
 | 
					.. code:: bash
 | 
				
			||||||
@ -264,6 +265,11 @@ Alternatively, you can build for Windows on the command-line, like so:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    cmake --build . --config RelWithDebInfo
 | 
					    cmake --build . --config RelWithDebInfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMake options
 | 
				
			||||||
 | 
					=============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you are interested what CMake options are available run ``cmake .. -LH``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The version string in detail
 | 
					The version string in detail
 | 
				
			||||||
============================
 | 
					============================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -35,7 +35,7 @@ Solidity version 0.4.0 or anything newer that does not break functionality
 | 
				
			|||||||
(up to, but not including, version 0.5.0). This is to ensure that the
 | 
					(up to, but not including, version 0.5.0). This is to ensure that the
 | 
				
			||||||
contract does not suddenly behave differently with a new compiler version. The keyword ``pragma`` is called that way because, in general,
 | 
					contract does not suddenly behave differently with a new compiler version. The keyword ``pragma`` is called that way because, in general,
 | 
				
			||||||
pragmas are instructions for the compiler about how to treat the
 | 
					pragmas are instructions for the compiler about how to treat the
 | 
				
			||||||
source code (e.g. `pragma once <https://en.wikipedia.org/wiki/Pragma_once>`_).  .
 | 
					source code (e.g. `pragma once <https://en.wikipedia.org/wiki/Pragma_once>`_).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A contract in the sense of Solidity is a collection of code (its *functions*) and
 | 
					A contract in the sense of Solidity is a collection of code (its *functions*) and
 | 
				
			||||||
data (its *state*) that resides at a specific address on the Ethereum
 | 
					data (its *state*) that resides at a specific address on the Ethereum
 | 
				
			||||||
@ -133,7 +133,7 @@ too far, though, as it is neither possible to obtain a list of all keys of
 | 
				
			|||||||
a mapping, nor a list of all values. So either keep in mind (or
 | 
					a mapping, nor a list of all values. So either keep in mind (or
 | 
				
			||||||
better, keep a list or use a more advanced data type) what you
 | 
					better, keep a list or use a more advanced data type) what you
 | 
				
			||||||
added to the mapping or use it in a context where this is not needed,
 | 
					added to the mapping or use it in a context where this is not needed,
 | 
				
			||||||
like this one. The getter function created by the ``public`` keyword
 | 
					like this one. The :ref:`getter function<getter-functions>` created by the ``public`` keyword
 | 
				
			||||||
is a bit more complex in this case. It roughly looks like the
 | 
					is a bit more complex in this case. It roughly looks like the
 | 
				
			||||||
following::
 | 
					following::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -494,22 +494,24 @@ Function Visibility Specifiers
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- ``public``: visible externally and internally (creates getter function for storage/state variables)
 | 
					- ``public``: visible externally and internally (creates a :ref:`getter function<getter-functions>` for storage/state variables)
 | 
				
			||||||
- ``private``: only visible in the current contract
 | 
					- ``private``: only visible in the current contract
 | 
				
			||||||
- ``external``: only visible externally (only for functions) - i.e. can only be message-called (via ``this.func``)
 | 
					- ``external``: only visible externally (only for functions) - i.e. can only be message-called (via ``this.func``)
 | 
				
			||||||
- ``internal``: only visible internally
 | 
					- ``internal``: only visible internally
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. index:: modifiers, constant, anonymous, indexed
 | 
					.. index:: modifiers, pure, view, payable, constant, anonymous, indexed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Modifiers
 | 
					Modifiers
 | 
				
			||||||
=========
 | 
					=========
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- ``pure`` for functions: Disallows modification or access of state - this is not enforced yet.
 | 
				
			||||||
 | 
					- ``view`` for functions: Disallows modification of state - this is not enforced yet.
 | 
				
			||||||
 | 
					- ``payable`` for functions: Allows them to receive Ether together with a call.
 | 
				
			||||||
- ``constant`` for state variables: Disallows assignment (except initialisation), does not occupy storage slot.
 | 
					- ``constant`` for state variables: Disallows assignment (except initialisation), does not occupy storage slot.
 | 
				
			||||||
- ``constant`` for functions: Disallows modification of state - this is not enforced yet.
 | 
					- ``constant`` for functions: Same as ``view``.
 | 
				
			||||||
- ``anonymous`` for events: Does not store event signature as topic.
 | 
					- ``anonymous`` for events: Does not store event signature as topic.
 | 
				
			||||||
- ``indexed`` for event parameters: Stores the parameter as topic.
 | 
					- ``indexed`` for event parameters: Stores the parameter as topic.
 | 
				
			||||||
- ``payable`` for functions: Allows them to receive Ether together with a call.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Reserved Keywords
 | 
					Reserved Keywords
 | 
				
			||||||
=================
 | 
					=================
 | 
				
			||||||
 | 
				
			|||||||
@ -126,7 +126,7 @@ of votes.
 | 
				
			|||||||
            // modifies `voters[msg.sender].voted`
 | 
					            // modifies `voters[msg.sender].voted`
 | 
				
			||||||
            sender.voted = true;
 | 
					            sender.voted = true;
 | 
				
			||||||
            sender.delegate = to;
 | 
					            sender.delegate = to;
 | 
				
			||||||
            Voter delegate = voters[to];
 | 
					            Voter storage delegate = voters[to];
 | 
				
			||||||
            if (delegate.voted) {
 | 
					            if (delegate.voted) {
 | 
				
			||||||
                // If the delegate already voted,
 | 
					                // If the delegate already voted,
 | 
				
			||||||
                // directly add to the number of votes
 | 
					                // directly add to the number of votes
 | 
				
			||||||
@ -467,7 +467,7 @@ high or low invalid bids.
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                // Make it impossible for the sender to re-claim
 | 
					                // Make it impossible for the sender to re-claim
 | 
				
			||||||
                // the same deposit.
 | 
					                // the same deposit.
 | 
				
			||||||
                bid.blindedBid = 0;
 | 
					                bid.blindedBid = bytes32(0);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            msg.sender.transfer(refund);
 | 
					            msg.sender.transfer(refund);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -83,6 +83,8 @@ Operators:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
* ``<=``, ``<``, ``==``, ``!=``, ``>=`` and ``>``
 | 
					* ``<=``, ``<``, ``==``, ``!=``, ``>=`` and ``>``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. _members-of-addresses:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Members of Addresses
 | 
					Members of Addresses
 | 
				
			||||||
^^^^^^^^^^^^^^^^^^^^
 | 
					^^^^^^^^^^^^^^^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -184,7 +186,9 @@ number of bytes, always use one of ``bytes1`` to ``bytes32`` because they are mu
 | 
				
			|||||||
Fixed Point Numbers
 | 
					Fixed Point Numbers
 | 
				
			||||||
-------------------
 | 
					-------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**COMING SOON...**
 | 
					.. warning::
 | 
				
			||||||
 | 
					    Fixed point numbers are not fully supported by Solidity yet. They can be declared, but
 | 
				
			||||||
 | 
					    cannot be assigned to or from.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. index:: address, literal;address
 | 
					.. index:: address, literal;address
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -321,7 +325,7 @@ can be assigned from functions and function parameters of function type
 | 
				
			|||||||
can be used to pass functions to and return functions from function calls.
 | 
					can be used to pass functions to and return functions from function calls.
 | 
				
			||||||
Function types come in two flavours - *internal* and *external* functions:
 | 
					Function types come in two flavours - *internal* and *external* functions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Internal functions can only be used inside the current contract (more specifically,
 | 
					Internal functions can only be called inside the current contract (more specifically,
 | 
				
			||||||
inside the current code unit, which also includes internal library functions
 | 
					inside the current code unit, which also includes internal library functions
 | 
				
			||||||
and inherited functions) because they cannot be executed outside of the
 | 
					and inherited functions) because they cannot be executed outside of the
 | 
				
			||||||
context of the current contract. Calling an internal function is realized
 | 
					context of the current contract. Calling an internal function is realized
 | 
				
			||||||
@ -333,14 +337,15 @@ be passed via and returned from external function calls.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Function types are notated as follows::
 | 
					Function types are notated as follows::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function (<parameter types>) {internal|external} [constant] [payable] [returns (<return types>)]
 | 
					    function (<parameter types>) {internal|external} [pure|constant|view|payable] [returns (<return types>)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In contrast to the parameter types, the return types cannot be empty - if the
 | 
					In contrast to the parameter types, the return types cannot be empty - if the
 | 
				
			||||||
function type should not return anything, the whole ``returns (<return types>)``
 | 
					function type should not return anything, the whole ``returns (<return types>)``
 | 
				
			||||||
part has to be omitted.
 | 
					part has to be omitted.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
By default, function types are internal, so the ``internal`` keyword can be
 | 
					By default, function types are internal, so the ``internal`` keyword can be
 | 
				
			||||||
omitted.
 | 
					omitted. In contrast, contract functions themselves are public by default,
 | 
				
			||||||
 | 
					only when used as the name of a type, the default is internal.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
There are two ways to access a function in the current contract: Either directly
 | 
					There are two ways to access a function in the current contract: Either directly
 | 
				
			||||||
by its name, ``f``, or using ``this.f``. The former will result in an internal
 | 
					by its name, ``f``, or using ``this.f``. The former will result in an internal
 | 
				
			||||||
 | 
				
			|||||||
@ -57,7 +57,7 @@ class SolidityLexer(RegexLexer):
 | 
				
			|||||||
            (r'(anonymous|as|assembly|break|constant|continue|do|delete|else|external|for|hex|if|'
 | 
					            (r'(anonymous|as|assembly|break|constant|continue|do|delete|else|external|for|hex|if|'
 | 
				
			||||||
             r'indexed|internal|import|is|mapping|memory|new|payable|public|pragma|'
 | 
					             r'indexed|internal|import|is|mapping|memory|new|payable|public|pragma|'
 | 
				
			||||||
             r'private|return|returns|storage|super|this|throw|using|while)\b', Keyword, 'slashstartsregex'),
 | 
					             r'private|return|returns|storage|super|this|throw|using|while)\b', Keyword, 'slashstartsregex'),
 | 
				
			||||||
            (r'(var|function|event|modifier|struct|enum|contract|library)\b', Keyword.Declaration, 'slashstartsregex'),
 | 
					            (r'(var|function|event|modifier|struct|enum|contract|library|interface)\b', Keyword.Declaration, 'slashstartsregex'),
 | 
				
			||||||
            (r'(bytes|string|address|uint|int|bool|byte|' +
 | 
					            (r'(bytes|string|address|uint|int|bool|byte|' +
 | 
				
			||||||
             '|'.join(
 | 
					             '|'.join(
 | 
				
			||||||
                 ['uint%d' % (i + 8) for i in range(0, 256, 8)] +
 | 
					                 ['uint%d' % (i + 8) for i in range(0, 256, 8)] +
 | 
				
			||||||
@ -71,7 +71,7 @@ class SolidityLexer(RegexLexer):
 | 
				
			|||||||
             r'null|of|pure|relocatable|static|switch|try|type|typeof|view)\b', Keyword.Reserved),
 | 
					             r'null|of|pure|relocatable|static|switch|try|type|typeof|view)\b', Keyword.Reserved),
 | 
				
			||||||
            (r'(true|false)\b', Keyword.Constant),
 | 
					            (r'(true|false)\b', Keyword.Constant),
 | 
				
			||||||
            (r'(block|msg|tx|now|suicide|selfdestruct|addmod|mulmod|sha3|keccak256|log[0-4]|'
 | 
					            (r'(block|msg|tx|now|suicide|selfdestruct|addmod|mulmod|sha3|keccak256|log[0-4]|'
 | 
				
			||||||
             r'sha256|ecrecover|ripemd160|assert|revert)', Name.Builtin),
 | 
					             r'sha256|ecrecover|ripemd160|assert|revert|require)', Name.Builtin),
 | 
				
			||||||
            (r'[$a-zA-Z_][a-zA-Z0-9_]*', Name.Other),
 | 
					            (r'[$a-zA-Z_][a-zA-Z0-9_]*', Name.Other),
 | 
				
			||||||
            (r'[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?', Number.Float),
 | 
					            (r'[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?', Number.Float),
 | 
				
			||||||
            (r'0x[0-9a-fA-F]+', Number.Hex),
 | 
					            (r'0x[0-9a-fA-F]+', Number.Hex),
 | 
				
			||||||
 | 
				
			|||||||
@ -1,14 +1,8 @@
 | 
				
			|||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
 | 
					file(GLOB sources "*.cpp")
 | 
				
			||||||
 | 
					file(GLOB headers "*.h")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
aux_source_directory(. SRC_LIST)
 | 
					add_library(devcore ${sources} ${headers})
 | 
				
			||||||
 | 
					target_link_libraries(devcore PRIVATE ${Boost_FILESYSTEM_LIBRARIES} ${Boost_REGEX_LIBRARIES} ${Boost_SYSTEM_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
 | 
				
			||||||
set(EXECUTABLE soldevcore)
 | 
					target_include_directories(devcore SYSTEM PUBLIC ${Boost_INCLUDE_DIRS})
 | 
				
			||||||
 | 
					target_include_directories(devcore PUBLIC "${CMAKE_SOURCE_DIR}")
 | 
				
			||||||
file(GLOB HEADERS "*.h")
 | 
					add_dependencies(devcore solidity_BuildInfo.h)
 | 
				
			||||||
 | 
					 | 
				
			||||||
include_directories(..)
 | 
					 | 
				
			||||||
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
eth_use(${EXECUTABLE} REQUIRED Dev::base)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -44,7 +44,6 @@
 | 
				
			|||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <chrono>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(__GNUC__)
 | 
					#if defined(__GNUC__)
 | 
				
			||||||
#pragma warning(push)
 | 
					#pragma warning(push)
 | 
				
			||||||
@ -158,7 +157,7 @@ template <> inline u256 exp10<0>()
 | 
				
			|||||||
class ScopeGuard
 | 
					class ScopeGuard
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	ScopeGuard(std::function<void(void)> _f): m_f(_f) {}
 | 
						explicit ScopeGuard(std::function<void(void)> _f): m_f(_f) {}
 | 
				
			||||||
	~ScopeGuard() { m_f(); }
 | 
						~ScopeGuard() { m_f(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
				
			|||||||
@ -145,6 +145,24 @@ inline std::string toHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd)
 | 
				
			|||||||
	return (prefix == HexPrefix::Add) ? "0x" + str : str;
 | 
						return (prefix == HexPrefix::Add) ? "0x" + str : str;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns decimal representation for small numbers and hex for large numbers.
 | 
				
			||||||
 | 
					inline std::string formatNumber(bigint const& _value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (_value < 0)
 | 
				
			||||||
 | 
							return "-" + formatNumber(-_value);
 | 
				
			||||||
 | 
						if (_value > 0x1000000)
 | 
				
			||||||
 | 
							return toHex(toCompactBigEndian(_value), 2, HexPrefix::Add);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return _value.str();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline std::string toCompactHexWithPrefix(u256 val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::ostringstream ret;
 | 
				
			||||||
 | 
						ret << std::hex << val;
 | 
				
			||||||
 | 
						return "0x" + ret.str();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Algorithms for string and string-like collections.
 | 
					// Algorithms for string and string-like collections.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Escapes a string into the C-string representation.
 | 
					/// Escapes a string into the C-string representation.
 | 
				
			||||||
@ -177,7 +195,8 @@ template <class T>
 | 
				
			|||||||
inline std::vector<T> operator+(std::vector<T> const& _a, std::vector<T> const& _b)
 | 
					inline std::vector<T> operator+(std::vector<T> const& _a, std::vector<T> const& _b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::vector<T> ret(_a);
 | 
						std::vector<T> ret(_a);
 | 
				
			||||||
	return ret += _b;
 | 
						ret += _b;
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <class T, class V>
 | 
					template <class T, class V>
 | 
				
			||||||
 | 
				
			|||||||
@ -27,6 +27,7 @@
 | 
				
			|||||||
#include <cstdint>
 | 
					#include <cstdint>
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <boost/functional/hash.hpp>
 | 
					#include <boost/functional/hash.hpp>
 | 
				
			||||||
 | 
					#include <boost/io/ios_state.hpp>
 | 
				
			||||||
#include "CommonData.h"
 | 
					#include "CommonData.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace dev
 | 
					namespace dev
 | 
				
			||||||
@ -59,7 +60,7 @@ public:
 | 
				
			|||||||
	enum ConstructFromHashType { AlignLeft, AlignRight, FailIfDifferent };
 | 
						enum ConstructFromHashType { AlignLeft, AlignRight, FailIfDifferent };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Construct an empty hash.
 | 
						/// Construct an empty hash.
 | 
				
			||||||
	FixedHash() { m_data.fill(0); }
 | 
						explicit FixedHash() { m_data.fill(0); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Construct from another hash, filling with zeroes or cropping as necessary.
 | 
						/// Construct from another hash, filling with zeroes or cropping as necessary.
 | 
				
			||||||
	template <unsigned M> explicit FixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; }
 | 
						template <unsigned M> explicit FixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; }
 | 
				
			||||||
@ -224,6 +225,7 @@ template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& va
 | 
				
			|||||||
template <unsigned N>
 | 
					template <unsigned N>
 | 
				
			||||||
inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
 | 
					inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						boost::io::ios_all_saver guard(_out);
 | 
				
			||||||
	_out << std::noshowbase << std::hex << std::setfill('0');
 | 
						_out << std::noshowbase << std::hex << std::setfill('0');
 | 
				
			||||||
	for (unsigned i = 0; i < N; ++i)
 | 
						for (unsigned i = 0; i < N; ++i)
 | 
				
			||||||
		_out << std::setw(2) << (int)_h[i];
 | 
							_out << std::setw(2) << (int)_h[i];
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										65
									
								
								libdevcore/IndentedWriter.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								libdevcore/IndentedWriter.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
						This file is part of solidity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
						it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
						the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
						(at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
						but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
						MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
						GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
						along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @date 2017
 | 
				
			||||||
 | 
					 * Indented text writer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libdevcore/IndentedWriter.h>
 | 
				
			||||||
 | 
					#include <libdevcore/Assertions.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace std;
 | 
				
			||||||
 | 
					using namespace dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string IndentedWriter::format() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						string result;
 | 
				
			||||||
 | 
						for (auto const& line: m_lines)
 | 
				
			||||||
 | 
							result += string(line.indentation * 4, ' ') + line.contents + "\n";
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void IndentedWriter::newLine()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!m_lines.back().contents.empty())
 | 
				
			||||||
 | 
							m_lines.push_back({ string(), m_lines.back().indentation });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void IndentedWriter::indent()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						newLine();
 | 
				
			||||||
 | 
						m_lines.back().indentation++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void IndentedWriter::unindent()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						newLine();
 | 
				
			||||||
 | 
						assertThrow(m_lines.back().indentation > 0, IndentedWriterError, "Negative indentation.");
 | 
				
			||||||
 | 
						m_lines.back().indentation--;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void IndentedWriter::add(string const& _str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_lines.back().contents += _str;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void IndentedWriter::addLine(string const& _line)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						newLine();
 | 
				
			||||||
 | 
						add(_line);
 | 
				
			||||||
 | 
						newLine();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										67
									
								
								libdevcore/IndentedWriter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								libdevcore/IndentedWriter.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
						This file is part of solidity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
						it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
						the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
						(at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
						but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
						MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
						GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
						along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @date 2017
 | 
				
			||||||
 | 
					 * Indented text writer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libdevcore/Exceptions.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace dev
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEV_SIMPLE_EXCEPTION(IndentedWriterError);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IndentedWriter
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						explicit IndentedWriter(): m_lines(std::vector<Line>{{std::string(), 0}}) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Returns the formatted output.
 | 
				
			||||||
 | 
						std::string format() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Go one indentation level in.
 | 
				
			||||||
 | 
						void indent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Go one indentation level out.
 | 
				
			||||||
 | 
						void unindent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Add text.
 | 
				
			||||||
 | 
						void add(std::string const& _str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Add text with new line.
 | 
				
			||||||
 | 
						void addLine(std::string const& _line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Add new line.
 | 
				
			||||||
 | 
						void newLine();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						struct Line
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							std::string contents;
 | 
				
			||||||
 | 
							unsigned indentation;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::vector<Line> m_lines;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -90,7 +90,7 @@ string Whiskers::replace(
 | 
				
			|||||||
		string tagName(_match[1]);
 | 
							string tagName(_match[1]);
 | 
				
			||||||
		if (!tagName.empty())
 | 
							if (!tagName.empty())
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			assertThrow(_parameters.count(tagName), WhiskersError, "Tag " + tagName + " not found.");
 | 
								assertThrow(_parameters.count(tagName), WhiskersError, "Value for tag " + tagName + " not provided.");
 | 
				
			||||||
			return _parameters.at(tagName);
 | 
								return _parameters.at(tagName);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
 | 
				
			|||||||
@ -233,7 +233,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	Json::Value root;
 | 
						Json::Value root;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Json::Value collection(Json::arrayValue);
 | 
						Json::Value& collection = root[".code"] = Json::arrayValue;
 | 
				
			||||||
	for (AssemblyItem const& i: m_items)
 | 
						for (AssemblyItem const& i: m_items)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		switch (i.type())
 | 
							switch (i.type())
 | 
				
			||||||
@ -289,11 +289,9 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	root[".code"] = collection;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!m_data.empty() || !m_subs.empty())
 | 
						if (!m_data.empty() || !m_subs.empty())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Json::Value data;
 | 
							Json::Value& data = root[".data"] = Json::objectValue;
 | 
				
			||||||
		for (auto const& i: m_data)
 | 
							for (auto const& i: m_data)
 | 
				
			||||||
			if (u256(i.first) >= m_subs.size())
 | 
								if (u256(i.first) >= m_subs.size())
 | 
				
			||||||
				data[toStringInHex((u256)i.first)] = toHex(i.second);
 | 
									data[toStringInHex((u256)i.first)] = toHex(i.second);
 | 
				
			||||||
@ -304,7 +302,6 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes
 | 
				
			|||||||
			hexStr << hex << i;
 | 
								hexStr << hex << i;
 | 
				
			||||||
			data[hexStr.str()] = m_subs[i]->stream(_out, "", _sourceCodes, true);
 | 
								data[hexStr.str()] = m_subs[i]->stream(_out, "", _sourceCodes, true);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		root[".data"] = data;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (m_auxiliaryData.size() > 0)
 | 
						if (m_auxiliaryData.size() > 0)
 | 
				
			||||||
 | 
				
			|||||||
@ -219,10 +219,10 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item)
 | 
				
			|||||||
			_out << "\t" << _item.getJumpTypeAsString();
 | 
								_out << "\t" << _item.getJumpTypeAsString();
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case Push:
 | 
						case Push:
 | 
				
			||||||
		_out << " PUSH " << hex << _item.data();
 | 
							_out << " PUSH " << hex << _item.data() << dec;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PushString:
 | 
						case PushString:
 | 
				
			||||||
		_out << " PushString"  << hex << (unsigned)_item.data();
 | 
							_out << " PushString"  << hex << (unsigned)_item.data() << dec;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PushTag:
 | 
						case PushTag:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -237,19 +237,19 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item)
 | 
				
			|||||||
		_out << " Tag " << _item.data();
 | 
							_out << " Tag " << _item.data();
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PushData:
 | 
						case PushData:
 | 
				
			||||||
		_out << " PushData " << hex << (unsigned)_item.data();
 | 
							_out << " PushData " << hex << (unsigned)_item.data() << dec;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PushSub:
 | 
						case PushSub:
 | 
				
			||||||
		_out << " PushSub " << hex << size_t(_item.data());
 | 
							_out << " PushSub " << hex << size_t(_item.data()) << dec;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PushSubSize:
 | 
						case PushSubSize:
 | 
				
			||||||
		_out << " PushSubSize " << hex << size_t(_item.data());
 | 
							_out << " PushSubSize " << hex << size_t(_item.data()) << dec;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PushProgramSize:
 | 
						case PushProgramSize:
 | 
				
			||||||
		_out << " PushProgramSize";
 | 
							_out << " PushProgramSize";
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PushLibraryAddress:
 | 
						case PushLibraryAddress:
 | 
				
			||||||
		_out << " PushLibraryAddress " << hex << h256(_item.data()).abridgedMiddle();
 | 
							_out << " PushLibraryAddress " << hex << h256(_item.data()).abridgedMiddle() << dec;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case UndefinedItem:
 | 
						case UndefinedItem:
 | 
				
			||||||
		_out << " ???";
 | 
							_out << " ???";
 | 
				
			||||||
 | 
				
			|||||||
@ -45,7 +45,7 @@ using AssemblyItems = std::vector<AssemblyItem>;
 | 
				
			|||||||
class BlockDeduplicator
 | 
					class BlockDeduplicator
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	BlockDeduplicator(AssemblyItems& _items): m_items(_items) {}
 | 
						explicit BlockDeduplicator(AssemblyItems& _items): m_items(_items) {}
 | 
				
			||||||
	/// @returns true if something was changed
 | 
						/// @returns true if something was changed
 | 
				
			||||||
	bool deduplicate();
 | 
						bool deduplicate();
 | 
				
			||||||
	/// @returns the tags that were replaced.
 | 
						/// @returns the tags that were replaced.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,14 +1,5 @@
 | 
				
			|||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
 | 
					file(GLOB sources "*.cpp")
 | 
				
			||||||
 | 
					file(GLOB headers "*.h")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
aux_source_directory(. SRC_LIST)
 | 
					add_library(evmasm ${sources} ${headers})
 | 
				
			||||||
 | 
					target_link_libraries(evmasm PUBLIC devcore jsoncpp)
 | 
				
			||||||
set(EXECUTABLE solevmasm)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
file(GLOB HEADERS "*.h")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
include_directories(BEFORE ..)
 | 
					 | 
				
			||||||
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
 | 
					 | 
				
			||||||
eth_use(${EXECUTABLE} REQUIRED Dev::soldevcore)
 | 
					 | 
				
			||||||
target_link_libraries(${EXECUTABLE} jsoncpp)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -220,6 +220,7 @@ void CSECodeGenerator::addDependencies(Id _c)
 | 
				
			|||||||
	if (m_neededBy.count(_c))
 | 
						if (m_neededBy.count(_c))
 | 
				
			||||||
		return; // we already computed the dependencies for _c
 | 
							return; // we already computed the dependencies for _c
 | 
				
			||||||
	ExpressionClasses::Expression expr = m_expressionClasses.representative(_c);
 | 
						ExpressionClasses::Expression expr = m_expressionClasses.representative(_c);
 | 
				
			||||||
 | 
						assertThrow(expr.item, OptimizerException, "");
 | 
				
			||||||
	if (expr.item->type() == UndefinedItem)
 | 
						if (expr.item->type() == UndefinedItem)
 | 
				
			||||||
		BOOST_THROW_EXCEPTION(
 | 
							BOOST_THROW_EXCEPTION(
 | 
				
			||||||
			// If this exception happens, we need to find a different way to generate the
 | 
								// If this exception happens, we need to find a different way to generate the
 | 
				
			||||||
 | 
				
			|||||||
@ -61,7 +61,7 @@ public:
 | 
				
			|||||||
	using Id = ExpressionClasses::Id;
 | 
						using Id = ExpressionClasses::Id;
 | 
				
			||||||
	using StoreOperation = KnownState::StoreOperation;
 | 
						using StoreOperation = KnownState::StoreOperation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CommonSubexpressionEliminator(KnownState const& _state): m_initialState(_state), m_state(_state) {}
 | 
						explicit CommonSubexpressionEliminator(KnownState const& _state): m_initialState(_state), m_state(_state) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Feeds AssemblyItems into the eliminator and @returns the iterator pointing at the first
 | 
						/// Feeds AssemblyItems into the eliminator and @returns the iterator pointing at the first
 | 
				
			||||||
	/// item that must be fed into a new instance of the eliminator.
 | 
						/// item that must be fed into a new instance of the eliminator.
 | 
				
			||||||
@ -147,7 +147,7 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	AssemblyItems m_generatedItems;
 | 
						AssemblyItems m_generatedItems;
 | 
				
			||||||
	/// Current height of the stack relative to the start.
 | 
						/// Current height of the stack relative to the start.
 | 
				
			||||||
	int m_stackHeight;
 | 
						int m_stackHeight = 0;
 | 
				
			||||||
	/// If (b, a) is in m_requests then b is needed to compute a.
 | 
						/// If (b, a) is in m_requests then b is needed to compute a.
 | 
				
			||||||
	std::multimap<Id, Id> m_neededBy;
 | 
						std::multimap<Id, Id> m_neededBy;
 | 
				
			||||||
	/// Current content of the stack.
 | 
						/// Current content of the stack.
 | 
				
			||||||
 | 
				
			|||||||
@ -124,7 +124,7 @@ void ConstantOptimisationMethod::replaceConstants(
 | 
				
			|||||||
	_items = std::move(replaced);
 | 
						_items = std::move(replaced);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bigint LiteralMethod::gasNeeded()
 | 
					bigint LiteralMethod::gasNeeded() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return combineGas(
 | 
						return combineGas(
 | 
				
			||||||
		simpleRunGas({Instruction::PUSH1}),
 | 
							simpleRunGas({Instruction::PUSH1}),
 | 
				
			||||||
@ -139,7 +139,7 @@ CodeCopyMethod::CodeCopyMethod(Params const& _params, u256 const& _value):
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bigint CodeCopyMethod::gasNeeded()
 | 
					bigint CodeCopyMethod::gasNeeded() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return combineGas(
 | 
						return combineGas(
 | 
				
			||||||
		// Run gas: we ignore memory increase costs
 | 
							// Run gas: we ignore memory increase costs
 | 
				
			||||||
@ -151,7 +151,7 @@ bigint CodeCopyMethod::gasNeeded()
 | 
				
			|||||||
	);
 | 
						);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AssemblyItems CodeCopyMethod::execute(Assembly& _assembly)
 | 
					AssemblyItems CodeCopyMethod::execute(Assembly& _assembly) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	bytes data = toBigEndian(m_value);
 | 
						bytes data = toBigEndian(m_value);
 | 
				
			||||||
	AssemblyItems actualCopyRoutine = copyRoutine();
 | 
						AssemblyItems actualCopyRoutine = copyRoutine();
 | 
				
			||||||
@ -159,7 +159,7 @@ AssemblyItems CodeCopyMethod::execute(Assembly& _assembly)
 | 
				
			|||||||
	return actualCopyRoutine;
 | 
						return actualCopyRoutine;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AssemblyItems const& CodeCopyMethod::copyRoutine() const
 | 
					AssemblyItems const& CodeCopyMethod::copyRoutine()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	AssemblyItems static copyRoutine{
 | 
						AssemblyItems static copyRoutine{
 | 
				
			||||||
		u256(0),
 | 
							u256(0),
 | 
				
			||||||
@ -282,7 +282,7 @@ bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const&
 | 
				
			|||||||
	return stack.size() == 1 && stack.front() == _value;
 | 
						return stack.size() == 1 && stack.front() == _value;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine)
 | 
					bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP);
 | 
						size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP);
 | 
				
			||||||
	return combineGas(
 | 
						return combineGas(
 | 
				
			||||||
 | 
				
			|||||||
@ -63,11 +63,11 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	explicit ConstantOptimisationMethod(Params const& _params, u256 const& _value):
 | 
						explicit ConstantOptimisationMethod(Params const& _params, u256 const& _value):
 | 
				
			||||||
		m_params(_params), m_value(_value) {}
 | 
							m_params(_params), m_value(_value) {}
 | 
				
			||||||
	virtual bigint gasNeeded() = 0;
 | 
						virtual bigint gasNeeded() const = 0;
 | 
				
			||||||
	/// Executes the method, potentially appending to the assembly and returns a vector of
 | 
						/// Executes the method, potentially appending to the assembly and returns a vector of
 | 
				
			||||||
	/// assembly items the constant should be relpaced with in one sweep.
 | 
						/// assembly items the constant should be relpaced with in one sweep.
 | 
				
			||||||
	/// If the vector is empty, the constants will not be deleted.
 | 
						/// If the vector is empty, the constants will not be deleted.
 | 
				
			||||||
	virtual AssemblyItems execute(Assembly& _assembly) = 0;
 | 
						virtual AssemblyItems execute(Assembly& _assembly) const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	size_t dataSize() const { return std::max<size_t>(1, dev::bytesRequired(m_value)); }
 | 
						size_t dataSize() const { return std::max<size_t>(1, dev::bytesRequired(m_value)); }
 | 
				
			||||||
@ -84,7 +84,7 @@ protected:
 | 
				
			|||||||
		bigint const& _runGas,
 | 
							bigint const& _runGas,
 | 
				
			||||||
		bigint const& _repeatedDataGas,
 | 
							bigint const& _repeatedDataGas,
 | 
				
			||||||
		bigint const& _uniqueDataGas
 | 
							bigint const& _uniqueDataGas
 | 
				
			||||||
	)
 | 
						) const
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// _runGas is not multiplied by _multiplicity because the runs are "per opcode"
 | 
							// _runGas is not multiplied by _multiplicity because the runs are "per opcode"
 | 
				
			||||||
		return m_params.runs * _runGas + m_params.multiplicity * _repeatedDataGas + _uniqueDataGas;
 | 
							return m_params.runs * _runGas + m_params.multiplicity * _repeatedDataGas + _uniqueDataGas;
 | 
				
			||||||
@ -106,8 +106,8 @@ class LiteralMethod: public ConstantOptimisationMethod
 | 
				
			|||||||
public:
 | 
					public:
 | 
				
			||||||
	explicit LiteralMethod(Params const& _params, u256 const& _value):
 | 
						explicit LiteralMethod(Params const& _params, u256 const& _value):
 | 
				
			||||||
		ConstantOptimisationMethod(_params, _value) {}
 | 
							ConstantOptimisationMethod(_params, _value) {}
 | 
				
			||||||
	virtual bigint gasNeeded() override;
 | 
						virtual bigint gasNeeded() const override;
 | 
				
			||||||
	virtual AssemblyItems execute(Assembly&) override { return AssemblyItems{}; }
 | 
						virtual AssemblyItems execute(Assembly&) const override { return AssemblyItems{}; }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -117,11 +117,11 @@ class CodeCopyMethod: public ConstantOptimisationMethod
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	explicit CodeCopyMethod(Params const& _params, u256 const& _value);
 | 
						explicit CodeCopyMethod(Params const& _params, u256 const& _value);
 | 
				
			||||||
	virtual bigint gasNeeded() override;
 | 
						virtual bigint gasNeeded() const override;
 | 
				
			||||||
	virtual AssemblyItems execute(Assembly& _assembly) override;
 | 
						virtual AssemblyItems execute(Assembly& _assembly) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	AssemblyItems const& copyRoutine() const;
 | 
						static AssemblyItems const& copyRoutine();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -141,8 +141,8 @@ public:
 | 
				
			|||||||
		);
 | 
							);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bigint gasNeeded() override { return gasNeeded(m_routine); }
 | 
						virtual bigint gasNeeded() const override { return gasNeeded(m_routine); }
 | 
				
			||||||
	virtual AssemblyItems execute(Assembly&) override
 | 
						virtual AssemblyItems execute(Assembly&) const override
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return m_routine;
 | 
							return m_routine;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -151,8 +151,8 @@ protected:
 | 
				
			|||||||
	/// Tries to recursively find a way to compute @a _value.
 | 
						/// Tries to recursively find a way to compute @a _value.
 | 
				
			||||||
	AssemblyItems findRepresentation(u256 const& _value);
 | 
						AssemblyItems findRepresentation(u256 const& _value);
 | 
				
			||||||
	/// Recomputes the value from the calculated representation and checks for correctness.
 | 
						/// Recomputes the value from the calculated representation and checks for correctness.
 | 
				
			||||||
	bool checkRepresentation(u256 const& _value, AssemblyItems const& _routine);
 | 
						static bool checkRepresentation(u256 const& _value, AssemblyItems const& _routine);
 | 
				
			||||||
	bigint gasNeeded(AssemblyItems const& _routine);
 | 
						bigint gasNeeded(AssemblyItems const& _routine) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Counter for the complexity of optimization, will stop when it reaches zero.
 | 
						/// Counter for the complexity of optimization, will stop when it reaches zero.
 | 
				
			||||||
	size_t m_maxSteps = 10000;
 | 
						size_t m_maxSteps = 10000;
 | 
				
			||||||
 | 
				
			|||||||
@ -50,7 +50,7 @@ struct GasPath
 | 
				
			|||||||
class PathGasMeter
 | 
					class PathGasMeter
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	PathGasMeter(AssemblyItems const& _items);
 | 
						explicit PathGasMeter(AssemblyItems const& _items);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GasMeter::GasConsumption estimateMax(size_t _startIndex, std::shared_ptr<KnownState> const& _state);
 | 
						GasMeter::GasConsumption estimateMax(size_t _startIndex, std::shared_ptr<KnownState> const& _state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,18 +1,5 @@
 | 
				
			|||||||
cmake_policy(SET CMP0015 NEW)
 | 
					file(GLOB sources "*.cpp")
 | 
				
			||||||
set(CMAKE_AUTOMOC OFF)
 | 
					file(GLOB headers "*.h")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
 | 
					add_library(lll ${sources} ${headers})
 | 
				
			||||||
 | 
					target_link_libraries(lll PUBLIC evmasm devcore)
 | 
				
			||||||
aux_source_directory(. SRC_LIST)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set(EXECUTABLE lll)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
file(GLOB HEADERS "*.h")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
include_directories(BEFORE ..)
 | 
					 | 
				
			||||||
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
eth_use(${EXECUTABLE} REQUIRED Solidity::solevmasm)
 | 
					 | 
				
			||||||
#target_link_libraries(${EXECUTABLE} evmasm)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -50,8 +50,8 @@ public:
 | 
				
			|||||||
private:
 | 
					private:
 | 
				
			||||||
	void finalise(CompilerState const& _cs);
 | 
						void finalise(CompilerState const& _cs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	template <class T> void error() const { BOOST_THROW_EXCEPTION(T() ); }
 | 
						template <class T> static void error() { BOOST_THROW_EXCEPTION(T() ); }
 | 
				
			||||||
	template <class T> void error(std::string const& reason) const {
 | 
						template <class T> static void error(std::string const& reason) {
 | 
				
			||||||
		auto err = T();
 | 
							auto err = T();
 | 
				
			||||||
		err << errinfo_comment(reason);
 | 
							err << errinfo_comment(reason);
 | 
				
			||||||
		BOOST_THROW_EXCEPTION(err);
 | 
							BOOST_THROW_EXCEPTION(err);
 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,7 @@ CompilerState::CompilerState()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CodeFragment const& CompilerState::getDef(std::string const& _s)
 | 
					CodeFragment const& CompilerState::getDef(std::string const& _s) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (defs.count(_s))
 | 
						if (defs.count(_s))
 | 
				
			||||||
		return defs.at(_s);
 | 
							return defs.at(_s);
 | 
				
			||||||
 | 
				
			|||||||
@ -40,7 +40,7 @@ struct CompilerState
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	CompilerState();
 | 
						CompilerState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CodeFragment const& getDef(std::string const& _s);
 | 
						CodeFragment const& getDef(std::string const& _s) const;
 | 
				
			||||||
	void populateStandard();
 | 
						void populateStandard();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned stackSize = 128;
 | 
						unsigned stackSize = 128;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,23 +1,20 @@
 | 
				
			|||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
aux_source_directory(analysis SRC_LIST)
 | 
					 | 
				
			||||||
aux_source_directory(ast SRC_LIST)
 | 
					 | 
				
			||||||
aux_source_directory(codegen SRC_LIST)
 | 
					 | 
				
			||||||
aux_source_directory(formal SRC_LIST)
 | 
					 | 
				
			||||||
aux_source_directory(interface SRC_LIST)
 | 
					 | 
				
			||||||
aux_source_directory(parsing SRC_LIST)
 | 
					 | 
				
			||||||
aux_source_directory(inlineasm SRC_LIST)
 | 
					 | 
				
			||||||
# Until we have a clear separation, libjulia has to be included here
 | 
					# Until we have a clear separation, libjulia has to be included here
 | 
				
			||||||
aux_source_directory(../libjulia SRC_LIST)
 | 
					file(GLOB_RECURSE sources "*.cpp" "../libjulia/*.cpp")
 | 
				
			||||||
 | 
					file(GLOB_RECURSE headers "*.h" "../libjulia/*.h")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(EXECUTABLE solidity)
 | 
					find_package(Z3 QUIET)
 | 
				
			||||||
 | 
					if (${Z3_FOUND})
 | 
				
			||||||
 | 
					  include_directories(${Z3_INCLUDE_DIR})
 | 
				
			||||||
 | 
					  add_definitions(-DHAVE_Z3)
 | 
				
			||||||
 | 
					  message("Z3 SMT solver FOUND.")
 | 
				
			||||||
 | 
					else()
 | 
				
			||||||
 | 
					  message("Z3 SMT solver NOT found.")
 | 
				
			||||||
 | 
					  list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/Z3Interface.cpp")
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
file(GLOB HEADERS "*/*.h" "../libjulia/backends/evm/*")
 | 
					add_library(solidity ${sources} ${headers})
 | 
				
			||||||
 | 
					target_link_libraries(solidity PUBLIC evmasm devcore)
 | 
				
			||||||
include_directories(BEFORE ..)
 | 
					 | 
				
			||||||
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
eth_use(${EXECUTABLE} REQUIRED Dev::soldevcore Solidity::solevmasm)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (${Z3_FOUND})
 | 
				
			||||||
 | 
					  target_link_libraries(solidity PUBLIC ${Z3_LIBRARY})
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
@ -57,6 +57,8 @@ bool StaticAnalyzer::visit(FunctionDefinition const& _function)
 | 
				
			|||||||
	solAssert(m_localVarUseCount.empty(), "");
 | 
						solAssert(m_localVarUseCount.empty(), "");
 | 
				
			||||||
	m_nonPayablePublic = _function.isPublic() && !_function.isPayable();
 | 
						m_nonPayablePublic = _function.isPublic() && !_function.isPayable();
 | 
				
			||||||
	m_constructor = _function.isConstructor();
 | 
						m_constructor = _function.isConstructor();
 | 
				
			||||||
 | 
						if (_function.stateMutability() == StateMutability::Pure)
 | 
				
			||||||
 | 
							m_errorReporter.warning(_function.location(), "Function is marked pure. Be careful, pureness is not enforced yet.");
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -92,6 +94,17 @@ bool StaticAnalyzer::visit(VariableDeclaration const& _variable)
 | 
				
			|||||||
			// This is not a no-op, the entry might pre-exist.
 | 
								// This is not a no-op, the entry might pre-exist.
 | 
				
			||||||
			m_localVarUseCount[&_variable] += 0;
 | 
								m_localVarUseCount[&_variable] += 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						else if (_variable.isStateVariable())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							set<StructDefinition const*> structsSeen;
 | 
				
			||||||
 | 
							if (structureSizeEstimate(*_variable.type(), structsSeen) >= bigint(1) << 64)
 | 
				
			||||||
 | 
								m_errorReporter.warning(
 | 
				
			||||||
 | 
									_variable.location(),
 | 
				
			||||||
 | 
									"Variable covers a large part of storage and thus makes collisions likely. "
 | 
				
			||||||
 | 
									"Either use mappings or dynamic arrays and allow their size to be increased only "
 | 
				
			||||||
 | 
									"in small quantities per transaction."
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -160,3 +173,34 @@ bool StaticAnalyzer::visit(InlineAssembly const& _inlineAssembly)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bigint StaticAnalyzer::structureSizeEstimate(Type const& _type, set<StructDefinition const*>& _structsSeen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (_type.category())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						case Type::Category::Array:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto const& t = dynamic_cast<ArrayType const&>(_type);
 | 
				
			||||||
 | 
							return structureSizeEstimate(*t.baseType(), _structsSeen) * (t.isDynamicallySized() ? 1 : t.length());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						case Type::Category::Struct:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto const& t = dynamic_cast<StructType const&>(_type);
 | 
				
			||||||
 | 
							bigint size = 1;
 | 
				
			||||||
 | 
							if (!_structsSeen.count(&t.structDefinition()))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								_structsSeen.insert(&t.structDefinition());
 | 
				
			||||||
 | 
								for (auto const& m: t.members(nullptr))
 | 
				
			||||||
 | 
									size += structureSizeEstimate(*m.type, _structsSeen);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return size;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						case Type::Category::Mapping:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return structureSizeEstimate(*dynamic_cast<MappingType const&>(_type).valueType(), _structsSeen);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return bigint(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -65,6 +65,9 @@ private:
 | 
				
			|||||||
	virtual bool visit(MemberAccess const& _memberAccess) override;
 | 
						virtual bool visit(MemberAccess const& _memberAccess) override;
 | 
				
			||||||
	virtual bool visit(InlineAssembly const& _inlineAssembly) override;
 | 
						virtual bool visit(InlineAssembly const& _inlineAssembly) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// @returns the size of this type in storage, including all sub-types.
 | 
				
			||||||
 | 
						static bigint structureSizeEstimate(Type const& _type, std::set<StructDefinition const*>& _structsSeen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ErrorReporter& m_errorReporter;
 | 
						ErrorReporter& m_errorReporter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Flag that indicates whether the current contract definition is a library.
 | 
						/// Flag that indicates whether the current contract definition is a library.
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@
 | 
				
			|||||||
#include <libsolidity/analysis/SyntaxChecker.h>
 | 
					#include <libsolidity/analysis/SyntaxChecker.h>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <libsolidity/ast/AST.h>
 | 
					#include <libsolidity/ast/AST.h>
 | 
				
			||||||
 | 
					#include <libsolidity/ast/ExperimentalFeatures.h>
 | 
				
			||||||
#include <libsolidity/analysis/SemVerHandler.h>
 | 
					#include <libsolidity/analysis/SemVerHandler.h>
 | 
				
			||||||
#include <libsolidity/interface/ErrorReporter.h>
 | 
					#include <libsolidity/interface/ErrorReporter.h>
 | 
				
			||||||
#include <libsolidity/interface/Version.h>
 | 
					#include <libsolidity/interface/Version.h>
 | 
				
			||||||
@ -33,9 +34,10 @@ bool SyntaxChecker::checkSyntax(ASTNode const& _astRoot)
 | 
				
			|||||||
	return Error::containsOnlyWarnings(m_errorReporter.errors());
 | 
						return Error::containsOnlyWarnings(m_errorReporter.errors());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool SyntaxChecker::visit(SourceUnit const&)
 | 
					bool SyntaxChecker::visit(SourceUnit const& _sourceUnit)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	m_versionPragmaFound = false;
 | 
						m_versionPragmaFound = false;
 | 
				
			||||||
 | 
						m_sourceUnit = &_sourceUnit;
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -57,15 +59,46 @@ void SyntaxChecker::endVisit(SourceUnit const& _sourceUnit)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		m_errorReporter.warning(_sourceUnit.location(), errorString);
 | 
							m_errorReporter.warning(_sourceUnit.location(), errorString);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						m_sourceUnit = nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool SyntaxChecker::visit(PragmaDirective const& _pragma)
 | 
					bool SyntaxChecker::visit(PragmaDirective const& _pragma)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	solAssert(!_pragma.tokens().empty(), "");
 | 
						solAssert(!_pragma.tokens().empty(), "");
 | 
				
			||||||
	solAssert(_pragma.tokens().size() == _pragma.literals().size(), "");
 | 
						solAssert(_pragma.tokens().size() == _pragma.literals().size(), "");
 | 
				
			||||||
	if (_pragma.tokens()[0] != Token::Identifier || _pragma.literals()[0] != "solidity")
 | 
						if (_pragma.tokens()[0] != Token::Identifier)
 | 
				
			||||||
		m_errorReporter.syntaxError(_pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\"");
 | 
							m_errorReporter.syntaxError(_pragma.location(), "Invalid pragma \"" + _pragma.literals()[0] + "\"");
 | 
				
			||||||
	else
 | 
						else if (_pragma.literals()[0] == "experimental")
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							solAssert(m_sourceUnit, "");
 | 
				
			||||||
 | 
							vector<string> literals(_pragma.literals().begin() + 1, _pragma.literals().end());
 | 
				
			||||||
 | 
							if (literals.size() == 0)
 | 
				
			||||||
 | 
								m_errorReporter.syntaxError(
 | 
				
			||||||
 | 
									_pragma.location(),
 | 
				
			||||||
 | 
									"Experimental feature name is missing."
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							else if (literals.size() > 1)
 | 
				
			||||||
 | 
								m_errorReporter.syntaxError(
 | 
				
			||||||
 | 
									_pragma.location(),
 | 
				
			||||||
 | 
									"Stray arguments."
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								string const literal = literals[0];
 | 
				
			||||||
 | 
								if (literal.empty())
 | 
				
			||||||
 | 
									m_errorReporter.syntaxError(_pragma.location(), "Empty experimental feature name is invalid.");
 | 
				
			||||||
 | 
								else if (!ExperimentalFeatureNames.count(literal))
 | 
				
			||||||
 | 
									m_errorReporter.syntaxError(_pragma.location(), "Unsupported experimental feature name.");
 | 
				
			||||||
 | 
								else if (m_sourceUnit->annotation().experimentalFeatures.count(ExperimentalFeatureNames.at(literal)))
 | 
				
			||||||
 | 
									m_errorReporter.syntaxError(_pragma.location(), "Duplicate experimental feature name.");
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									m_sourceUnit->annotation().experimentalFeatures.insert(ExperimentalFeatureNames.at(literal));
 | 
				
			||||||
 | 
									m_errorReporter.warning(_pragma.location(), "Experimental features are turned on. Do not use experimental features on live deployments.");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (_pragma.literals()[0] == "solidity")
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		vector<Token::Value> tokens(_pragma.tokens().begin() + 1, _pragma.tokens().end());
 | 
							vector<Token::Value> tokens(_pragma.tokens().begin() + 1, _pragma.tokens().end());
 | 
				
			||||||
		vector<string> literals(_pragma.literals().begin() + 1, _pragma.literals().end());
 | 
							vector<string> literals(_pragma.literals().begin() + 1, _pragma.literals().end());
 | 
				
			||||||
@ -81,6 +114,8 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma)
 | 
				
			|||||||
			);
 | 
								);
 | 
				
			||||||
		m_versionPragmaFound = true;
 | 
							m_versionPragmaFound = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							m_errorReporter.syntaxError(_pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\"");
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -77,6 +77,8 @@ private:
 | 
				
			|||||||
	bool m_versionPragmaFound = false;
 | 
						bool m_versionPragmaFound = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int m_inLoopDepth = 0;
 | 
						int m_inLoopDepth = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SourceUnit const* m_sourceUnit = nullptr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -84,8 +84,13 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		if (!function->returnParameters().empty())
 | 
							if (!function->returnParameters().empty())
 | 
				
			||||||
			m_errorReporter.typeError(function->returnParameterList()->location(), "Non-empty \"returns\" directive for constructor.");
 | 
								m_errorReporter.typeError(function->returnParameterList()->location(), "Non-empty \"returns\" directive for constructor.");
 | 
				
			||||||
		if (function->isDeclaredConst())
 | 
							if (function->stateMutability() != StateMutability::NonPayable && function->stateMutability() != StateMutability::Payable)
 | 
				
			||||||
			m_errorReporter.typeError(function->location(), "Constructor cannot be defined as constant.");
 | 
								m_errorReporter.typeError(
 | 
				
			||||||
 | 
									function->location(),
 | 
				
			||||||
 | 
									"Constructor must be payable or non-payable, but is \"" +
 | 
				
			||||||
 | 
									stateMutabilityToString(function->stateMutability()) +
 | 
				
			||||||
 | 
									"\"."
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
		if (function->visibility() != FunctionDefinition::Visibility::Public && function->visibility() != FunctionDefinition::Visibility::Internal)
 | 
							if (function->visibility() != FunctionDefinition::Visibility::Public && function->visibility() != FunctionDefinition::Visibility::Internal)
 | 
				
			||||||
			m_errorReporter.typeError(function->location(), "Constructor must be public or internal.");
 | 
								m_errorReporter.typeError(function->location(), "Constructor must be public or internal.");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -104,8 +109,13 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
 | 
				
			|||||||
				fallbackFunction = function;
 | 
									fallbackFunction = function;
 | 
				
			||||||
				if (_contract.isLibrary())
 | 
									if (_contract.isLibrary())
 | 
				
			||||||
					m_errorReporter.typeError(fallbackFunction->location(), "Libraries cannot have fallback functions.");
 | 
										m_errorReporter.typeError(fallbackFunction->location(), "Libraries cannot have fallback functions.");
 | 
				
			||||||
				if (fallbackFunction->isDeclaredConst())
 | 
									if (function->stateMutability() != StateMutability::NonPayable && function->stateMutability() != StateMutability::Payable)
 | 
				
			||||||
					m_errorReporter.typeError(fallbackFunction->location(), "Fallback function cannot be declared constant.");
 | 
										m_errorReporter.typeError(
 | 
				
			||||||
 | 
											function->location(),
 | 
				
			||||||
 | 
											"Fallback function must be payable or non-payable, but is \"" +
 | 
				
			||||||
 | 
											stateMutabilityToString(function->stateMutability()) +
 | 
				
			||||||
 | 
											"\"."
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
				if (!fallbackFunction->parameters().empty())
 | 
									if (!fallbackFunction->parameters().empty())
 | 
				
			||||||
					m_errorReporter.typeError(fallbackFunction->parameterList().location(), "Fallback function cannot take parameters.");
 | 
										m_errorReporter.typeError(fallbackFunction->parameterList().location(), "Fallback function cannot take parameters.");
 | 
				
			||||||
				if (!fallbackFunction->returnParameters().empty())
 | 
									if (!fallbackFunction->returnParameters().empty())
 | 
				
			||||||
@ -277,21 +287,10 @@ void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contr
 | 
				
			|||||||
			string const& name = function->name();
 | 
								string const& name = function->name();
 | 
				
			||||||
			if (modifiers.count(name))
 | 
								if (modifiers.count(name))
 | 
				
			||||||
				m_errorReporter.typeError(modifiers[name]->location(), "Override changes function to modifier.");
 | 
									m_errorReporter.typeError(modifiers[name]->location(), "Override changes function to modifier.");
 | 
				
			||||||
			FunctionType functionType(*function);
 | 
					
 | 
				
			||||||
			// function should not change the return type
 | 
					 | 
				
			||||||
			for (FunctionDefinition const* overriding: functions[name])
 | 
								for (FunctionDefinition const* overriding: functions[name])
 | 
				
			||||||
			{
 | 
									checkFunctionOverride(*overriding, *function);
 | 
				
			||||||
				FunctionType overridingType(*overriding);
 | 
					
 | 
				
			||||||
				if (!overridingType.hasEqualArgumentTypes(functionType))
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
				if (
 | 
					 | 
				
			||||||
					overriding->visibility() != function->visibility() ||
 | 
					 | 
				
			||||||
					overriding->isDeclaredConst() != function->isDeclaredConst() ||
 | 
					 | 
				
			||||||
					overriding->isPayable() != function->isPayable() ||
 | 
					 | 
				
			||||||
					overridingType != functionType
 | 
					 | 
				
			||||||
				)
 | 
					 | 
				
			||||||
					m_errorReporter.typeError(overriding->location(), "Override changes extended function signature.");
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			functions[name].push_back(function);
 | 
								functions[name].push_back(function);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for (ModifierDefinition const* modifier: contract->functionModifiers())
 | 
							for (ModifierDefinition const* modifier: contract->functionModifiers())
 | 
				
			||||||
@ -308,6 +307,41 @@ void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contr
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void TypeChecker::checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						FunctionType functionType(function);
 | 
				
			||||||
 | 
						FunctionType superType(super);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!functionType.hasEqualArgumentTypes(superType))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (function.visibility() != super.visibility())
 | 
				
			||||||
 | 
							overrideError(function, super, "Overriding function visibility differs.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						else if (function.stateMutability() != super.stateMutability())
 | 
				
			||||||
 | 
							overrideError(
 | 
				
			||||||
 | 
								function,
 | 
				
			||||||
 | 
								super,
 | 
				
			||||||
 | 
								"Overriding function changes state mutability from \"" +
 | 
				
			||||||
 | 
								stateMutabilityToString(super.stateMutability()) +
 | 
				
			||||||
 | 
								"\" to \"" +
 | 
				
			||||||
 | 
								stateMutabilityToString(function.stateMutability()) +
 | 
				
			||||||
 | 
								"\"."
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						else if (functionType != superType)
 | 
				
			||||||
 | 
							overrideError(function, super, "Overriding function return types differ.");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void TypeChecker::overrideError(FunctionDefinition const& function, FunctionDefinition const& super, string message)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_errorReporter.typeError(
 | 
				
			||||||
 | 
							function.location(),
 | 
				
			||||||
 | 
							SecondarySourceLocation().append("Overriden function is here:", super.location()),
 | 
				
			||||||
 | 
							message
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TypeChecker::checkContractExternalTypeClashes(ContractDefinition const& _contract)
 | 
					void TypeChecker::checkContractExternalTypeClashes(ContractDefinition const& _contract)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	map<string, vector<pair<Declaration const*, FunctionTypePointer>>> externalDeclarations;
 | 
						map<string, vector<pair<Declaration const*, FunctionTypePointer>>> externalDeclarations;
 | 
				
			||||||
@ -396,7 +430,11 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
 | 
				
			|||||||
		m_errorReporter.typeError(_inheritance.location(), "Libraries cannot be inherited from.");
 | 
							m_errorReporter.typeError(_inheritance.location(), "Libraries cannot be inherited from.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto const& arguments = _inheritance.arguments();
 | 
						auto const& arguments = _inheritance.arguments();
 | 
				
			||||||
	TypePointers parameterTypes = ContractType(*base).newExpressionType()->parameterTypes();
 | 
						TypePointers parameterTypes;
 | 
				
			||||||
 | 
						if (base->contractKind() != ContractDefinition::ContractKind::Interface)
 | 
				
			||||||
 | 
							// Interfaces do not have constructors, so there are zero parameters.
 | 
				
			||||||
 | 
							parameterTypes = ContractType(*base).newExpressionType()->parameterTypes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!arguments.empty() && parameterTypes.size() != arguments.size())
 | 
						if (!arguments.empty() && parameterTypes.size() != arguments.size())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_errorReporter.typeError(
 | 
							m_errorReporter.typeError(
 | 
				
			||||||
@ -429,7 +467,7 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
 | 
				
			|||||||
		_usingFor.libraryName().annotation().referencedDeclaration
 | 
							_usingFor.libraryName().annotation().referencedDeclaration
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
	if (!library || !library->isLibrary())
 | 
						if (!library || !library->isLibrary())
 | 
				
			||||||
		m_errorReporter.typeError(_usingFor.libraryName().location(), "Library name expected.");
 | 
							m_errorReporter.fatalTypeError(_usingFor.libraryName().location(), "Library name expected.");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TypeChecker::visit(StructDefinition const& _struct)
 | 
					bool TypeChecker::visit(StructDefinition const& _struct)
 | 
				
			||||||
@ -475,8 +513,6 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
 | 
				
			|||||||
			m_errorReporter.typeError(_function.location(), "Library functions cannot be payable.");
 | 
								m_errorReporter.typeError(_function.location(), "Library functions cannot be payable.");
 | 
				
			||||||
		if (!_function.isConstructor() && !_function.isFallback() && !_function.isPartOfExternalInterface())
 | 
							if (!_function.isConstructor() && !_function.isFallback() && !_function.isPartOfExternalInterface())
 | 
				
			||||||
			m_errorReporter.typeError(_function.location(), "Internal functions cannot be payable.");
 | 
								m_errorReporter.typeError(_function.location(), "Internal functions cannot be payable.");
 | 
				
			||||||
		if (_function.isDeclaredConst())
 | 
					 | 
				
			||||||
			m_errorReporter.typeError(_function.location(), "Functions cannot be constant and payable at the same time.");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (ASTPointer<VariableDeclaration> const& var: _function.parameters() + _function.returnParameters())
 | 
						for (ASTPointer<VariableDeclaration> const& var: _function.parameters() + _function.returnParameters())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -514,6 +550,9 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
 | 
				
			|||||||
		if (_function.isConstructor())
 | 
							if (_function.isConstructor())
 | 
				
			||||||
			m_errorReporter.typeError(_function.location(), "Constructor cannot be defined in interfaces.");
 | 
								m_errorReporter.typeError(_function.location(), "Constructor cannot be defined in interfaces.");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						else if (m_scope->contractKind() == ContractDefinition::ContractKind::Library)
 | 
				
			||||||
 | 
							if (_function.isConstructor())
 | 
				
			||||||
 | 
								m_errorReporter.typeError(_function.location(), "Constructor cannot be defined in libraries.");
 | 
				
			||||||
	if (_function.isImplemented())
 | 
						if (_function.isImplemented())
 | 
				
			||||||
		_function.body().accept(*this);
 | 
							_function.body().accept(*this);
 | 
				
			||||||
	else if (_function.isConstructor())
 | 
						else if (_function.isConstructor())
 | 
				
			||||||
@ -1282,8 +1321,9 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
 | 
				
			|||||||
		_operation.leftExpression().annotation().isPure &&
 | 
							_operation.leftExpression().annotation().isPure &&
 | 
				
			||||||
		_operation.rightExpression().annotation().isPure;
 | 
							_operation.rightExpression().annotation().isPure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (_operation.getOperator() == Token::Exp)
 | 
						if (_operation.getOperator() == Token::Exp || _operation.getOperator() == Token::SHL)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							string operation = _operation.getOperator() == Token::Exp ? "exponentiation" : "shift";
 | 
				
			||||||
		if (
 | 
							if (
 | 
				
			||||||
			leftType->category() == Type::Category::RationalNumber &&
 | 
								leftType->category() == Type::Category::RationalNumber &&
 | 
				
			||||||
			rightType->category() != Type::Category::RationalNumber
 | 
								rightType->category() != Type::Category::RationalNumber
 | 
				
			||||||
@ -1297,7 +1337,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
 | 
				
			|||||||
			))
 | 
								))
 | 
				
			||||||
				m_errorReporter.warning(
 | 
									m_errorReporter.warning(
 | 
				
			||||||
					_operation.location(),
 | 
										_operation.location(),
 | 
				
			||||||
					"Result of exponentiation has type " + commonType->toString() + " and thus "
 | 
										"Result of " + operation + " has type " + commonType->toString() + " and thus "
 | 
				
			||||||
					"might overflow. Silence this warning by converting the literal to the "
 | 
										"might overflow. Silence this warning by converting the literal to the "
 | 
				
			||||||
					"expected type."
 | 
										"expected type."
 | 
				
			||||||
				);
 | 
									);
 | 
				
			||||||
@ -1518,6 +1558,8 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (!contract)
 | 
							if (!contract)
 | 
				
			||||||
			m_errorReporter.fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
 | 
								m_errorReporter.fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
 | 
				
			||||||
 | 
							if (contract->contractKind() == ContractDefinition::ContractKind::Interface)
 | 
				
			||||||
 | 
									m_errorReporter.fatalTypeError(_newExpression.location(), "Cannot instantiate an interface.");
 | 
				
			||||||
		if (!contract->annotation().unimplementedFunctions.empty())
 | 
							if (!contract->annotation().unimplementedFunctions.empty())
 | 
				
			||||||
			m_errorReporter.typeError(
 | 
								m_errorReporter.typeError(
 | 
				
			||||||
				_newExpression.location(),
 | 
									_newExpression.location(),
 | 
				
			||||||
@ -1949,4 +1991,3 @@ void TypeChecker::requireLValue(Expression const& _expression)
 | 
				
			|||||||
	else if (!_expression.annotation().isLValue)
 | 
						else if (!_expression.annotation().isLValue)
 | 
				
			||||||
		m_errorReporter.typeError(_expression.location(), "Expression has to be an lvalue.");
 | 
							m_errorReporter.typeError(_expression.location(), "Expression has to be an lvalue.");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -62,6 +62,9 @@ private:
 | 
				
			|||||||
	/// arguments and that there is at most one constructor.
 | 
						/// arguments and that there is at most one constructor.
 | 
				
			||||||
	void checkContractDuplicateFunctions(ContractDefinition const& _contract);
 | 
						void checkContractDuplicateFunctions(ContractDefinition const& _contract);
 | 
				
			||||||
	void checkContractIllegalOverrides(ContractDefinition const& _contract);
 | 
						void checkContractIllegalOverrides(ContractDefinition const& _contract);
 | 
				
			||||||
 | 
						/// Reports a type error with an appropiate message if overriden function signature differs.
 | 
				
			||||||
 | 
						void checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super);
 | 
				
			||||||
 | 
						void overrideError(FunctionDefinition const& function, FunctionDefinition const& super, std::string message);
 | 
				
			||||||
	void checkContractAbstractFunctions(ContractDefinition const& _contract);
 | 
						void checkContractAbstractFunctions(ContractDefinition const& _contract);
 | 
				
			||||||
	void checkContractAbstractConstructors(ContractDefinition const& _contract);
 | 
						void checkContractAbstractConstructors(ContractDefinition const& _contract);
 | 
				
			||||||
	/// Checks that different functions with external visibility end up having different
 | 
						/// Checks that different functions with external visibility end up having different
 | 
				
			||||||
 | 
				
			|||||||
@ -22,6 +22,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolidity/ast/AST.h>
 | 
					#include <libsolidity/ast/AST.h>
 | 
				
			||||||
#include <libsolidity/ast/ASTVisitor.h>
 | 
					#include <libsolidity/ast/ASTVisitor.h>
 | 
				
			||||||
 | 
					#include <libsolidity/interface/Exceptions.h>
 | 
				
			||||||
#include <libsolidity/ast/AST_accept.h>
 | 
					#include <libsolidity/ast/AST_accept.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <libdevcore/SHA3.h>
 | 
					#include <libdevcore/SHA3.h>
 | 
				
			||||||
@ -188,7 +189,6 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (!m_interfaceFunctionList)
 | 
						if (!m_interfaceFunctionList)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		set<string> functionsSeen;
 | 
					 | 
				
			||||||
		set<string> signaturesSeen;
 | 
							set<string> signaturesSeen;
 | 
				
			||||||
		m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionTypePointer>>());
 | 
							m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionTypePointer>>());
 | 
				
			||||||
		for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
 | 
							for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
 | 
				
			||||||
@ -371,6 +371,15 @@ string FunctionDefinition::externalSignature() const
 | 
				
			|||||||
	return FunctionType(*this).externalSignature();
 | 
						return FunctionType(*this).externalSignature();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string FunctionDefinition::fullyQualifiedName() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						auto const* contract = dynamic_cast<ContractDefinition const*>(scope());
 | 
				
			||||||
 | 
						solAssert(contract, "Enclosing scope of function definition was not set.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto fname = name().empty() ? "<fallback>" : name();
 | 
				
			||||||
 | 
						return sourceUnitName() + ":" + contract->name() + "." + fname;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
 | 
					FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!m_annotation)
 | 
						if (!m_annotation)
 | 
				
			||||||
 | 
				
			|||||||
@ -28,6 +28,7 @@
 | 
				
			|||||||
#include <libsolidity/ast/Types.h>
 | 
					#include <libsolidity/ast/Types.h>
 | 
				
			||||||
#include <libsolidity/interface/Exceptions.h>
 | 
					#include <libsolidity/interface/Exceptions.h>
 | 
				
			||||||
#include <libsolidity/ast/ASTAnnotations.h>
 | 
					#include <libsolidity/ast/ASTAnnotations.h>
 | 
				
			||||||
 | 
					#include <libsolidity/ast/ASTEnums.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <libevmasm/SourceLocation.h>
 | 
					#include <libevmasm/SourceLocation.h>
 | 
				
			||||||
#include <libevmasm/Instruction.h>
 | 
					#include <libevmasm/Instruction.h>
 | 
				
			||||||
@ -152,6 +153,24 @@ public:
 | 
				
			|||||||
	/// Visibility ordered from restricted to unrestricted.
 | 
						/// Visibility ordered from restricted to unrestricted.
 | 
				
			||||||
	enum class Visibility { Default, Private, Internal, Public, External };
 | 
						enum class Visibility { Default, Private, Internal, Public, External };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static std::string visibilityToString(Declaration::Visibility _visibility)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							switch(_visibility)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							case Declaration::Visibility::Public:
 | 
				
			||||||
 | 
								return "public";
 | 
				
			||||||
 | 
							case Declaration::Visibility::Internal:
 | 
				
			||||||
 | 
								return "internal";
 | 
				
			||||||
 | 
							case Declaration::Visibility::Private:
 | 
				
			||||||
 | 
								return "private";
 | 
				
			||||||
 | 
							case Declaration::Visibility::External:
 | 
				
			||||||
 | 
								return "external";
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								solAssert(false, "Invalid visibility specifier.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return std::string();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Declaration(
 | 
						Declaration(
 | 
				
			||||||
		SourceLocation const& _location,
 | 
							SourceLocation const& _location,
 | 
				
			||||||
		ASTPointer<ASTString> const& _name,
 | 
							ASTPointer<ASTString> const& _name,
 | 
				
			||||||
@ -566,21 +585,19 @@ public:
 | 
				
			|||||||
		SourceLocation const& _location,
 | 
							SourceLocation const& _location,
 | 
				
			||||||
		ASTPointer<ASTString> const& _name,
 | 
							ASTPointer<ASTString> const& _name,
 | 
				
			||||||
		Declaration::Visibility _visibility,
 | 
							Declaration::Visibility _visibility,
 | 
				
			||||||
 | 
							StateMutability _stateMutability,
 | 
				
			||||||
		bool _isConstructor,
 | 
							bool _isConstructor,
 | 
				
			||||||
		ASTPointer<ASTString> const& _documentation,
 | 
							ASTPointer<ASTString> const& _documentation,
 | 
				
			||||||
		ASTPointer<ParameterList> const& _parameters,
 | 
							ASTPointer<ParameterList> const& _parameters,
 | 
				
			||||||
		bool _isDeclaredConst,
 | 
					 | 
				
			||||||
		std::vector<ASTPointer<ModifierInvocation>> const& _modifiers,
 | 
							std::vector<ASTPointer<ModifierInvocation>> const& _modifiers,
 | 
				
			||||||
		ASTPointer<ParameterList> const& _returnParameters,
 | 
							ASTPointer<ParameterList> const& _returnParameters,
 | 
				
			||||||
		bool _isPayable,
 | 
					 | 
				
			||||||
		ASTPointer<Block> const& _body
 | 
							ASTPointer<Block> const& _body
 | 
				
			||||||
	):
 | 
						):
 | 
				
			||||||
		CallableDeclaration(_location, _name, _visibility, _parameters, _returnParameters),
 | 
							CallableDeclaration(_location, _name, _visibility, _parameters, _returnParameters),
 | 
				
			||||||
		Documented(_documentation),
 | 
							Documented(_documentation),
 | 
				
			||||||
		ImplementationOptional(_body != nullptr),
 | 
							ImplementationOptional(_body != nullptr),
 | 
				
			||||||
 | 
							m_stateMutability(_stateMutability),
 | 
				
			||||||
		m_isConstructor(_isConstructor),
 | 
							m_isConstructor(_isConstructor),
 | 
				
			||||||
		m_isDeclaredConst(_isDeclaredConst),
 | 
					 | 
				
			||||||
		m_isPayable(_isPayable),
 | 
					 | 
				
			||||||
		m_functionModifiers(_modifiers),
 | 
							m_functionModifiers(_modifiers),
 | 
				
			||||||
		m_body(_body)
 | 
							m_body(_body)
 | 
				
			||||||
	{}
 | 
						{}
 | 
				
			||||||
@ -588,13 +605,14 @@ public:
 | 
				
			|||||||
	virtual void accept(ASTVisitor& _visitor) override;
 | 
						virtual void accept(ASTVisitor& _visitor) override;
 | 
				
			||||||
	virtual void accept(ASTConstVisitor& _visitor) const override;
 | 
						virtual void accept(ASTConstVisitor& _visitor) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						StateMutability stateMutability() const { return m_stateMutability; }
 | 
				
			||||||
	bool isConstructor() const { return m_isConstructor; }
 | 
						bool isConstructor() const { return m_isConstructor; }
 | 
				
			||||||
	bool isFallback() const { return name().empty(); }
 | 
						bool isFallback() const { return name().empty(); }
 | 
				
			||||||
	bool isDeclaredConst() const { return m_isDeclaredConst; }
 | 
						bool isPayable() const { return m_stateMutability == StateMutability::Payable; }
 | 
				
			||||||
	bool isPayable() const { return m_isPayable; }
 | 
					 | 
				
			||||||
	std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; }
 | 
						std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; }
 | 
				
			||||||
	std::vector<ASTPointer<VariableDeclaration>> const& returnParameters() const { return m_returnParameters->parameters(); }
 | 
						std::vector<ASTPointer<VariableDeclaration>> const& returnParameters() const { return m_returnParameters->parameters(); }
 | 
				
			||||||
	Block const& body() const { solAssert(m_body, ""); return *m_body; }
 | 
						Block const& body() const { solAssert(m_body, ""); return *m_body; }
 | 
				
			||||||
 | 
						std::string fullyQualifiedName() const;
 | 
				
			||||||
	virtual bool isVisibleInContract() const override
 | 
						virtual bool isVisibleInContract() const override
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return Declaration::isVisibleInContract() && !isConstructor() && !isFallback();
 | 
							return Declaration::isVisibleInContract() && !isConstructor() && !isFallback();
 | 
				
			||||||
@ -615,9 +633,8 @@ public:
 | 
				
			|||||||
	virtual FunctionDefinitionAnnotation& annotation() const override;
 | 
						virtual FunctionDefinitionAnnotation& annotation() const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
						StateMutability m_stateMutability;
 | 
				
			||||||
	bool m_isConstructor;
 | 
						bool m_isConstructor;
 | 
				
			||||||
	bool m_isDeclaredConst;
 | 
					 | 
				
			||||||
	bool m_isPayable;
 | 
					 | 
				
			||||||
	std::vector<ASTPointer<ModifierInvocation>> m_functionModifiers;
 | 
						std::vector<ASTPointer<ModifierInvocation>> m_functionModifiers;
 | 
				
			||||||
	ASTPointer<Block> m_body;
 | 
						ASTPointer<Block> m_body;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -819,11 +836,10 @@ private:
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class TypeName: public ASTNode
 | 
					class TypeName: public ASTNode
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					protected:
 | 
				
			||||||
	explicit TypeName(SourceLocation const& _location): ASTNode(_location) {}
 | 
						explicit TypeName(SourceLocation const& _location): ASTNode(_location) {}
 | 
				
			||||||
	virtual void accept(ASTVisitor& _visitor) override;
 | 
					 | 
				
			||||||
	virtual void accept(ASTConstVisitor& _visitor) const override;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
	virtual TypeNameAnnotation& annotation() const override;
 | 
						virtual TypeNameAnnotation& annotation() const override;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -877,11 +893,10 @@ public:
 | 
				
			|||||||
		ASTPointer<ParameterList> const& _parameterTypes,
 | 
							ASTPointer<ParameterList> const& _parameterTypes,
 | 
				
			||||||
		ASTPointer<ParameterList> const& _returnTypes,
 | 
							ASTPointer<ParameterList> const& _returnTypes,
 | 
				
			||||||
		Declaration::Visibility _visibility,
 | 
							Declaration::Visibility _visibility,
 | 
				
			||||||
		bool _isDeclaredConst,
 | 
							StateMutability _stateMutability
 | 
				
			||||||
		bool _isPayable
 | 
					 | 
				
			||||||
	):
 | 
						):
 | 
				
			||||||
		TypeName(_location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes),
 | 
							TypeName(_location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes),
 | 
				
			||||||
		m_visibility(_visibility), m_isDeclaredConst(_isDeclaredConst), m_isPayable(_isPayable)
 | 
							m_visibility(_visibility), m_stateMutability(_stateMutability)
 | 
				
			||||||
	{}
 | 
						{}
 | 
				
			||||||
	virtual void accept(ASTVisitor& _visitor) override;
 | 
						virtual void accept(ASTVisitor& _visitor) override;
 | 
				
			||||||
	virtual void accept(ASTConstVisitor& _visitor) const override;
 | 
						virtual void accept(ASTConstVisitor& _visitor) const override;
 | 
				
			||||||
@ -895,15 +910,14 @@ public:
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		return m_visibility == Declaration::Visibility::Default ? Declaration::Visibility::Internal : m_visibility;
 | 
							return m_visibility == Declaration::Visibility::Default ? Declaration::Visibility::Internal : m_visibility;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bool isDeclaredConst() const { return m_isDeclaredConst; }
 | 
						StateMutability stateMutability() const { return m_stateMutability; }
 | 
				
			||||||
	bool isPayable() const { return m_isPayable; }
 | 
						bool isPayable() const { return m_stateMutability == StateMutability::Payable; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	ASTPointer<ParameterList> m_parameterTypes;
 | 
						ASTPointer<ParameterList> m_parameterTypes;
 | 
				
			||||||
	ASTPointer<ParameterList> m_returnTypes;
 | 
						ASTPointer<ParameterList> m_returnTypes;
 | 
				
			||||||
	Declaration::Visibility m_visibility;
 | 
						Declaration::Visibility m_visibility;
 | 
				
			||||||
	bool m_isDeclaredConst;
 | 
						StateMutability m_stateMutability;
 | 
				
			||||||
	bool m_isPayable;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <libsolidity/ast/ASTForward.h>
 | 
					#include <libsolidity/ast/ASTForward.h>
 | 
				
			||||||
 | 
					#include <libsolidity/ast/ExperimentalFeatures.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <map>
 | 
					#include <map>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
@ -61,6 +62,8 @@ struct SourceUnitAnnotation: ASTAnnotation
 | 
				
			|||||||
	std::string path;
 | 
						std::string path;
 | 
				
			||||||
	/// The exported symbols (all global symbols).
 | 
						/// The exported symbols (all global symbols).
 | 
				
			||||||
	std::map<ASTString, std::vector<Declaration const*>> exportedSymbols;
 | 
						std::map<ASTString, std::vector<Declaration const*>> exportedSymbols;
 | 
				
			||||||
 | 
						/// Experimental features.
 | 
				
			||||||
 | 
						std::set<ExperimentalFeature> experimentalFeatures;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ImportAnnotation: ASTAnnotation
 | 
					struct ImportAnnotation: ASTAnnotation
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										54
									
								
								libsolidity/ast/ASTEnums.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								libsolidity/ast/ASTEnums.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					    This file is part of solidity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    solidity is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					    it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					    the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					    (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    solidity is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					    GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					    along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @date 2017
 | 
				
			||||||
 | 
					 * Enums for AST classes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/interface/Exceptions.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace dev
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					namespace solidity
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// How a function can mutate the EVM state.
 | 
				
			||||||
 | 
					enum class StateMutability { Pure, View, NonPayable, Payable };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline std::string stateMutabilityToString(StateMutability const& _stateMutability)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch(_stateMutability)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						case StateMutability::Pure:
 | 
				
			||||||
 | 
							return "pure";
 | 
				
			||||||
 | 
						case StateMutability::View:
 | 
				
			||||||
 | 
							return "view";
 | 
				
			||||||
 | 
						case StateMutability::NonPayable:
 | 
				
			||||||
 | 
							return "nonpayable";
 | 
				
			||||||
 | 
						case StateMutability::Payable:
 | 
				
			||||||
 | 
							return "payable";
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							solAssert(false, "Unknown state mutability.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -95,6 +95,5 @@ using ASTPointer = std::shared_ptr<T>;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using ASTString = std::string;
 | 
					using ASTString = std::string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -15,8 +15,7 @@
 | 
				
			|||||||
    along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
					    along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @author Lefteris <lefteris@ethdev.com>
 | 
					 * @date 2017
 | 
				
			||||||
 * @date 2015
 | 
					 | 
				
			||||||
 * Converts the AST into json format
 | 
					 * Converts the AST into json format
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -81,28 +80,30 @@ void ASTJsonConverter::setJsonNode(
 | 
				
			|||||||
			(_nodeType == "InlineAssembly") ||
 | 
								(_nodeType == "InlineAssembly") ||
 | 
				
			||||||
			(_nodeType == "Throw")
 | 
								(_nodeType == "Throw")
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		{
 | 
								m_currentValue["children"] = Json::arrayValue;
 | 
				
			||||||
			Json::Value children(Json::arrayValue);
 | 
					 | 
				
			||||||
			m_currentValue["children"] = children;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (auto& e: _attributes)
 | 
							for (auto& e: _attributes)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (
 | 
								if ((!e.second.isNull()) && (
 | 
				
			||||||
				(!e.second.isNull()) &&
 | 
									(e.second.isObject() && e.second.isMember("name")) ||
 | 
				
			||||||
					(
 | 
									(e.second.isArray() && e.second[0].isObject() && e.second[0].isMember("name")) ||
 | 
				
			||||||
					(e.second.isObject() && e.second.isMember("name")) ||
 | 
									(e.first == "declarations") // (in the case (_,x)= ... there's a nullpointer at [0]
 | 
				
			||||||
					(e.second.isArray() && e.second[0].isObject() && e.second[0].isMember("name")) ||
 | 
								))
 | 
				
			||||||
					(e.first == "declarations") // (in the case (_,x)= ... there's a nullpointer at [0]
 | 
					 | 
				
			||||||
					)
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				if (e.second.isObject())
 | 
									if (e.second.isObject())
 | 
				
			||||||
					m_currentValue["children"].append(std::move(e.second));
 | 
									{
 | 
				
			||||||
 | 
										if (!m_currentValue["children"].isArray())
 | 
				
			||||||
 | 
											m_currentValue["children"] = Json::arrayValue;
 | 
				
			||||||
 | 
										appendMove(m_currentValue["children"], std::move(e.second));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				if (e.second.isArray())
 | 
									if (e.second.isArray())
 | 
				
			||||||
					for (auto& child: e.second)
 | 
										for (auto& child: e.second)
 | 
				
			||||||
						if (!child.isNull())
 | 
											if (!child.isNull())
 | 
				
			||||||
							m_currentValue["children"].append(std::move(child));
 | 
											{
 | 
				
			||||||
 | 
												if (!m_currentValue["children"].isArray())
 | 
				
			||||||
 | 
													m_currentValue["children"] = Json::arrayValue;
 | 
				
			||||||
 | 
												appendMove(m_currentValue["children"], std::move(child));
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
@ -147,7 +148,7 @@ Json::Value ASTJsonConverter::typePointerToJson(std::shared_ptr<std::vector<Type
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		Json::Value arguments(Json::arrayValue);
 | 
							Json::Value arguments(Json::arrayValue);
 | 
				
			||||||
		for (auto const& tp: *_tps)
 | 
							for (auto const& tp: *_tps)
 | 
				
			||||||
			arguments.append(typePointerToJson(tp));
 | 
								appendMove(arguments, typePointerToJson(tp));
 | 
				
			||||||
		return arguments;
 | 
							return arguments;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
@ -186,7 +187,7 @@ void ASTJsonConverter::print(ostream& _stream, ASTNode const& _node)
 | 
				
			|||||||
	_stream << toJson(_node);
 | 
						_stream << toJson(_node);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Json::Value ASTJsonConverter::toJson(ASTNode const& _node)
 | 
					Json::Value&& ASTJsonConverter::toJson(ASTNode const& _node)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	_node.accept(*this);
 | 
						_node.accept(*this);
 | 
				
			||||||
	return std::move(m_currentValue);
 | 
						return std::move(m_currentValue);
 | 
				
			||||||
@ -285,7 +286,7 @@ bool ASTJsonConverter::visit(StructDefinition const& _node)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	setJsonNode(_node, "StructDefinition", {
 | 
						setJsonNode(_node, "StructDefinition", {
 | 
				
			||||||
		make_pair("name", _node.name()),
 | 
							make_pair("name", _node.name()),
 | 
				
			||||||
		make_pair("visibility", visibility(_node.visibility())),
 | 
							make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
 | 
				
			||||||
		make_pair("canonicalName", _node.annotation().canonicalName),
 | 
							make_pair("canonicalName", _node.annotation().canonicalName),
 | 
				
			||||||
		make_pair("members", toJson(_node.members())),
 | 
							make_pair("members", toJson(_node.members())),
 | 
				
			||||||
		make_pair("scope", idOrNull(_node.scope()))
 | 
							make_pair("scope", idOrNull(_node.scope()))
 | 
				
			||||||
@ -323,9 +324,11 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	std::vector<pair<string, Json::Value>> attributes = {
 | 
						std::vector<pair<string, Json::Value>> attributes = {
 | 
				
			||||||
		make_pair("name", _node.name()),
 | 
							make_pair("name", _node.name()),
 | 
				
			||||||
		make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.isDeclaredConst()),
 | 
							// FIXME: remove with next breaking release
 | 
				
			||||||
 | 
							make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.stateMutability() <= StateMutability::View),
 | 
				
			||||||
		make_pair("payable", _node.isPayable()),
 | 
							make_pair("payable", _node.isPayable()),
 | 
				
			||||||
		make_pair("visibility", visibility(_node.visibility())),
 | 
							make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())),
 | 
				
			||||||
 | 
							make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
 | 
				
			||||||
		make_pair("parameters", toJson(_node.parameterList())),
 | 
							make_pair("parameters", toJson(_node.parameterList())),
 | 
				
			||||||
		make_pair("isConstructor", _node.isConstructor()),
 | 
							make_pair("isConstructor", _node.isConstructor()),
 | 
				
			||||||
		make_pair("returnParameters", toJson(*_node.returnParameterList())),
 | 
							make_pair("returnParameters", toJson(*_node.returnParameterList())),
 | 
				
			||||||
@ -346,7 +349,7 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node)
 | 
				
			|||||||
		make_pair("constant", _node.isConstant()),
 | 
							make_pair("constant", _node.isConstant()),
 | 
				
			||||||
		make_pair("stateVariable", _node.isStateVariable()),
 | 
							make_pair("stateVariable", _node.isStateVariable()),
 | 
				
			||||||
		make_pair("storageLocation", location(_node.referenceLocation())),
 | 
							make_pair("storageLocation", location(_node.referenceLocation())),
 | 
				
			||||||
		make_pair("visibility", visibility(_node.visibility())),
 | 
							make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
 | 
				
			||||||
		make_pair("value", _node.value() ? toJson(*_node.value()) : Json::nullValue),
 | 
							make_pair("value", _node.value() ? toJson(*_node.value()) : Json::nullValue),
 | 
				
			||||||
		make_pair("scope", idOrNull(_node.scope())),
 | 
							make_pair("scope", idOrNull(_node.scope())),
 | 
				
			||||||
		make_pair("typeDescriptions", typePointerToJson(_node.annotation().type))
 | 
							make_pair("typeDescriptions", typePointerToJson(_node.annotation().type))
 | 
				
			||||||
@ -361,7 +364,7 @@ bool ASTJsonConverter::visit(ModifierDefinition const& _node)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	setJsonNode(_node, "ModifierDefinition", {
 | 
						setJsonNode(_node, "ModifierDefinition", {
 | 
				
			||||||
		make_pair("name", _node.name()),
 | 
							make_pair("name", _node.name()),
 | 
				
			||||||
		make_pair("visibility", visibility(_node.visibility())),
 | 
							make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
 | 
				
			||||||
		make_pair("parameters", toJson(_node.parameterList())),
 | 
							make_pair("parameters", toJson(_node.parameterList())),
 | 
				
			||||||
		make_pair("body", toJson(_node.body()))
 | 
							make_pair("body", toJson(_node.body()))
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
@ -377,12 +380,6 @@ bool ASTJsonConverter::visit(ModifierInvocation const& _node)
 | 
				
			|||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ASTJsonConverter::visit(TypeName const&)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	solAssert(false, "AST node of abstract type used.");
 | 
					 | 
				
			||||||
	return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool ASTJsonConverter::visit(EventDefinition const& _node)
 | 
					bool ASTJsonConverter::visit(EventDefinition const& _node)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	m_inEvent = true;
 | 
						m_inEvent = true;
 | 
				
			||||||
@ -418,8 +415,10 @@ bool ASTJsonConverter::visit(FunctionTypeName const& _node)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	setJsonNode(_node, "FunctionTypeName", {
 | 
						setJsonNode(_node, "FunctionTypeName", {
 | 
				
			||||||
		make_pair("payable", _node.isPayable()),
 | 
							make_pair("payable", _node.isPayable()),
 | 
				
			||||||
		make_pair("visibility", visibility(_node.visibility())),
 | 
							make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
 | 
				
			||||||
		make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.isDeclaredConst()),
 | 
							make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())),
 | 
				
			||||||
 | 
							// FIXME: remove with next breaking release
 | 
				
			||||||
 | 
							make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.stateMutability() <= StateMutability::View),
 | 
				
			||||||
		make_pair("parameterTypes", toJson(*_node.parameterTypeList())),
 | 
							make_pair("parameterTypes", toJson(*_node.parameterTypeList())),
 | 
				
			||||||
		make_pair("returnParameterTypes", toJson(*_node.returnParameterTypeList())),
 | 
							make_pair("returnParameterTypes", toJson(*_node.returnParameterTypeList())),
 | 
				
			||||||
		make_pair("typeDescriptions", typePointerToJson(_node.annotation().type))
 | 
							make_pair("typeDescriptions", typePointerToJson(_node.annotation().type))
 | 
				
			||||||
@ -545,7 +544,7 @@ bool ASTJsonConverter::visit(VariableDeclarationStatement const& _node)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	Json::Value varDecs(Json::arrayValue);
 | 
						Json::Value varDecs(Json::arrayValue);
 | 
				
			||||||
	for (auto const& v: _node.annotation().assignments)
 | 
						for (auto const& v: _node.annotation().assignments)
 | 
				
			||||||
		varDecs.append(idOrNull(v));
 | 
							appendMove(varDecs, idOrNull(v));
 | 
				
			||||||
	setJsonNode(_node, "VariableDeclarationStatement", {
 | 
						setJsonNode(_node, "VariableDeclarationStatement", {
 | 
				
			||||||
		make_pair("assignments", std::move(varDecs)),
 | 
							make_pair("assignments", std::move(varDecs)),
 | 
				
			||||||
		make_pair("declarations", toJson(_node.declarations())),
 | 
							make_pair("declarations", toJson(_node.declarations())),
 | 
				
			||||||
@ -730,23 +729,6 @@ void ASTJsonConverter::endVisit(EventDefinition const&)
 | 
				
			|||||||
	m_inEvent = false;
 | 
						m_inEvent = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
string ASTJsonConverter::visibility(Declaration::Visibility const& _visibility)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	switch (_visibility)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	case Declaration::Visibility::Private:
 | 
					 | 
				
			||||||
		return "private";
 | 
					 | 
				
			||||||
	case Declaration::Visibility::Internal:
 | 
					 | 
				
			||||||
		return "internal";
 | 
					 | 
				
			||||||
	case Declaration::Visibility::Public:
 | 
					 | 
				
			||||||
		return "public";
 | 
					 | 
				
			||||||
	case Declaration::Visibility::External:
 | 
					 | 
				
			||||||
		return "external";
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		solAssert(false, "Unknown declaration visibility.");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
string ASTJsonConverter::location(VariableDeclaration::Location _location)
 | 
					string ASTJsonConverter::location(VariableDeclaration::Location _location)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	switch (_location)
 | 
						switch (_location)
 | 
				
			||||||
 | 
				
			|||||||
@ -49,13 +49,16 @@ public:
 | 
				
			|||||||
	);
 | 
						);
 | 
				
			||||||
	/// Output the json representation of the AST to _stream.
 | 
						/// Output the json representation of the AST to _stream.
 | 
				
			||||||
	void print(std::ostream& _stream, ASTNode const& _node);
 | 
						void print(std::ostream& _stream, ASTNode const& _node);
 | 
				
			||||||
	Json::Value toJson(ASTNode const& _node);
 | 
						Json::Value&& toJson(ASTNode const& _node);
 | 
				
			||||||
	template <class T>
 | 
						template <class T>
 | 
				
			||||||
	Json::Value toJson(std::vector<ASTPointer<T>> const& _nodes)
 | 
						Json::Value toJson(std::vector<ASTPointer<T>> const& _nodes)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Json::Value ret(Json::arrayValue);
 | 
							Json::Value ret(Json::arrayValue);
 | 
				
			||||||
		for (auto const& n: _nodes)
 | 
							for (auto const& n: _nodes)
 | 
				
			||||||
			ret.append(n ? toJson(*n) : Json::nullValue);
 | 
								if (n)
 | 
				
			||||||
 | 
									appendMove(ret, toJson(*n));
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									ret.append(Json::nullValue);
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bool visit(SourceUnit const& _node) override;
 | 
						bool visit(SourceUnit const& _node) override;
 | 
				
			||||||
@ -73,7 +76,6 @@ public:
 | 
				
			|||||||
	bool visit(ModifierDefinition const& _node) override;
 | 
						bool visit(ModifierDefinition const& _node) override;
 | 
				
			||||||
	bool visit(ModifierInvocation const& _node) override;
 | 
						bool visit(ModifierInvocation const& _node) override;
 | 
				
			||||||
	bool visit(EventDefinition const& _node) override;
 | 
						bool visit(EventDefinition const& _node) override;
 | 
				
			||||||
	bool visit(TypeName const& _node) override;
 | 
					 | 
				
			||||||
	bool visit(ElementaryTypeName const& _node) override;
 | 
						bool visit(ElementaryTypeName const& _node) override;
 | 
				
			||||||
	bool visit(UserDefinedTypeName const& _node) override;
 | 
						bool visit(UserDefinedTypeName const& _node) override;
 | 
				
			||||||
	bool visit(FunctionTypeName const& _node) override;
 | 
						bool visit(FunctionTypeName const& _node) override;
 | 
				
			||||||
@ -119,7 +121,7 @@ private:
 | 
				
			|||||||
	);
 | 
						);
 | 
				
			||||||
	std::string sourceLocationToString(SourceLocation const& _location) const;
 | 
						std::string sourceLocationToString(SourceLocation const& _location) const;
 | 
				
			||||||
	std::string namePathToString(std::vector<ASTString> const& _namePath) const;
 | 
						std::string namePathToString(std::vector<ASTString> const& _namePath) const;
 | 
				
			||||||
	Json::Value idOrNull(ASTNode const* _pt)
 | 
						static Json::Value idOrNull(ASTNode const* _pt)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return _pt ? Json::Value(nodeId(*_pt)) : Json::nullValue;
 | 
							return _pt ? Json::Value(nodeId(*_pt)) : Json::nullValue;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -128,19 +130,18 @@ private:
 | 
				
			|||||||
		return _node ? toJson(*_node) : Json::nullValue;
 | 
							return _node ? toJson(*_node) : Json::nullValue;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	Json::Value inlineAssemblyIdentifierToJson(std::pair<assembly::Identifier const* , InlineAssemblyAnnotation::ExternalIdentifierInfo> _info);
 | 
						Json::Value inlineAssemblyIdentifierToJson(std::pair<assembly::Identifier const* , InlineAssemblyAnnotation::ExternalIdentifierInfo> _info);
 | 
				
			||||||
	std::string visibility(Declaration::Visibility const& _visibility);
 | 
					 | 
				
			||||||
	std::string location(VariableDeclaration::Location _location);
 | 
						std::string location(VariableDeclaration::Location _location);
 | 
				
			||||||
	std::string contractKind(ContractDefinition::ContractKind _kind);
 | 
						std::string contractKind(ContractDefinition::ContractKind _kind);
 | 
				
			||||||
	std::string functionCallKind(FunctionCallKind _kind);
 | 
						std::string functionCallKind(FunctionCallKind _kind);
 | 
				
			||||||
	std::string literalTokenKind(Token::Value _token);
 | 
						std::string literalTokenKind(Token::Value _token);
 | 
				
			||||||
	std::string type(Expression const& _expression);
 | 
						std::string type(Expression const& _expression);
 | 
				
			||||||
	std::string type(VariableDeclaration const& _varDecl);
 | 
						std::string type(VariableDeclaration const& _varDecl);
 | 
				
			||||||
	int nodeId(ASTNode const& _node)
 | 
						static int nodeId(ASTNode const& _node)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return _node.id();
 | 
							return _node.id();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	template<class Container>
 | 
						template<class Container>
 | 
				
			||||||
	Json::Value getContainerIds(Container const& container)
 | 
						static Json::Value getContainerIds(Container const& container)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Json::Value tmp(Json::arrayValue);
 | 
							Json::Value tmp(Json::arrayValue);
 | 
				
			||||||
		for (auto const& element: container)
 | 
							for (auto const& element: container)
 | 
				
			||||||
@ -156,6 +157,12 @@ private:
 | 
				
			|||||||
		std::vector<std::pair<std::string, Json::Value>> &_attributes,
 | 
							std::vector<std::pair<std::string, Json::Value>> &_attributes,
 | 
				
			||||||
		ExpressionAnnotation const& _annotation
 | 
							ExpressionAnnotation const& _annotation
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
 | 
						static void appendMove(Json::Value& _array, Json::Value&& _value)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							solAssert(_array.isArray(), "");
 | 
				
			||||||
 | 
							_array.append(std::move(_value));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool m_legacy = false; ///< if true, use legacy format
 | 
						bool m_legacy = false; ///< if true, use legacy format
 | 
				
			||||||
	bool m_inEvent = false; ///< whether we are currently inside an event or not
 | 
						bool m_inEvent = false; ///< whether we are currently inside an event or not
 | 
				
			||||||
	Json::Value m_currentValue;
 | 
						Json::Value m_currentValue;
 | 
				
			||||||
 | 
				
			|||||||
@ -105,7 +105,7 @@ bool ASTPrinter::visit(FunctionDefinition const& _node)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	writeLine("FunctionDefinition \"" + _node.name() + "\"" +
 | 
						writeLine("FunctionDefinition \"" + _node.name() + "\"" +
 | 
				
			||||||
			  (_node.isPublic() ? " - public" : "") +
 | 
								  (_node.isPublic() ? " - public" : "") +
 | 
				
			||||||
			  (_node.isDeclaredConst() ? " - const" : ""));
 | 
								  (_node.stateMutability() == StateMutability::View ? " - const" : ""));
 | 
				
			||||||
	printSourcePart(_node);
 | 
						printSourcePart(_node);
 | 
				
			||||||
	return goDeeper();
 | 
						return goDeeper();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -143,13 +143,6 @@ bool ASTPrinter::visit(EventDefinition const& _node)
 | 
				
			|||||||
	return goDeeper();
 | 
						return goDeeper();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ASTPrinter::visit(TypeName const& _node)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	writeLine("TypeName");
 | 
					 | 
				
			||||||
	printSourcePart(_node);
 | 
					 | 
				
			||||||
	return goDeeper();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool ASTPrinter::visit(ElementaryTypeName const& _node)
 | 
					bool ASTPrinter::visit(ElementaryTypeName const& _node)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	writeLine(string("ElementaryTypeName ") + _node.typeName().toString());
 | 
						writeLine(string("ElementaryTypeName ") + _node.typeName().toString());
 | 
				
			||||||
@ -434,11 +427,6 @@ void ASTPrinter::endVisit(EventDefinition const&)
 | 
				
			|||||||
	m_indentation--;
 | 
						m_indentation--;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ASTPrinter::endVisit(TypeName const&)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	m_indentation--;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ASTPrinter::endVisit(ElementaryTypeName const&)
 | 
					void ASTPrinter::endVisit(ElementaryTypeName const&)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	m_indentation--;
 | 
						m_indentation--;
 | 
				
			||||||
 | 
				
			|||||||
@ -60,7 +60,6 @@ public:
 | 
				
			|||||||
	bool visit(ModifierDefinition const& _node) override;
 | 
						bool visit(ModifierDefinition const& _node) override;
 | 
				
			||||||
	bool visit(ModifierInvocation const& _node) override;
 | 
						bool visit(ModifierInvocation const& _node) override;
 | 
				
			||||||
	bool visit(EventDefinition const& _node) override;
 | 
						bool visit(EventDefinition const& _node) override;
 | 
				
			||||||
	bool visit(TypeName const& _node) override;
 | 
					 | 
				
			||||||
	bool visit(ElementaryTypeName const& _node) override;
 | 
						bool visit(ElementaryTypeName const& _node) override;
 | 
				
			||||||
	bool visit(UserDefinedTypeName const& _node) override;
 | 
						bool visit(UserDefinedTypeName const& _node) override;
 | 
				
			||||||
	bool visit(FunctionTypeName const& _node) override;
 | 
						bool visit(FunctionTypeName const& _node) override;
 | 
				
			||||||
@ -104,7 +103,6 @@ public:
 | 
				
			|||||||
	void endVisit(ModifierDefinition const&) override;
 | 
						void endVisit(ModifierDefinition const&) override;
 | 
				
			||||||
	void endVisit(ModifierInvocation const&) override;
 | 
						void endVisit(ModifierInvocation const&) override;
 | 
				
			||||||
	void endVisit(EventDefinition const&) override;
 | 
						void endVisit(EventDefinition const&) override;
 | 
				
			||||||
	void endVisit(TypeName const&) override;
 | 
					 | 
				
			||||||
	void endVisit(ElementaryTypeName const&) override;
 | 
						void endVisit(ElementaryTypeName const&) override;
 | 
				
			||||||
	void endVisit(UserDefinedTypeName const&) override;
 | 
						void endVisit(UserDefinedTypeName const&) override;
 | 
				
			||||||
	void endVisit(FunctionTypeName const&) override;
 | 
						void endVisit(FunctionTypeName const&) override;
 | 
				
			||||||
@ -146,7 +144,7 @@ private:
 | 
				
			|||||||
	std::string m_source;
 | 
						std::string m_source;
 | 
				
			||||||
	ASTNode const* m_ast;
 | 
						ASTNode const* m_ast;
 | 
				
			||||||
	GasEstimator::ASTGasConsumption m_gasCosts;
 | 
						GasEstimator::ASTGasConsumption m_gasCosts;
 | 
				
			||||||
	std::ostream* m_ostream;
 | 
						std::ostream* m_ostream = nullptr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -58,7 +58,6 @@ public:
 | 
				
			|||||||
	virtual bool visit(ModifierDefinition& _node) { return visitNode(_node); }
 | 
						virtual bool visit(ModifierDefinition& _node) { return visitNode(_node); }
 | 
				
			||||||
	virtual bool visit(ModifierInvocation& _node) { return visitNode(_node); }
 | 
						virtual bool visit(ModifierInvocation& _node) { return visitNode(_node); }
 | 
				
			||||||
	virtual bool visit(EventDefinition& _node) { return visitNode(_node); }
 | 
						virtual bool visit(EventDefinition& _node) { return visitNode(_node); }
 | 
				
			||||||
	virtual bool visit(TypeName& _node) { return visitNode(_node); }
 | 
					 | 
				
			||||||
	virtual bool visit(ElementaryTypeName& _node) { return visitNode(_node); }
 | 
						virtual bool visit(ElementaryTypeName& _node) { return visitNode(_node); }
 | 
				
			||||||
	virtual bool visit(UserDefinedTypeName& _node) { return visitNode(_node); }
 | 
						virtual bool visit(UserDefinedTypeName& _node) { return visitNode(_node); }
 | 
				
			||||||
	virtual bool visit(FunctionTypeName& _node) { return visitNode(_node); }
 | 
						virtual bool visit(FunctionTypeName& _node) { return visitNode(_node); }
 | 
				
			||||||
@ -104,7 +103,6 @@ public:
 | 
				
			|||||||
	virtual void endVisit(ModifierDefinition& _node) { endVisitNode(_node); }
 | 
						virtual void endVisit(ModifierDefinition& _node) { endVisitNode(_node); }
 | 
				
			||||||
	virtual void endVisit(ModifierInvocation& _node) { endVisitNode(_node); }
 | 
						virtual void endVisit(ModifierInvocation& _node) { endVisitNode(_node); }
 | 
				
			||||||
	virtual void endVisit(EventDefinition& _node) { endVisitNode(_node); }
 | 
						virtual void endVisit(EventDefinition& _node) { endVisitNode(_node); }
 | 
				
			||||||
	virtual void endVisit(TypeName& _node) { endVisitNode(_node); }
 | 
					 | 
				
			||||||
	virtual void endVisit(ElementaryTypeName& _node) { endVisitNode(_node); }
 | 
						virtual void endVisit(ElementaryTypeName& _node) { endVisitNode(_node); }
 | 
				
			||||||
	virtual void endVisit(UserDefinedTypeName& _node) { endVisitNode(_node); }
 | 
						virtual void endVisit(UserDefinedTypeName& _node) { endVisitNode(_node); }
 | 
				
			||||||
	virtual void endVisit(FunctionTypeName& _node) { endVisitNode(_node); }
 | 
						virtual void endVisit(FunctionTypeName& _node) { endVisitNode(_node); }
 | 
				
			||||||
@ -162,7 +160,6 @@ public:
 | 
				
			|||||||
	virtual bool visit(ModifierDefinition const& _node) { return visitNode(_node); }
 | 
						virtual bool visit(ModifierDefinition const& _node) { return visitNode(_node); }
 | 
				
			||||||
	virtual bool visit(ModifierInvocation const& _node) { return visitNode(_node); }
 | 
						virtual bool visit(ModifierInvocation const& _node) { return visitNode(_node); }
 | 
				
			||||||
	virtual bool visit(EventDefinition const& _node) { return visitNode(_node); }
 | 
						virtual bool visit(EventDefinition const& _node) { return visitNode(_node); }
 | 
				
			||||||
	virtual bool visit(TypeName const& _node) { return visitNode(_node); }
 | 
					 | 
				
			||||||
	virtual bool visit(ElementaryTypeName const& _node) { return visitNode(_node); }
 | 
						virtual bool visit(ElementaryTypeName const& _node) { return visitNode(_node); }
 | 
				
			||||||
	virtual bool visit(UserDefinedTypeName const& _node) { return visitNode(_node); }
 | 
						virtual bool visit(UserDefinedTypeName const& _node) { return visitNode(_node); }
 | 
				
			||||||
	virtual bool visit(FunctionTypeName const& _node) { return visitNode(_node); }
 | 
						virtual bool visit(FunctionTypeName const& _node) { return visitNode(_node); }
 | 
				
			||||||
@ -208,7 +205,6 @@ public:
 | 
				
			|||||||
	virtual void endVisit(ModifierDefinition const& _node) { endVisitNode(_node); }
 | 
						virtual void endVisit(ModifierDefinition const& _node) { endVisitNode(_node); }
 | 
				
			||||||
	virtual void endVisit(ModifierInvocation const& _node) { endVisitNode(_node); }
 | 
						virtual void endVisit(ModifierInvocation const& _node) { endVisitNode(_node); }
 | 
				
			||||||
	virtual void endVisit(EventDefinition const& _node) { endVisitNode(_node); }
 | 
						virtual void endVisit(EventDefinition const& _node) { endVisitNode(_node); }
 | 
				
			||||||
	virtual void endVisit(TypeName const& _node) { endVisitNode(_node); }
 | 
					 | 
				
			||||||
	virtual void endVisit(ElementaryTypeName const& _node) { endVisitNode(_node); }
 | 
						virtual void endVisit(ElementaryTypeName const& _node) { endVisitNode(_node); }
 | 
				
			||||||
	virtual void endVisit(UserDefinedTypeName const& _node) { endVisitNode(_node); }
 | 
						virtual void endVisit(UserDefinedTypeName const& _node) { endVisitNode(_node); }
 | 
				
			||||||
	virtual void endVisit(FunctionTypeName const& _node) { endVisitNode(_node); }
 | 
						virtual void endVisit(FunctionTypeName const& _node) { endVisitNode(_node); }
 | 
				
			||||||
 | 
				
			|||||||
@ -291,18 +291,6 @@ void EventDefinition::accept(ASTConstVisitor& _visitor) const
 | 
				
			|||||||
	_visitor.endVisit(*this);
 | 
						_visitor.endVisit(*this);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TypeName::accept(ASTVisitor& _visitor)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	_visitor.visit(*this);
 | 
					 | 
				
			||||||
	_visitor.endVisit(*this);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void TypeName::accept(ASTConstVisitor& _visitor) const
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	_visitor.visit(*this);
 | 
					 | 
				
			||||||
	_visitor.endVisit(*this);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ElementaryTypeName::accept(ASTVisitor& _visitor)
 | 
					void ElementaryTypeName::accept(ASTVisitor& _visitor)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	_visitor.visit(*this);
 | 
						_visitor.visit(*this);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										53
									
								
								libsolidity/ast/ExperimentalFeatures.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								libsolidity/ast/ExperimentalFeatures.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
						This file is part of solidity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
						it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
						the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
						(at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
						but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
						MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
						GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
						along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * List of experimental features.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace dev
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					namespace solidity
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class ExperimentalFeature
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						SMTChecker,
 | 
				
			||||||
 | 
						ABIEncoderV2, // new ABI encoder that makes use of JULIA
 | 
				
			||||||
 | 
						Test,
 | 
				
			||||||
 | 
						TestOnlyAnalysis
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const std::map<ExperimentalFeature, bool> ExperimentalFeatureOnlyAnalysis =
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						{ ExperimentalFeature::SMTChecker, true },
 | 
				
			||||||
 | 
						{ ExperimentalFeature::TestOnlyAnalysis, true },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const std::map<std::string, ExperimentalFeature> ExperimentalFeatureNames =
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						{ "SMTChecker", ExperimentalFeature::SMTChecker },
 | 
				
			||||||
 | 
						{ "ABIEncoderV2", ExperimentalFeature::ABIEncoderV2 },
 | 
				
			||||||
 | 
						{ "__test", ExperimentalFeature::Test },
 | 
				
			||||||
 | 
						{ "__testOnlyAnalysis", ExperimentalFeature::TestOnlyAnalysis },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -477,8 +477,8 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons
 | 
				
			|||||||
	if (isAddress())
 | 
						if (isAddress())
 | 
				
			||||||
		return {
 | 
							return {
 | 
				
			||||||
			{"balance", make_shared<IntegerType >(256)},
 | 
								{"balance", make_shared<IntegerType >(256)},
 | 
				
			||||||
			{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCall, true, false, true)},
 | 
								{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCall, true, StateMutability::Payable)},
 | 
				
			||||||
			{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCallCode, true, false, true)},
 | 
								{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCallCode, true, StateMutability::Payable)},
 | 
				
			||||||
			{"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareDelegateCall, true)},
 | 
								{"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareDelegateCall, true)},
 | 
				
			||||||
			{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
 | 
								{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
 | 
				
			||||||
			{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
 | 
								{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
 | 
				
			||||||
@ -525,19 +525,20 @@ bool FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
TypePointer FixedPointType::unaryOperatorResult(Token::Value _operator) const
 | 
					TypePointer FixedPointType::unaryOperatorResult(Token::Value _operator) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// "delete" is ok for all fixed types
 | 
						switch(_operator)
 | 
				
			||||||
	if (_operator == Token::Delete)
 | 
						{
 | 
				
			||||||
 | 
						case Token::Delete:
 | 
				
			||||||
 | 
							// "delete" is ok for all fixed types
 | 
				
			||||||
		return make_shared<TupleType>();
 | 
							return make_shared<TupleType>();
 | 
				
			||||||
	// for fixed, we allow +, -, ++ and --
 | 
						case Token::Add:
 | 
				
			||||||
	else if (
 | 
						case Token::Sub:
 | 
				
			||||||
		_operator == Token::Add || 
 | 
						case Token::Inc:
 | 
				
			||||||
		_operator == Token::Sub ||
 | 
						case Token::Dec:
 | 
				
			||||||
		_operator == Token::Inc || 
 | 
							// for fixed, we allow +, -, ++ and --
 | 
				
			||||||
		_operator == Token::Dec
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
		return shared_from_this();
 | 
							return shared_from_this();
 | 
				
			||||||
	else
 | 
						default:
 | 
				
			||||||
		return TypePointer();
 | 
							return TypePointer();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool FixedPointType::operator==(Type const& _other) const
 | 
					bool FixedPointType::operator==(Type const& _other) const
 | 
				
			||||||
@ -738,18 +739,18 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (_convertTo.category() == Category::Integer)
 | 
						if (_convertTo.category() == Category::Integer)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		auto targetType = dynamic_cast<IntegerType const*>(&_convertTo);
 | 
					 | 
				
			||||||
		if (m_value == rational(0))
 | 
							if (m_value == rational(0))
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		if (isFractional())
 | 
							if (isFractional())
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		int forSignBit = (targetType->isSigned() ? 1 : 0);
 | 
							IntegerType const& targetType = dynamic_cast<IntegerType const&>(_convertTo);
 | 
				
			||||||
 | 
							int forSignBit = (targetType.isSigned() ? 1 : 0);
 | 
				
			||||||
		if (m_value > rational(0))
 | 
							if (m_value > rational(0))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (m_value.numerator() <= (u256(-1) >> (256 - targetType->numBits() + forSignBit)))
 | 
								if (m_value.numerator() <= (u256(-1) >> (256 - targetType.numBits() + forSignBit)))
 | 
				
			||||||
				return true;
 | 
									return true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if (targetType->isSigned() && -m_value.numerator() <= (u256(1) << (targetType->numBits() - forSignBit)))
 | 
							else if (targetType.isSigned() && -m_value.numerator() <= (u256(1) << (targetType.numBits() - forSignBit)))
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -1408,6 +1409,11 @@ unsigned ArrayType::calldataEncodedSize(bool _padded) const
 | 
				
			|||||||
	return unsigned(size);
 | 
						return unsigned(size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ArrayType::isDynamicallyEncoded() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return isDynamicallySized() || baseType()->isDynamicallyEncoded();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
u256 ArrayType::storageSize() const
 | 
					u256 ArrayType::storageSize() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (isDynamicallySized())
 | 
						if (isDynamicallySized())
 | 
				
			||||||
@ -1523,8 +1529,6 @@ TypePointer ArrayType::interfaceType(bool _inLibrary) const
 | 
				
			|||||||
	TypePointer baseExt = m_baseType->interfaceType(_inLibrary);
 | 
						TypePointer baseExt = m_baseType->interfaceType(_inLibrary);
 | 
				
			||||||
	if (!baseExt)
 | 
						if (!baseExt)
 | 
				
			||||||
		return TypePointer();
 | 
							return TypePointer();
 | 
				
			||||||
	if (m_baseType->category() == Category::Array && m_baseType->isDynamicallySized())
 | 
					 | 
				
			||||||
		return TypePointer();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (isDynamicallySized())
 | 
						if (isDynamicallySized())
 | 
				
			||||||
		return make_shared<ArrayType>(DataLocation::Memory, baseExt);
 | 
							return make_shared<ArrayType>(DataLocation::Memory, baseExt);
 | 
				
			||||||
@ -1710,6 +1714,11 @@ unsigned StructType::calldataEncodedSize(bool _padded) const
 | 
				
			|||||||
	return size;
 | 
						return size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool StructType::isDynamicallyEncoded() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						solAssert(false, "Structs are not yet supported in the ABI.");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
u256 StructType::memorySize() const
 | 
					u256 StructType::memorySize() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u256 size;
 | 
						u256 size;
 | 
				
			||||||
@ -1989,8 +1998,7 @@ TypePointer TupleType::closestTemporaryType(TypePointer const& _targetType) cons
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal):
 | 
					FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal):
 | 
				
			||||||
	m_kind(_isInternal ? Kind::Internal : Kind::External),
 | 
						m_kind(_isInternal ? Kind::Internal : Kind::External),
 | 
				
			||||||
	m_isConstant(_function.isDeclaredConst()),
 | 
						m_stateMutability(_function.stateMutability()),
 | 
				
			||||||
	m_isPayable(_isInternal ? false : _function.isPayable()),
 | 
					 | 
				
			||||||
	m_declaration(&_function)
 | 
						m_declaration(&_function)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	TypePointers params;
 | 
						TypePointers params;
 | 
				
			||||||
@ -1998,6 +2006,9 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal
 | 
				
			|||||||
	TypePointers retParams;
 | 
						TypePointers retParams;
 | 
				
			||||||
	vector<string> retParamNames;
 | 
						vector<string> retParamNames;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (_isInternal && m_stateMutability == StateMutability::Payable)
 | 
				
			||||||
 | 
							m_stateMutability = StateMutability::NonPayable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	params.reserve(_function.parameters().size());
 | 
						params.reserve(_function.parameters().size());
 | 
				
			||||||
	paramNames.reserve(_function.parameters().size());
 | 
						paramNames.reserve(_function.parameters().size());
 | 
				
			||||||
	for (ASTPointer<VariableDeclaration> const& var: _function.parameters())
 | 
						for (ASTPointer<VariableDeclaration> const& var: _function.parameters())
 | 
				
			||||||
@ -2019,7 +2030,7 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FunctionType::FunctionType(VariableDeclaration const& _varDecl):
 | 
					FunctionType::FunctionType(VariableDeclaration const& _varDecl):
 | 
				
			||||||
	m_kind(Kind::External), m_isConstant(true), m_declaration(&_varDecl)
 | 
						m_kind(Kind::External), m_stateMutability(StateMutability::View), m_declaration(&_varDecl)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	TypePointers paramTypes;
 | 
						TypePointers paramTypes;
 | 
				
			||||||
	vector<string> paramNames;
 | 
						vector<string> paramNames;
 | 
				
			||||||
@ -2079,7 +2090,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FunctionType::FunctionType(EventDefinition const& _event):
 | 
					FunctionType::FunctionType(EventDefinition const& _event):
 | 
				
			||||||
	m_kind(Kind::Event), m_isConstant(true), m_declaration(&_event)
 | 
						m_kind(Kind::Event), m_stateMutability(StateMutability::View), m_declaration(&_event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	TypePointers params;
 | 
						TypePointers params;
 | 
				
			||||||
	vector<string> paramNames;
 | 
						vector<string> paramNames;
 | 
				
			||||||
@ -2096,14 +2107,10 @@ FunctionType::FunctionType(EventDefinition const& _event):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
FunctionType::FunctionType(FunctionTypeName const& _typeName):
 | 
					FunctionType::FunctionType(FunctionTypeName const& _typeName):
 | 
				
			||||||
	m_kind(_typeName.visibility() == VariableDeclaration::Visibility::External ? Kind::External : Kind::Internal),
 | 
						m_kind(_typeName.visibility() == VariableDeclaration::Visibility::External ? Kind::External : Kind::Internal),
 | 
				
			||||||
	m_isConstant(_typeName.isDeclaredConst()),
 | 
						m_stateMutability(_typeName.stateMutability())
 | 
				
			||||||
	m_isPayable(_typeName.isPayable())
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (_typeName.isPayable())
 | 
						if (_typeName.isPayable())
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		solAssert(m_kind == Kind::External, "Internal payable function type used.");
 | 
							solAssert(m_kind == Kind::External, "Internal payable function type used.");
 | 
				
			||||||
		solAssert(!m_isConstant, "Payable constant function");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for (auto const& t: _typeName.parameterTypes())
 | 
						for (auto const& t: _typeName.parameterTypes())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		solAssert(t->annotation().type, "Type not set for parameter.");
 | 
							solAssert(t->annotation().type, "Type not set for parameter.");
 | 
				
			||||||
@ -2131,7 +2138,9 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c
 | 
				
			|||||||
	FunctionDefinition const* constructor = _contract.constructor();
 | 
						FunctionDefinition const* constructor = _contract.constructor();
 | 
				
			||||||
	TypePointers parameters;
 | 
						TypePointers parameters;
 | 
				
			||||||
	strings parameterNames;
 | 
						strings parameterNames;
 | 
				
			||||||
	bool payable = false;
 | 
						StateMutability stateMutability = StateMutability::NonPayable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solAssert(_contract.contractKind() != ContractDefinition::ContractKind::Interface, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (constructor)
 | 
						if (constructor)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -2140,8 +2149,10 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c
 | 
				
			|||||||
			parameterNames.push_back(var->name());
 | 
								parameterNames.push_back(var->name());
 | 
				
			||||||
			parameters.push_back(var->annotation().type);
 | 
								parameters.push_back(var->annotation().type);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		payable = constructor->isPayable();
 | 
							if (constructor->isPayable())
 | 
				
			||||||
 | 
								stateMutability = StateMutability::Payable;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return make_shared<FunctionType>(
 | 
						return make_shared<FunctionType>(
 | 
				
			||||||
		parameters,
 | 
							parameters,
 | 
				
			||||||
		TypePointers{make_shared<ContractType>(_contract)},
 | 
							TypePointers{make_shared<ContractType>(_contract)},
 | 
				
			||||||
@ -2150,8 +2161,7 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c
 | 
				
			|||||||
		Kind::Creation,
 | 
							Kind::Creation,
 | 
				
			||||||
		false,
 | 
							false,
 | 
				
			||||||
		nullptr,
 | 
							nullptr,
 | 
				
			||||||
		false,
 | 
							stateMutability
 | 
				
			||||||
		payable
 | 
					 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2208,8 +2218,7 @@ string FunctionType::identifier() const
 | 
				
			|||||||
	case Kind::Require: id += "require";break;
 | 
						case Kind::Require: id += "require";break;
 | 
				
			||||||
	default: solAssert(false, "Unknown function location."); break;
 | 
						default: solAssert(false, "Unknown function location."); break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (isConstant())
 | 
						id += "_" + stateMutabilityToString(m_stateMutability);
 | 
				
			||||||
		id += "_constant";
 | 
					 | 
				
			||||||
	id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes);
 | 
						id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes);
 | 
				
			||||||
	if (m_gasSet)
 | 
						if (m_gasSet)
 | 
				
			||||||
		id += "gas";
 | 
							id += "gas";
 | 
				
			||||||
@ -2224,23 +2233,21 @@ bool FunctionType::operator==(Type const& _other) const
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (_other.category() != category())
 | 
						if (_other.category() != category())
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FunctionType const& other = dynamic_cast<FunctionType const&>(_other);
 | 
						FunctionType const& other = dynamic_cast<FunctionType const&>(_other);
 | 
				
			||||||
 | 
						if (
 | 
				
			||||||
	if (m_kind != other.m_kind)
 | 
							m_kind != other.m_kind ||
 | 
				
			||||||
		return false;
 | 
							m_stateMutability != other.stateMutability() ||
 | 
				
			||||||
	if (m_isConstant != other.isConstant())
 | 
							m_parameterTypes.size() != other.m_parameterTypes.size() ||
 | 
				
			||||||
 | 
							m_returnParameterTypes.size() != other.m_returnParameterTypes.size()
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (m_parameterTypes.size() != other.m_parameterTypes.size() ||
 | 
					 | 
				
			||||||
			m_returnParameterTypes.size() != other.m_returnParameterTypes.size())
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	auto typeCompare = [](TypePointer const& _a, TypePointer const& _b) -> bool { return *_a == *_b; };
 | 
						auto typeCompare = [](TypePointer const& _a, TypePointer const& _b) -> bool { return *_a == *_b; };
 | 
				
			||||||
 | 
						if (
 | 
				
			||||||
	if (!equal(m_parameterTypes.cbegin(), m_parameterTypes.cend(),
 | 
							!equal(m_parameterTypes.cbegin(), m_parameterTypes.cend(), other.m_parameterTypes.cbegin(), typeCompare) ||
 | 
				
			||||||
			   other.m_parameterTypes.cbegin(), typeCompare))
 | 
							!equal(m_returnParameterTypes.cbegin(), m_returnParameterTypes.cend(), other.m_returnParameterTypes.cbegin(), typeCompare)
 | 
				
			||||||
		return false;
 | 
						)
 | 
				
			||||||
	if (!equal(m_returnParameterTypes.cbegin(), m_returnParameterTypes.cend(),
 | 
					 | 
				
			||||||
			   other.m_returnParameterTypes.cbegin(), typeCompare))
 | 
					 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	//@todo this is ugly, but cannot be prevented right now
 | 
						//@todo this is ugly, but cannot be prevented right now
 | 
				
			||||||
	if (m_gasSet != other.m_gasSet || m_valueSet != other.m_valueSet)
 | 
						if (m_gasSet != other.m_gasSet || m_valueSet != other.m_valueSet)
 | 
				
			||||||
@ -2292,10 +2299,8 @@ string FunctionType::toString(bool _short) const
 | 
				
			|||||||
	for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
 | 
						for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
 | 
				
			||||||
		name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
 | 
							name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
 | 
				
			||||||
	name += ")";
 | 
						name += ")";
 | 
				
			||||||
	if (m_isConstant)
 | 
						if (m_stateMutability != StateMutability::NonPayable)
 | 
				
			||||||
		name += " constant";
 | 
							name += " " + stateMutabilityToString(m_stateMutability);
 | 
				
			||||||
	if (m_isPayable)
 | 
					 | 
				
			||||||
		name += " payable";
 | 
					 | 
				
			||||||
	if (m_kind == Kind::External)
 | 
						if (m_kind == Kind::External)
 | 
				
			||||||
		name += " external";
 | 
							name += " external";
 | 
				
			||||||
	if (!m_returnParameterTypes.empty())
 | 
						if (!m_returnParameterTypes.empty())
 | 
				
			||||||
@ -2344,14 +2349,26 @@ unsigned FunctionType::sizeOnStack() const
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned size = 0;
 | 
						unsigned size = 0;
 | 
				
			||||||
	if (kind == Kind::External || kind == Kind::CallCode || kind == Kind::DelegateCall)
 | 
					
 | 
				
			||||||
 | 
						switch(kind)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						case Kind::External:
 | 
				
			||||||
 | 
						case Kind::CallCode:
 | 
				
			||||||
 | 
						case Kind::DelegateCall:
 | 
				
			||||||
		size = 2;
 | 
							size = 2;
 | 
				
			||||||
	else if (kind == Kind::BareCall || kind == Kind::BareCallCode || kind == Kind::BareDelegateCall)
 | 
							break;
 | 
				
			||||||
		size = 1;
 | 
						case Kind::BareCall:
 | 
				
			||||||
	else if (kind == Kind::Internal)
 | 
						case Kind::BareCallCode:
 | 
				
			||||||
		size = 1;
 | 
						case Kind::BareDelegateCall:
 | 
				
			||||||
	else if (kind == Kind::ArrayPush || kind == Kind::ByteArrayPush)
 | 
						case Kind::Internal:
 | 
				
			||||||
 | 
						case Kind::ArrayPush:
 | 
				
			||||||
 | 
						case Kind::ByteArrayPush:
 | 
				
			||||||
		size = 1;
 | 
							size = 1;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (m_gasSet)
 | 
						if (m_gasSet)
 | 
				
			||||||
		size++;
 | 
							size++;
 | 
				
			||||||
	if (m_valueSet)
 | 
						if (m_valueSet)
 | 
				
			||||||
@ -2389,10 +2406,14 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
 | 
				
			|||||||
		return FunctionTypePointer();
 | 
							return FunctionTypePointer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return make_shared<FunctionType>(
 | 
						return make_shared<FunctionType>(
 | 
				
			||||||
		paramTypes, retParamTypes,
 | 
							paramTypes,
 | 
				
			||||||
		m_parameterNames, m_returnParameterNames,
 | 
							retParamTypes,
 | 
				
			||||||
		m_kind, m_arbitraryParameters,
 | 
							m_parameterNames,
 | 
				
			||||||
		m_declaration, m_isConstant, m_isPayable
 | 
							m_returnParameterNames,
 | 
				
			||||||
 | 
							m_kind,
 | 
				
			||||||
 | 
							m_arbitraryParameters,
 | 
				
			||||||
 | 
							m_declaration,
 | 
				
			||||||
 | 
							m_stateMutability
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2409,7 +2430,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
 | 
				
			|||||||
		MemberList::MemberMap members;
 | 
							MemberList::MemberMap members;
 | 
				
			||||||
		if (m_kind != Kind::BareDelegateCall && m_kind != Kind::DelegateCall)
 | 
							if (m_kind != Kind::BareDelegateCall && m_kind != Kind::DelegateCall)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (m_isPayable)
 | 
								if (isPayable())
 | 
				
			||||||
				members.push_back(MemberList::Member(
 | 
									members.push_back(MemberList::Member(
 | 
				
			||||||
					"value",
 | 
										"value",
 | 
				
			||||||
					make_shared<FunctionType>(
 | 
										make_shared<FunctionType>(
 | 
				
			||||||
@ -2420,8 +2441,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
 | 
				
			|||||||
						Kind::SetValue,
 | 
											Kind::SetValue,
 | 
				
			||||||
						false,
 | 
											false,
 | 
				
			||||||
						nullptr,
 | 
											nullptr,
 | 
				
			||||||
						false,
 | 
											StateMutability::NonPayable,
 | 
				
			||||||
						false,
 | 
					 | 
				
			||||||
						m_gasSet,
 | 
											m_gasSet,
 | 
				
			||||||
						m_valueSet
 | 
											m_valueSet
 | 
				
			||||||
					)
 | 
										)
 | 
				
			||||||
@ -2438,8 +2458,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
 | 
				
			|||||||
					Kind::SetGas,
 | 
										Kind::SetGas,
 | 
				
			||||||
					false,
 | 
										false,
 | 
				
			||||||
					nullptr,
 | 
										nullptr,
 | 
				
			||||||
					false,
 | 
										StateMutability::NonPayable,
 | 
				
			||||||
					false,
 | 
					 | 
				
			||||||
					m_gasSet,
 | 
										m_gasSet,
 | 
				
			||||||
					m_valueSet
 | 
										m_valueSet
 | 
				
			||||||
				)
 | 
									)
 | 
				
			||||||
@ -2575,8 +2594,7 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con
 | 
				
			|||||||
		m_kind,
 | 
							m_kind,
 | 
				
			||||||
		m_arbitraryParameters,
 | 
							m_arbitraryParameters,
 | 
				
			||||||
		m_declaration,
 | 
							m_declaration,
 | 
				
			||||||
		m_isConstant,
 | 
							m_stateMutability,
 | 
				
			||||||
		m_isPayable,
 | 
					 | 
				
			||||||
		m_gasSet || _setGas,
 | 
							m_gasSet || _setGas,
 | 
				
			||||||
		m_valueSet || _setValue,
 | 
							m_valueSet || _setValue,
 | 
				
			||||||
		m_bound
 | 
							m_bound
 | 
				
			||||||
@ -2625,8 +2643,7 @@ FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound)
 | 
				
			|||||||
		kind,
 | 
							kind,
 | 
				
			||||||
		m_arbitraryParameters,
 | 
							m_arbitraryParameters,
 | 
				
			||||||
		m_declaration,
 | 
							m_declaration,
 | 
				
			||||||
		m_isConstant,
 | 
							m_stateMutability,
 | 
				
			||||||
		m_isPayable,
 | 
					 | 
				
			||||||
		m_gasSet,
 | 
							m_gasSet,
 | 
				
			||||||
		m_valueSet,
 | 
							m_valueSet,
 | 
				
			||||||
		_bound
 | 
							_bound
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolidity/interface/Exceptions.h>
 | 
					#include <libsolidity/interface/Exceptions.h>
 | 
				
			||||||
#include <libsolidity/ast/ASTForward.h>
 | 
					#include <libsolidity/ast/ASTForward.h>
 | 
				
			||||||
 | 
					#include <libsolidity/ast/ASTEnums.h>
 | 
				
			||||||
#include <libsolidity/parsing/Token.h>
 | 
					#include <libsolidity/parsing/Token.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <libdevcore/Common.h>
 | 
					#include <libdevcore/Common.h>
 | 
				
			||||||
@ -187,6 +188,7 @@ public:
 | 
				
			|||||||
	/// @returns number of bytes used by this type when encoded for CALL. If it is a dynamic type,
 | 
						/// @returns number of bytes used by this type when encoded for CALL. If it is a dynamic type,
 | 
				
			||||||
	/// returns the size of the pointer (usually 32). Returns 0 if the type cannot be encoded
 | 
						/// returns the size of the pointer (usually 32). Returns 0 if the type cannot be encoded
 | 
				
			||||||
	/// in calldata.
 | 
						/// in calldata.
 | 
				
			||||||
 | 
						/// @note: This should actually not be called on types, where isDynamicallyEncoded returns true.
 | 
				
			||||||
	/// If @a _padded then it is assumed that each element is padded to a multiple of 32 bytes.
 | 
						/// If @a _padded then it is assumed that each element is padded to a multiple of 32 bytes.
 | 
				
			||||||
	virtual unsigned calldataEncodedSize(bool _padded) const { (void)_padded; return 0; }
 | 
						virtual unsigned calldataEncodedSize(bool _padded) const { (void)_padded; return 0; }
 | 
				
			||||||
	/// @returns the size of this data type in bytes when stored in memory. For memory-reference
 | 
						/// @returns the size of this data type in bytes when stored in memory. For memory-reference
 | 
				
			||||||
@ -194,8 +196,10 @@ public:
 | 
				
			|||||||
	virtual unsigned memoryHeadSize() const { return calldataEncodedSize(); }
 | 
						virtual unsigned memoryHeadSize() const { return calldataEncodedSize(); }
 | 
				
			||||||
	/// Convenience version of @see calldataEncodedSize(bool)
 | 
						/// Convenience version of @see calldataEncodedSize(bool)
 | 
				
			||||||
	unsigned calldataEncodedSize() const { return calldataEncodedSize(true); }
 | 
						unsigned calldataEncodedSize() const { return calldataEncodedSize(true); }
 | 
				
			||||||
	/// @returns true if the type is dynamically encoded in calldata
 | 
						/// @returns true if the type is a dynamic array
 | 
				
			||||||
	virtual bool isDynamicallySized() const { return false; }
 | 
						virtual bool isDynamicallySized() const { return false; }
 | 
				
			||||||
 | 
						/// @returns true if the type is dynamically encoded in the ABI
 | 
				
			||||||
 | 
						virtual bool isDynamicallyEncoded() const { return false; }
 | 
				
			||||||
	/// @returns the number of storage slots required to hold this value in storage.
 | 
						/// @returns the number of storage slots required to hold this value in storage.
 | 
				
			||||||
	/// For dynamically "allocated" types, it returns the size of the statically allocated head,
 | 
						/// For dynamically "allocated" types, it returns the size of the statically allocated head,
 | 
				
			||||||
	virtual u256 storageSize() const { return 1; }
 | 
						virtual u256 storageSize() const { return 1; }
 | 
				
			||||||
@ -609,6 +613,7 @@ public:
 | 
				
			|||||||
	virtual bool operator==(const Type& _other) const override;
 | 
						virtual bool operator==(const Type& _other) const override;
 | 
				
			||||||
	virtual unsigned calldataEncodedSize(bool _padded) const override;
 | 
						virtual unsigned calldataEncodedSize(bool _padded) const override;
 | 
				
			||||||
	virtual bool isDynamicallySized() const override { return m_hasDynamicLength; }
 | 
						virtual bool isDynamicallySized() const override { return m_hasDynamicLength; }
 | 
				
			||||||
 | 
						virtual bool isDynamicallyEncoded() const override;
 | 
				
			||||||
	virtual u256 storageSize() const override;
 | 
						virtual u256 storageSize() const override;
 | 
				
			||||||
	virtual bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
 | 
						virtual bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
 | 
				
			||||||
	virtual unsigned sizeOnStack() const override;
 | 
						virtual unsigned sizeOnStack() const override;
 | 
				
			||||||
@ -723,6 +728,7 @@ public:
 | 
				
			|||||||
	virtual std::string identifier() const override;
 | 
						virtual std::string identifier() const override;
 | 
				
			||||||
	virtual bool operator==(Type const& _other) const override;
 | 
						virtual bool operator==(Type const& _other) const override;
 | 
				
			||||||
	virtual unsigned calldataEncodedSize(bool _padded) const override;
 | 
						virtual unsigned calldataEncodedSize(bool _padded) const override;
 | 
				
			||||||
 | 
						virtual bool isDynamicallyEncoded() const override;
 | 
				
			||||||
	u256 memorySize() const;
 | 
						u256 memorySize() const;
 | 
				
			||||||
	virtual u256 storageSize() const override;
 | 
						virtual u256 storageSize() const override;
 | 
				
			||||||
	virtual bool canLiveOutsideStorage() const override { return true; }
 | 
						virtual bool canLiveOutsideStorage() const override { return true; }
 | 
				
			||||||
@ -884,8 +890,7 @@ public:
 | 
				
			|||||||
		strings const& _returnParameterTypes,
 | 
							strings const& _returnParameterTypes,
 | 
				
			||||||
		Kind _kind = Kind::Internal,
 | 
							Kind _kind = Kind::Internal,
 | 
				
			||||||
		bool _arbitraryParameters = false,
 | 
							bool _arbitraryParameters = false,
 | 
				
			||||||
		bool _constant = false,
 | 
							StateMutability _stateMutability = StateMutability::NonPayable
 | 
				
			||||||
		bool _payable = false
 | 
					 | 
				
			||||||
	): FunctionType(
 | 
						): FunctionType(
 | 
				
			||||||
		parseElementaryTypeVector(_parameterTypes),
 | 
							parseElementaryTypeVector(_parameterTypes),
 | 
				
			||||||
		parseElementaryTypeVector(_returnParameterTypes),
 | 
							parseElementaryTypeVector(_returnParameterTypes),
 | 
				
			||||||
@ -894,8 +899,7 @@ public:
 | 
				
			|||||||
		_kind,
 | 
							_kind,
 | 
				
			||||||
		_arbitraryParameters,
 | 
							_arbitraryParameters,
 | 
				
			||||||
		nullptr,
 | 
							nullptr,
 | 
				
			||||||
		_constant,
 | 
							_stateMutability
 | 
				
			||||||
		_payable
 | 
					 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -912,8 +916,7 @@ public:
 | 
				
			|||||||
		Kind _kind = Kind::Internal,
 | 
							Kind _kind = Kind::Internal,
 | 
				
			||||||
		bool _arbitraryParameters = false,
 | 
							bool _arbitraryParameters = false,
 | 
				
			||||||
		Declaration const* _declaration = nullptr,
 | 
							Declaration const* _declaration = nullptr,
 | 
				
			||||||
		bool _isConstant = false,
 | 
							StateMutability _stateMutability = StateMutability::NonPayable,
 | 
				
			||||||
		bool _isPayable = false,
 | 
					 | 
				
			||||||
		bool _gasSet = false,
 | 
							bool _gasSet = false,
 | 
				
			||||||
		bool _valueSet = false,
 | 
							bool _valueSet = false,
 | 
				
			||||||
		bool _bound = false
 | 
							bool _bound = false
 | 
				
			||||||
@ -923,12 +926,11 @@ public:
 | 
				
			|||||||
		m_parameterNames(_parameterNames),
 | 
							m_parameterNames(_parameterNames),
 | 
				
			||||||
		m_returnParameterNames(_returnParameterNames),
 | 
							m_returnParameterNames(_returnParameterNames),
 | 
				
			||||||
		m_kind(_kind),
 | 
							m_kind(_kind),
 | 
				
			||||||
 | 
							m_stateMutability(_stateMutability),
 | 
				
			||||||
		m_arbitraryParameters(_arbitraryParameters),
 | 
							m_arbitraryParameters(_arbitraryParameters),
 | 
				
			||||||
		m_gasSet(_gasSet),
 | 
							m_gasSet(_gasSet),
 | 
				
			||||||
		m_valueSet(_valueSet),
 | 
							m_valueSet(_valueSet),
 | 
				
			||||||
		m_bound(_bound),
 | 
							m_bound(_bound),
 | 
				
			||||||
		m_isConstant(_isConstant),
 | 
					 | 
				
			||||||
		m_isPayable(_isPayable),
 | 
					 | 
				
			||||||
		m_declaration(_declaration)
 | 
							m_declaration(_declaration)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		solAssert(
 | 
							solAssert(
 | 
				
			||||||
@ -980,6 +982,7 @@ public:
 | 
				
			|||||||
	/// @returns true if the ABI is used for this call (only meaningful for external calls)
 | 
						/// @returns true if the ABI is used for this call (only meaningful for external calls)
 | 
				
			||||||
	bool isBareCall() const;
 | 
						bool isBareCall() const;
 | 
				
			||||||
	Kind const& kind() const { return m_kind; }
 | 
						Kind const& kind() const { return m_kind; }
 | 
				
			||||||
 | 
						StateMutability stateMutability() const { return m_stateMutability; }
 | 
				
			||||||
	/// @returns the external signature of this function type given the function name
 | 
						/// @returns the external signature of this function type given the function name
 | 
				
			||||||
	std::string externalSignature() const;
 | 
						std::string externalSignature() const;
 | 
				
			||||||
	/// @returns the external identifier of this function (the hash of the signature).
 | 
						/// @returns the external identifier of this function (the hash of the signature).
 | 
				
			||||||
@ -990,12 +993,11 @@ public:
 | 
				
			|||||||
		return *m_declaration;
 | 
							return *m_declaration;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bool hasDeclaration() const { return !!m_declaration; }
 | 
						bool hasDeclaration() const { return !!m_declaration; }
 | 
				
			||||||
	bool isConstant() const { return m_isConstant; }
 | 
					 | 
				
			||||||
	/// @returns true if the the result of this function only depends on its arguments
 | 
						/// @returns true if the the result of this function only depends on its arguments
 | 
				
			||||||
	/// and it does not modify the state.
 | 
						/// and it does not modify the state.
 | 
				
			||||||
	/// Currently, this will only return true for internal functions like keccak and ecrecover.
 | 
						/// Currently, this will only return true for internal functions like keccak and ecrecover.
 | 
				
			||||||
	bool isPure() const;
 | 
						bool isPure() const;
 | 
				
			||||||
	bool isPayable() const { return m_isPayable; }
 | 
						bool isPayable() const { return m_stateMutability == StateMutability::Payable; }
 | 
				
			||||||
	/// @return A shared pointer of an ASTString.
 | 
						/// @return A shared pointer of an ASTString.
 | 
				
			||||||
	/// Can contain a nullptr in which case indicates absence of documentation
 | 
						/// Can contain a nullptr in which case indicates absence of documentation
 | 
				
			||||||
	ASTPointer<ASTString> documentation() const;
 | 
						ASTPointer<ASTString> documentation() const;
 | 
				
			||||||
@ -1028,13 +1030,12 @@ private:
 | 
				
			|||||||
	std::vector<std::string> m_parameterNames;
 | 
						std::vector<std::string> m_parameterNames;
 | 
				
			||||||
	std::vector<std::string> m_returnParameterNames;
 | 
						std::vector<std::string> m_returnParameterNames;
 | 
				
			||||||
	Kind const m_kind;
 | 
						Kind const m_kind;
 | 
				
			||||||
 | 
						StateMutability m_stateMutability = StateMutability::NonPayable;
 | 
				
			||||||
	/// true if the function takes an arbitrary number of arguments of arbitrary types
 | 
						/// true if the function takes an arbitrary number of arguments of arbitrary types
 | 
				
			||||||
	bool const m_arbitraryParameters = false;
 | 
						bool const m_arbitraryParameters = false;
 | 
				
			||||||
	bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack
 | 
						bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack
 | 
				
			||||||
	bool const m_valueSet = false; ///< true iff the value to be sent is on the stack
 | 
						bool const m_valueSet = false; ///< true iff the value to be sent is on the stack
 | 
				
			||||||
	bool const m_bound = false; ///< true iff the function is called as arg1.fun(arg2, ..., argn)
 | 
						bool const m_bound = false; ///< true iff the function is called as arg1.fun(arg2, ..., argn)
 | 
				
			||||||
	bool m_isConstant = false;
 | 
					 | 
				
			||||||
	bool m_isPayable = false;
 | 
					 | 
				
			||||||
	Declaration const* m_declaration = nullptr;
 | 
						Declaration const* m_declaration = nullptr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1074
									
								
								libsolidity/codegen/ABIFunctions.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1074
									
								
								libsolidity/codegen/ABIFunctions.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										172
									
								
								libsolidity/codegen/ABIFunctions.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								libsolidity/codegen/ABIFunctions.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,172 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
						This file is part of solidity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
						it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
						the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
						(at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
						but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
						MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
						GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
						along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @author Christian <chris@ethereum.org>
 | 
				
			||||||
 | 
					 * @date 2017
 | 
				
			||||||
 | 
					 * Routines that generate JULIA code related to ABI encoding, decoding and type conversions.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/ast/ASTForward.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <functional>
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace dev {
 | 
				
			||||||
 | 
					namespace solidity {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Type;
 | 
				
			||||||
 | 
					class ArrayType;
 | 
				
			||||||
 | 
					class StructType;
 | 
				
			||||||
 | 
					class FunctionType;
 | 
				
			||||||
 | 
					using TypePointer = std::shared_ptr<Type const>;
 | 
				
			||||||
 | 
					using TypePointers = std::vector<TypePointer>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Class to generate encoding and decoding functions. Also maintains a collection
 | 
				
			||||||
 | 
					/// of "functions to be generated" in order to avoid generating the same function
 | 
				
			||||||
 | 
					/// multiple times.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Make sure to include the result of ``requestedFunctions()`` to a block that
 | 
				
			||||||
 | 
					/// is visible from the code that was generated here.
 | 
				
			||||||
 | 
					class ABIFunctions
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						~ABIFunctions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// @returns assembly code block to ABI-encode values of @a _givenTypes residing on the stack
 | 
				
			||||||
 | 
						/// into memory, converting the types to @a _targetTypes on the fly.
 | 
				
			||||||
 | 
						/// Assumed variables to be present: <$value0> <$value1> ... <$value(n-1)> <$headStart>
 | 
				
			||||||
 | 
						/// Does not allocate memory (does not change the memory head pointer), but writes
 | 
				
			||||||
 | 
						/// to memory starting at $headStart and an unrestricted amount after that.
 | 
				
			||||||
 | 
						/// Assigns the end of encoded memory either to $value0 or (if that is not present)
 | 
				
			||||||
 | 
						/// to $headStart.
 | 
				
			||||||
 | 
						std::string tupleEncoder(
 | 
				
			||||||
 | 
							TypePointers const& _givenTypes,
 | 
				
			||||||
 | 
							TypePointers const& _targetTypes,
 | 
				
			||||||
 | 
							bool _encodeAsLibraryTypes = false
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// @returns auxiliary functions referenced from the block generated in @a tupleEncoder
 | 
				
			||||||
 | 
						std::string requestedFunctions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						/// @returns the name of the cleanup function for the given type and
 | 
				
			||||||
 | 
						/// adds its implementation to the requested functions.
 | 
				
			||||||
 | 
						/// @param _revertOnFailure if true, causes revert on invalid data,
 | 
				
			||||||
 | 
						/// otherwise an assertion failure.
 | 
				
			||||||
 | 
						std::string cleanupFunction(Type const& _type, bool _revertOnFailure = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// @returns the name of the function that converts a value of type @a _from
 | 
				
			||||||
 | 
						/// to a value of type @a _to. The resulting vale is guaranteed to be in range
 | 
				
			||||||
 | 
						/// (i.e. "clean"). Asserts on failure.
 | 
				
			||||||
 | 
						std::string conversionFunction(Type const& _from, Type const& _to);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string cleanupCombinedExternalFunctionIdFunction();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// @returns a function that combines the address and selector to a single value
 | 
				
			||||||
 | 
						/// for use in the ABI.
 | 
				
			||||||
 | 
						std::string combineExternalFunctionIdFunction();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// @returns the name of the ABI encoding function with the given type
 | 
				
			||||||
 | 
						/// and queues the generation of the function to the requested functions.
 | 
				
			||||||
 | 
						/// @param _compacted if true, the input value was just loaded from storage
 | 
				
			||||||
 | 
						/// or memory and thus might be compacted into a single slot (depending on the type).
 | 
				
			||||||
 | 
						std::string abiEncodingFunction(
 | 
				
			||||||
 | 
							Type const& _givenType,
 | 
				
			||||||
 | 
							Type const& _targetType,
 | 
				
			||||||
 | 
							bool _encodeAsLibraryTypes,
 | 
				
			||||||
 | 
							bool _compacted
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
						/// Part of @a abiEncodingFunction for array target type and given calldata array.
 | 
				
			||||||
 | 
						std::string abiEncodingFunctionCalldataArray(
 | 
				
			||||||
 | 
							Type const& _givenType,
 | 
				
			||||||
 | 
							Type const& _targetType,
 | 
				
			||||||
 | 
							bool _encodeAsLibraryTypes
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
						/// Part of @a abiEncodingFunction for array target type and given memory array or
 | 
				
			||||||
 | 
						/// a given storage array with one item per slot.
 | 
				
			||||||
 | 
						std::string abiEncodingFunctionSimpleArray(
 | 
				
			||||||
 | 
							ArrayType const& _givenType,
 | 
				
			||||||
 | 
							ArrayType const& _targetType,
 | 
				
			||||||
 | 
							bool _encodeAsLibraryTypes
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
						std::string abiEncodingFunctionMemoryByteArray(
 | 
				
			||||||
 | 
							ArrayType const& _givenType,
 | 
				
			||||||
 | 
							ArrayType const& _targetType,
 | 
				
			||||||
 | 
							bool _encodeAsLibraryTypes
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
						/// Part of @a abiEncodingFunction for array target type and given storage array
 | 
				
			||||||
 | 
						/// where multiple items are packed into the same storage slot.
 | 
				
			||||||
 | 
						std::string abiEncodingFunctionCompactStorageArray(
 | 
				
			||||||
 | 
							ArrayType const& _givenType,
 | 
				
			||||||
 | 
							ArrayType const& _targetType,
 | 
				
			||||||
 | 
							bool _encodeAsLibraryTypes
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// @returns the name of the ABI encoding function with the given type
 | 
				
			||||||
 | 
						// and queues the generation of the function to the requested functions.
 | 
				
			||||||
 | 
						// Case for _givenType being a string literal
 | 
				
			||||||
 | 
						std::string abiEncodingFunctionStringLiteral(
 | 
				
			||||||
 | 
							Type const& _givenType,
 | 
				
			||||||
 | 
							Type const& _targetType,
 | 
				
			||||||
 | 
							bool _encodeAsLibraryTypes
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string abiEncodingFunctionFunctionType(
 | 
				
			||||||
 | 
							FunctionType const& _from,
 | 
				
			||||||
 | 
							Type const& _to,
 | 
				
			||||||
 | 
							bool _encodeAsLibraryTypes,
 | 
				
			||||||
 | 
							bool _compacted
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// @returns a function that copies raw bytes of dynamic length from calldata
 | 
				
			||||||
 | 
						/// or memory to memory.
 | 
				
			||||||
 | 
						/// Pads with zeros and might write more than exactly length.
 | 
				
			||||||
 | 
						std::string copyToMemoryFunction(bool _fromCalldata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string shiftLeftFunction(size_t _numBits);
 | 
				
			||||||
 | 
						std::string shiftRightFunction(size_t _numBits, bool _signed);
 | 
				
			||||||
 | 
						/// @returns the name of a function that rounds its input to the next multiple
 | 
				
			||||||
 | 
						/// of 32 or the input if it is a multiple of 32.
 | 
				
			||||||
 | 
						std::string roundUpFunction();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string arrayLengthFunction(ArrayType const& _type);
 | 
				
			||||||
 | 
						/// @returns the name of a function that converts a storage slot number
 | 
				
			||||||
 | 
						/// or a memory pointer to the slot number / memory pointer for the data position of an array
 | 
				
			||||||
 | 
						/// which is stored in that slot / memory area.
 | 
				
			||||||
 | 
						std::string arrayDataAreaFunction(ArrayType const& _type);
 | 
				
			||||||
 | 
						/// @returns the name of a function that advances an array data pointer to the next element.
 | 
				
			||||||
 | 
						/// Only works for memory arrays and storage arrays that store one item per slot.
 | 
				
			||||||
 | 
						std::string nextArrayElementFunction(ArrayType const& _type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Helper function that uses @a _creator to create a function and add it to
 | 
				
			||||||
 | 
						/// @a m_requestedFunctions if it has not been created yet and returns @a _name in both
 | 
				
			||||||
 | 
						/// cases.
 | 
				
			||||||
 | 
						std::string createFunction(std::string const& _name, std::function<std::string()> const& _creator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// @returns the size of the static part of the encoding of the given types.
 | 
				
			||||||
 | 
						static size_t headSize(TypePointers const& _targetTypes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Map from function name to code for a multi-use function.
 | 
				
			||||||
 | 
						std::map<std::string, std::string> m_requestedFunctions;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -40,7 +40,7 @@ using TypePointer = std::shared_ptr<Type const>;
 | 
				
			|||||||
class ArrayUtils
 | 
					class ArrayUtils
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	ArrayUtils(CompilerContext& _context): m_context(_context) {}
 | 
						explicit ArrayUtils(CompilerContext& _context): m_context(_context) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Copies an array to an array in storage. The arrays can be of different types only if
 | 
						/// Copies an array to an array in storage. The arrays can be of different types only if
 | 
				
			||||||
	/// their storage representation is the same.
 | 
						/// their storage representation is the same.
 | 
				
			||||||
 | 
				
			|||||||
@ -51,9 +51,9 @@ public:
 | 
				
			|||||||
		ContractDefinition const& _contract,
 | 
							ContractDefinition const& _contract,
 | 
				
			||||||
		std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts
 | 
							std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
	eth::Assembly const& assembly() { return m_context.assembly(); }
 | 
						eth::Assembly const& assembly() const { return m_context.assembly(); }
 | 
				
			||||||
	eth::LinkerObject assembledObject() { return m_context.assembledObject(); }
 | 
						eth::LinkerObject assembledObject() const { return m_context.assembledObject(); }
 | 
				
			||||||
	eth::LinkerObject runtimeObject() { return m_context.assembledRuntimeObject(m_runtimeSub); }
 | 
						eth::LinkerObject runtimeObject() const { return m_context.assembledRuntimeObject(m_runtimeSub); }
 | 
				
			||||||
	/// @arg _sourceCodes is the map of input files to source code strings
 | 
						/// @arg _sourceCodes is the map of input files to source code strings
 | 
				
			||||||
	/// @arg _inJsonFromat shows whether the out should be in Json format
 | 
						/// @arg _inJsonFromat shows whether the out should be in Json format
 | 
				
			||||||
	Json::Value 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
 | 
				
			||||||
 | 
				
			|||||||
@ -44,11 +44,6 @@ namespace dev
 | 
				
			|||||||
namespace solidity
 | 
					namespace solidity
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CompilerContext::addMagicGlobal(MagicVariableDeclaration const& _declaration)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	m_magicGlobals.insert(&_declaration);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void CompilerContext::addStateVariable(
 | 
					void CompilerContext::addStateVariable(
 | 
				
			||||||
	VariableDeclaration const& _declaration,
 | 
						VariableDeclaration const& _declaration,
 | 
				
			||||||
	u256 const& _storageOffset,
 | 
						u256 const& _storageOffset,
 | 
				
			||||||
 | 
				
			|||||||
@ -48,7 +48,7 @@ namespace solidity {
 | 
				
			|||||||
class CompilerContext
 | 
					class CompilerContext
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	CompilerContext(CompilerContext* _runtimeContext = nullptr):
 | 
						explicit CompilerContext(CompilerContext* _runtimeContext = nullptr):
 | 
				
			||||||
		m_asm(std::make_shared<eth::Assembly>()),
 | 
							m_asm(std::make_shared<eth::Assembly>()),
 | 
				
			||||||
		m_runtimeContext(_runtimeContext)
 | 
							m_runtimeContext(_runtimeContext)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -56,7 +56,9 @@ public:
 | 
				
			|||||||
			m_runtimeSub = size_t(m_asm->newSub(m_runtimeContext->m_asm).data());
 | 
								m_runtimeSub = size_t(m_asm->newSub(m_runtimeContext->m_asm).data());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void addMagicGlobal(MagicVariableDeclaration const& _declaration);
 | 
						void setExperimentalFeatures(std::set<ExperimentalFeature> const& _features) { m_experimentalFeatures = _features; }
 | 
				
			||||||
 | 
						bool experimentalFeatureActive(ExperimentalFeature _feature) const { return m_experimentalFeatures.count(_feature); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset);
 | 
						void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset);
 | 
				
			||||||
	void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0);
 | 
						void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0);
 | 
				
			||||||
	void removeVariable(VariableDeclaration const& _declaration);
 | 
						void removeVariable(VariableDeclaration const& _declaration);
 | 
				
			||||||
@ -68,7 +70,6 @@ public:
 | 
				
			|||||||
	void adjustStackOffset(int _adjustment) { m_asm->adjustDeposit(_adjustment); }
 | 
						void adjustStackOffset(int _adjustment) { m_asm->adjustDeposit(_adjustment); }
 | 
				
			||||||
	unsigned stackHeight() const { solAssert(m_asm->deposit() >= 0, ""); return unsigned(m_asm->deposit()); }
 | 
						unsigned stackHeight() const { solAssert(m_asm->deposit() >= 0, ""); return unsigned(m_asm->deposit()); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration) != 0; }
 | 
					 | 
				
			||||||
	bool isLocalVariable(Declaration const* _declaration) const;
 | 
						bool isLocalVariable(Declaration const* _declaration) const;
 | 
				
			||||||
	bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration) != 0; }
 | 
						bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration) != 0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -207,8 +208,8 @@ public:
 | 
				
			|||||||
		return m_asm->stream(_stream, "", _sourceCodes, _inJsonFormat);
 | 
							return m_asm->stream(_stream, "", _sourceCodes, _inJsonFormat);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	eth::LinkerObject const& assembledObject() { return m_asm->assemble(); }
 | 
						eth::LinkerObject const& assembledObject() const { return m_asm->assemble(); }
 | 
				
			||||||
	eth::LinkerObject const& assembledRuntimeObject(size_t _subIndex) { return m_asm->sub(_subIndex).assemble(); }
 | 
						eth::LinkerObject const& assembledRuntimeObject(size_t _subIndex) const { return m_asm->sub(_subIndex).assemble(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Helper class to pop the visited nodes stack when a scope closes
 | 
						 * Helper class to pop the visited nodes stack when a scope closes
 | 
				
			||||||
@ -265,8 +266,8 @@ private:
 | 
				
			|||||||
	} m_functionCompilationQueue;
 | 
						} m_functionCompilationQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	eth::AssemblyPointer m_asm;
 | 
						eth::AssemblyPointer m_asm;
 | 
				
			||||||
	/// Magic global variables like msg, tx or this, distinguished by type.
 | 
						/// Activated experimental features.
 | 
				
			||||||
	std::set<Declaration const*> m_magicGlobals;
 | 
						std::set<ExperimentalFeature> m_experimentalFeatures;
 | 
				
			||||||
	/// Other already compiled contracts to be used in contract creation calls.
 | 
						/// Other already compiled contracts to be used in contract creation calls.
 | 
				
			||||||
	std::map<ContractDefinition const*, eth::Assembly const*> m_compiledContracts;
 | 
						std::map<ContractDefinition const*, eth::Assembly const*> m_compiledContracts;
 | 
				
			||||||
	/// Storage offsets of state variables
 | 
						/// Storage offsets of state variables
 | 
				
			||||||
 | 
				
			|||||||
@ -25,6 +25,7 @@
 | 
				
			|||||||
#include <libevmasm/Instruction.h>
 | 
					#include <libevmasm/Instruction.h>
 | 
				
			||||||
#include <libsolidity/codegen/ArrayUtils.h>
 | 
					#include <libsolidity/codegen/ArrayUtils.h>
 | 
				
			||||||
#include <libsolidity/codegen/LValue.h>
 | 
					#include <libsolidity/codegen/LValue.h>
 | 
				
			||||||
 | 
					#include <libsolidity/codegen/ABIFunctions.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					using namespace std;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -182,6 +183,18 @@ void CompilerUtils::encodeToMemory(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (_givenTypes.empty())
 | 
						if (_givenTypes.empty())
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
						else if (
 | 
				
			||||||
 | 
							_padToWordBoundaries &&
 | 
				
			||||||
 | 
							!_copyDynamicDataInPlace &&
 | 
				
			||||||
 | 
							m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// Use the new JULIA-based encoding function
 | 
				
			||||||
 | 
							auto stackHeightBefore = m_context.stackHeight();
 | 
				
			||||||
 | 
							abiEncode(_givenTypes, targetTypes, _encodeAsLibraryTypes);
 | 
				
			||||||
 | 
							solAssert(stackHeightBefore - m_context.stackHeight() == sizeOnStack(_givenTypes), "");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Stack during operation:
 | 
						// Stack during operation:
 | 
				
			||||||
	// <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
 | 
						// <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
 | 
				
			||||||
@ -289,6 +302,28 @@ void CompilerUtils::encodeToMemory(
 | 
				
			|||||||
	popStackSlots(argSize + dynPointers + 1);
 | 
						popStackSlots(argSize + dynPointers + 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CompilerUtils::abiEncode(
 | 
				
			||||||
 | 
						TypePointers const& _givenTypes,
 | 
				
			||||||
 | 
						TypePointers const& _targetTypes,
 | 
				
			||||||
 | 
						bool _encodeAsLibraryTypes
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// stack: <$value0> <$value1> ... <$value(n-1)> <$headStart>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vector<string> variables;
 | 
				
			||||||
 | 
						size_t numValues = sizeOnStack(_givenTypes);
 | 
				
			||||||
 | 
						for (size_t i = 0; i < numValues; ++i)
 | 
				
			||||||
 | 
								variables.push_back("$value" + to_string(i));
 | 
				
			||||||
 | 
						variables.push_back("$headStart");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ABIFunctions funs;
 | 
				
			||||||
 | 
						string routine = funs.tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes);
 | 
				
			||||||
 | 
						routine += funs.requestedFunctions();
 | 
				
			||||||
 | 
						m_context.appendInlineAssembly("{" + routine + "}", variables);
 | 
				
			||||||
 | 
						// Remove everyhing except for "value0" / the final memory pointer.
 | 
				
			||||||
 | 
						popStackSlots(numValues);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
 | 
					void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto repeat = m_context.newTag();
 | 
						auto repeat = m_context.newTag();
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,7 @@ class Type; // forward
 | 
				
			|||||||
class CompilerUtils
 | 
					class CompilerUtils
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	CompilerUtils(CompilerContext& _context): m_context(_context) {}
 | 
						explicit CompilerUtils(CompilerContext& _context): m_context(_context) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Stores the initial value of the free-memory-pointer at its position;
 | 
						/// Stores the initial value of the free-memory-pointer at its position;
 | 
				
			||||||
	void initialiseFreeMemoryPointer();
 | 
						void initialiseFreeMemoryPointer();
 | 
				
			||||||
@ -103,6 +103,14 @@ public:
 | 
				
			|||||||
		bool _encodeAsLibraryTypes = false
 | 
							bool _encodeAsLibraryTypes = false
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Special case of @a encodeToMemory which assumes that everything is padded to words
 | 
				
			||||||
 | 
						/// and dynamic data is not copied in place (i.e. a proper ABI encoding).
 | 
				
			||||||
 | 
						void abiEncode(
 | 
				
			||||||
 | 
							TypePointers const& _givenTypes,
 | 
				
			||||||
 | 
							TypePointers const& _targetTypes,
 | 
				
			||||||
 | 
							bool _encodeAsLibraryTypes = false
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Zero-initialises (the data part of) an already allocated memory array.
 | 
						/// Zero-initialises (the data part of) an already allocated memory array.
 | 
				
			||||||
	/// Length has to be nonzero!
 | 
						/// Length has to be nonzero!
 | 
				
			||||||
	/// Stack pre: <length> <memptr>
 | 
						/// Stack pre: <length> <memptr>
 | 
				
			||||||
 | 
				
			|||||||
@ -45,7 +45,7 @@ using namespace dev::solidity;
 | 
				
			|||||||
class StackHeightChecker
 | 
					class StackHeightChecker
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	StackHeightChecker(CompilerContext const& _context):
 | 
						explicit StackHeightChecker(CompilerContext const& _context):
 | 
				
			||||||
		m_context(_context), stackHeight(m_context.stackHeight()) {}
 | 
							m_context(_context), stackHeight(m_context.stackHeight()) {}
 | 
				
			||||||
	void check() { solAssert(m_context.stackHeight() == stackHeight, std::string("I sense a disturbance in the stack: ") + std::to_string(m_context.stackHeight()) + " vs " + std::to_string(stackHeight)); }
 | 
						void check() { solAssert(m_context.stackHeight() == stackHeight, std::string("I sense a disturbance in the stack: ") + std::to_string(m_context.stackHeight()) + " vs " + std::to_string(stackHeight)); }
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
@ -100,6 +100,7 @@ void ContractCompiler::initializeContext(
 | 
				
			|||||||
	map<ContractDefinition const*, eth::Assembly const*> const& _compiledContracts
 | 
						map<ContractDefinition const*, eth::Assembly const*> const& _compiledContracts
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						m_context.setExperimentalFeatures(_contract.sourceUnit().annotation().experimentalFeatures);
 | 
				
			||||||
	m_context.setCompiledContracts(_compiledContracts);
 | 
						m_context.setCompiledContracts(_compiledContracts);
 | 
				
			||||||
	m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts);
 | 
						m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts);
 | 
				
			||||||
	CompilerUtils(m_context).initialiseFreeMemoryPointer();
 | 
						CompilerUtils(m_context).initialiseFreeMemoryPointer();
 | 
				
			||||||
 | 
				
			|||||||
@ -645,8 +645,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
 | 
				
			|||||||
					FunctionType::Kind::BareCall,
 | 
										FunctionType::Kind::BareCall,
 | 
				
			||||||
					false,
 | 
										false,
 | 
				
			||||||
					nullptr,
 | 
										nullptr,
 | 
				
			||||||
					false,
 | 
										StateMutability::NonPayable,
 | 
				
			||||||
					false,
 | 
					 | 
				
			||||||
					true,
 | 
										true,
 | 
				
			||||||
					true
 | 
										true
 | 
				
			||||||
				),
 | 
									),
 | 
				
			||||||
@ -1812,7 +1811,7 @@ void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression)
 | 
				
			|||||||
	setLValue<StorageItem>(_expression, *_expression.annotation().type);
 | 
						setLValue<StorageItem>(_expression, *_expression.annotation().type);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _op)
 | 
					bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _op) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (Token::isCompareOp(_op) || Token::isShiftOp(_op))
 | 
						if (Token::isCompareOp(_op) || Token::isShiftOp(_op))
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
				
			|||||||
@ -119,7 +119,7 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/// @returns true if the operator applied to the given type requires a cleanup prior to the
 | 
						/// @returns true if the operator applied to the given type requires a cleanup prior to the
 | 
				
			||||||
	/// operation.
 | 
						/// operation.
 | 
				
			||||||
	bool cleanupNeededForOp(Type::Category _type, Token::Value _op);
 | 
						bool cleanupNeededForOp(Type::Category _type, Token::Value _op) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// @returns the CompilerUtils object containing the current context.
 | 
						/// @returns the CompilerUtils object containing the current context.
 | 
				
			||||||
	CompilerUtils utils();
 | 
						CompilerUtils utils();
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										588
									
								
								libsolidity/formal/SMTChecker.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										588
									
								
								libsolidity/formal/SMTChecker.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,588 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
						This file is part of solidity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
						it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
						the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
						(at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
						but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
						MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
						GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
						along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/formal/SMTChecker.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_Z3
 | 
				
			||||||
 | 
					#include <libsolidity/formal/Z3Interface.h>
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#include <libsolidity/formal/SMTLib2Interface.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/interface/ErrorReporter.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/range/adaptor/map.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace std;
 | 
				
			||||||
 | 
					using namespace dev;
 | 
				
			||||||
 | 
					using namespace dev::solidity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SMTChecker::SMTChecker(ErrorReporter& _errorReporter, ReadCallback::Callback const& _readFileCallback):
 | 
				
			||||||
 | 
					#ifdef HAVE_Z3
 | 
				
			||||||
 | 
						m_interface(make_shared<smt::Z3Interface>()),
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						m_interface(make_shared<smt::SMTLib2Interface>(_readFileCallback)),
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						m_errorReporter(_errorReporter)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						(void)_readFileCallback;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::analyze(SourceUnit const& _source)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_interface->reset();
 | 
				
			||||||
 | 
							m_currentSequenceCounter.clear();
 | 
				
			||||||
 | 
							m_nextFreeSequenceCounter.clear();
 | 
				
			||||||
 | 
							_source.accept(*this);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::endVisit(VariableDeclaration const& _varDecl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (_varDecl.value())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_varDecl.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet support this."
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (_varDecl.isLocalOrReturn())
 | 
				
			||||||
 | 
							createVariable(_varDecl, true);
 | 
				
			||||||
 | 
						else if (_varDecl.isCallableParameter())
 | 
				
			||||||
 | 
							createVariable(_varDecl, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool SMTChecker::visit(FunctionDefinition const& _function)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!_function.modifiers().empty() || _function.isConstructor())
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_function.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet support constructors and functions with modifiers."
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						// TODO actually we probably also have to reset all local variables and similar things.
 | 
				
			||||||
 | 
						m_currentFunction = &_function;
 | 
				
			||||||
 | 
						m_interface->push();
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::endVisit(FunctionDefinition const&)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// TOOD we could check for "reachability", i.e. satisfiability here.
 | 
				
			||||||
 | 
						// We only handle local variables, so we clear everything.
 | 
				
			||||||
 | 
						// If we add storage variables, those should be cleared differently.
 | 
				
			||||||
 | 
						m_currentSequenceCounter.clear();
 | 
				
			||||||
 | 
						m_nextFreeSequenceCounter.clear();
 | 
				
			||||||
 | 
						m_interface->pop();
 | 
				
			||||||
 | 
						m_currentFunction = nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool SMTChecker::visit(IfStatement const& _node)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						_node.condition().accept(*this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO Check if condition is always true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto countersAtStart = m_currentSequenceCounter;
 | 
				
			||||||
 | 
						m_interface->push();
 | 
				
			||||||
 | 
						m_interface->addAssertion(expr(_node.condition()));
 | 
				
			||||||
 | 
						_node.trueStatement().accept(*this);
 | 
				
			||||||
 | 
						auto countersAtEndOfTrue = m_currentSequenceCounter;
 | 
				
			||||||
 | 
						m_interface->pop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decltype(m_currentSequenceCounter) countersAtEndOfFalse;
 | 
				
			||||||
 | 
						if (_node.falseStatement())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_currentSequenceCounter = countersAtStart;
 | 
				
			||||||
 | 
							m_interface->push();
 | 
				
			||||||
 | 
							m_interface->addAssertion(!expr(_node.condition()));
 | 
				
			||||||
 | 
							_node.falseStatement()->accept(*this);
 | 
				
			||||||
 | 
							countersAtEndOfFalse = m_currentSequenceCounter;
 | 
				
			||||||
 | 
							m_interface->pop();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							countersAtEndOfFalse = countersAtStart;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Reset all values that have been touched.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO this should use a previously generated side-effect structure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solAssert(countersAtEndOfFalse.size() == countersAtEndOfTrue.size(), "");
 | 
				
			||||||
 | 
						for (auto const& declCounter: countersAtEndOfTrue)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							solAssert(countersAtEndOfFalse.count(declCounter.first), "");
 | 
				
			||||||
 | 
							auto decl = declCounter.first;
 | 
				
			||||||
 | 
							int trueCounter = countersAtEndOfTrue.at(decl);
 | 
				
			||||||
 | 
							int falseCounter = countersAtEndOfFalse.at(decl);
 | 
				
			||||||
 | 
							if (trueCounter == falseCounter)
 | 
				
			||||||
 | 
								continue; // Was not modified
 | 
				
			||||||
 | 
							newValue(*decl);
 | 
				
			||||||
 | 
							setValue(*decl, 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool SMTChecker::visit(WhileStatement const& _node)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						_node.condition().accept(*this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//m_interface->push();
 | 
				
			||||||
 | 
						//m_interface->addAssertion(expr(_node.condition()));
 | 
				
			||||||
 | 
						// TDOO clear knowledge (increment sequence numbers and add bounds assertions	) apart from assertions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO combine similar to if
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::endVisit(VariableDeclarationStatement const& _varDecl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (_varDecl.declarations().size() != 1)
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_varDecl.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet support such variable declarations."
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						else if (knownVariable(*_varDecl.declarations()[0]))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (_varDecl.initialValue())
 | 
				
			||||||
 | 
								// TODO more checks?
 | 
				
			||||||
 | 
								// TODO add restrictions about type (might be assignment from smaller type)
 | 
				
			||||||
 | 
								m_interface->addAssertion(newValue(*_varDecl.declarations()[0]) == expr(*_varDecl.initialValue()));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_varDecl.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet implement such variable declarations."
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::endVisit(ExpressionStatement const&)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::endVisit(Assignment const& _assignment)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (_assignment.assignmentOperator() != Token::Value::Assign)
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_assignment.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet implement compound assignment."
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						else if (_assignment.annotation().type->category() != Type::Category::Integer)
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_assignment.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet implement type " + _assignment.annotation().type->toString()
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						else if (Identifier const* identifier = dynamic_cast<Identifier const*>(&_assignment.leftHandSide()))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Declaration const* decl = identifier->annotation().referencedDeclaration;
 | 
				
			||||||
 | 
							if (knownVariable(*decl))
 | 
				
			||||||
 | 
								// TODO more checks?
 | 
				
			||||||
 | 
								// TODO add restrictions about type (might be assignment from smaller type)
 | 
				
			||||||
 | 
								m_interface->addAssertion(newValue(*decl) == expr(_assignment.rightHandSide()));
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								m_errorReporter.warning(
 | 
				
			||||||
 | 
									_assignment.location(),
 | 
				
			||||||
 | 
									"Assertion checker does not yet implement such assignments."
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_assignment.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet implement such assignments."
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::endVisit(TupleExpression const& _tuple)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (_tuple.isInlineArray() || _tuple.components().size() != 1)
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_tuple.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet implement tules and inline arrays."
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							m_interface->addAssertion(expr(_tuple) == expr(*_tuple.components()[0]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::endVisit(BinaryOperation const& _op)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (Token::isArithmeticOp(_op.getOperator()))
 | 
				
			||||||
 | 
							arithmeticOperation(_op);
 | 
				
			||||||
 | 
						else if (Token::isCompareOp(_op.getOperator()))
 | 
				
			||||||
 | 
							compareOperation(_op);
 | 
				
			||||||
 | 
						else if (Token::isBooleanOp(_op.getOperator()))
 | 
				
			||||||
 | 
							booleanOperation(_op);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_op.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet implement this operator."
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::endVisit(FunctionCall const& _funCall)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						FunctionType const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::vector<ASTPointer<Expression const>> const args = _funCall.arguments();
 | 
				
			||||||
 | 
						if (funType.kind() == FunctionType::Kind::Assert)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							solAssert(args.size() == 1, "");
 | 
				
			||||||
 | 
							solAssert(args[0]->annotation().type->category() == Type::Category::Bool, "");
 | 
				
			||||||
 | 
							checkCondition(!(expr(*args[0])), _funCall.location(), "Assertion violation");
 | 
				
			||||||
 | 
							m_interface->addAssertion(expr(*args[0]));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (funType.kind() == FunctionType::Kind::Require)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							solAssert(args.size() == 1, "");
 | 
				
			||||||
 | 
							solAssert(args[0]->annotation().type->category() == Type::Category::Bool, "");
 | 
				
			||||||
 | 
							m_interface->addAssertion(expr(*args[0]));
 | 
				
			||||||
 | 
							checkCondition(!(expr(*args[0])), _funCall.location(), "Unreachable code");
 | 
				
			||||||
 | 
							// TODO is there something meaningful we can check here?
 | 
				
			||||||
 | 
							// We can check whether the condition is always fulfilled or never fulfilled.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::endVisit(Identifier const& _identifier)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Declaration const* decl = _identifier.annotation().referencedDeclaration;
 | 
				
			||||||
 | 
						solAssert(decl, "");
 | 
				
			||||||
 | 
						if (dynamic_cast<IntegerType const*>(_identifier.annotation().type.get()))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_interface->addAssertion(expr(_identifier) == currentValue(*decl));
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (FunctionType const* fun = dynamic_cast<FunctionType const*>(_identifier.annotation().type.get()))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (fun->kind() == FunctionType::Kind::Assert || fun->kind() == FunctionType::Kind::Require)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							// TODO for others, clear our knowledge about storage and memory
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						m_errorReporter.warning(
 | 
				
			||||||
 | 
							_identifier.location(),
 | 
				
			||||||
 | 
							"Assertion checker does not yet support the type of this expression (" +
 | 
				
			||||||
 | 
							_identifier.annotation().type->toString() +
 | 
				
			||||||
 | 
							")."
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::endVisit(Literal const& _literal)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Type const& type = *_literal.annotation().type;
 | 
				
			||||||
 | 
						if (type.category() == Type::Category::Integer || type.category() == Type::Category::RationalNumber)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (RationalNumberType const* rational = dynamic_cast<RationalNumberType const*>(&type))
 | 
				
			||||||
 | 
								solAssert(!rational->isFractional(), "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							m_interface->addAssertion(expr(_literal) == smt::Expression(type.literalValue(&_literal)));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_literal.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet support the type of this expression (" +
 | 
				
			||||||
 | 
								_literal.annotation().type->toString() +
 | 
				
			||||||
 | 
								")."
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::arithmeticOperation(BinaryOperation const& _op)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (_op.getOperator())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						case Token::Add:
 | 
				
			||||||
 | 
						case Token::Sub:
 | 
				
			||||||
 | 
						case Token::Mul:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							solAssert(_op.annotation().commonType, "");
 | 
				
			||||||
 | 
							solAssert(_op.annotation().commonType->category() == Type::Category::Integer, "");
 | 
				
			||||||
 | 
							smt::Expression left(expr(_op.leftExpression()));
 | 
				
			||||||
 | 
							smt::Expression right(expr(_op.rightExpression()));
 | 
				
			||||||
 | 
							Token::Value op = _op.getOperator();
 | 
				
			||||||
 | 
							smt::Expression value(
 | 
				
			||||||
 | 
								op == Token::Add ? left + right :
 | 
				
			||||||
 | 
								op == Token::Sub ? left - right :
 | 
				
			||||||
 | 
								/*op == Token::Mul*/ left * right
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Overflow check
 | 
				
			||||||
 | 
							auto const& intType = dynamic_cast<IntegerType const&>(*_op.annotation().commonType);
 | 
				
			||||||
 | 
							checkCondition(
 | 
				
			||||||
 | 
								value < minValue(intType),
 | 
				
			||||||
 | 
								_op.location(),
 | 
				
			||||||
 | 
								"Underflow (resulting value less than " + formatNumber(intType.minValue()) + ")",
 | 
				
			||||||
 | 
								"value",
 | 
				
			||||||
 | 
								&value
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							checkCondition(
 | 
				
			||||||
 | 
								value > maxValue(intType),
 | 
				
			||||||
 | 
								_op.location(),
 | 
				
			||||||
 | 
								"Overflow (resulting value larger than " + formatNumber(intType.maxValue()) + ")",
 | 
				
			||||||
 | 
								"value",
 | 
				
			||||||
 | 
								&value
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							m_interface->addAssertion(expr(_op) == value);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_op.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet implement this operator."
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::compareOperation(BinaryOperation const& _op)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						solAssert(_op.annotation().commonType, "");
 | 
				
			||||||
 | 
						if (_op.annotation().commonType->category() == Type::Category::Integer)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							smt::Expression left(expr(_op.leftExpression()));
 | 
				
			||||||
 | 
							smt::Expression right(expr(_op.rightExpression()));
 | 
				
			||||||
 | 
							Token::Value op = _op.getOperator();
 | 
				
			||||||
 | 
							smt::Expression value = (
 | 
				
			||||||
 | 
								op == Token::Equal ? (left == right) :
 | 
				
			||||||
 | 
								op == Token::NotEqual ? (left != right) :
 | 
				
			||||||
 | 
								op == Token::LessThan ? (left < right) :
 | 
				
			||||||
 | 
								op == Token::LessThanOrEqual ? (left <= right) :
 | 
				
			||||||
 | 
								op == Token::GreaterThan ? (left > right) :
 | 
				
			||||||
 | 
								/*op == Token::GreaterThanOrEqual*/ (left >= right)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							// TODO: check that other values for op are not possible.
 | 
				
			||||||
 | 
							m_interface->addAssertion(expr(_op) == value);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_op.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet implement the type " + _op.annotation().commonType->toString() + " for comparisons"
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::booleanOperation(BinaryOperation const& _op)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						solAssert(_op.getOperator() == Token::And || _op.getOperator() == Token::Or, "");
 | 
				
			||||||
 | 
						solAssert(_op.annotation().commonType, "");
 | 
				
			||||||
 | 
						if (_op.annotation().commonType->category() == Type::Category::Bool)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (_op.getOperator() == Token::And)
 | 
				
			||||||
 | 
								m_interface->addAssertion(expr(_op) == expr(_op.leftExpression()) && expr(_op.rightExpression()));
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								m_interface->addAssertion(expr(_op) == expr(_op.leftExpression()) || expr(_op.rightExpression()));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_op.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet implement the type " + _op.annotation().commonType->toString() + " for boolean operations"
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::checkCondition(
 | 
				
			||||||
 | 
						smt::Expression _condition,
 | 
				
			||||||
 | 
						SourceLocation const& _location,
 | 
				
			||||||
 | 
						string const& _description,
 | 
				
			||||||
 | 
						string const& _additionalValueName,
 | 
				
			||||||
 | 
						smt::Expression* _additionalValue
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_interface->push();
 | 
				
			||||||
 | 
						m_interface->addAssertion(_condition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vector<smt::Expression> expressionsToEvaluate;
 | 
				
			||||||
 | 
						vector<string> expressionNames;
 | 
				
			||||||
 | 
						if (m_currentFunction)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (_additionalValue)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expressionsToEvaluate.emplace_back(*_additionalValue);
 | 
				
			||||||
 | 
								expressionNames.push_back(_additionalValueName);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for (auto const& param: m_currentFunction->parameters())
 | 
				
			||||||
 | 
								if (knownVariable(*param))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									expressionsToEvaluate.emplace_back(currentValue(*param));
 | 
				
			||||||
 | 
									expressionNames.push_back(param->name());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							for (auto const& var: m_currentFunction->localVariables())
 | 
				
			||||||
 | 
								if (knownVariable(*var))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									expressionsToEvaluate.emplace_back(currentValue(*var));
 | 
				
			||||||
 | 
									expressionNames.push_back(var->name());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						smt::CheckResult result;
 | 
				
			||||||
 | 
						vector<string> values;
 | 
				
			||||||
 | 
						try
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							tie(result, values) = m_interface->check(expressionsToEvaluate);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						catch (smt::SolverError const& _e)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							string description("Error querying SMT solver");
 | 
				
			||||||
 | 
							if (_e.comment())
 | 
				
			||||||
 | 
								description += ": " + *_e.comment();
 | 
				
			||||||
 | 
							m_errorReporter.warning(_location, description);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (result)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						case smt::CheckResult::SATISFIABLE:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							std::ostringstream message;
 | 
				
			||||||
 | 
							message << _description << " happens here";
 | 
				
			||||||
 | 
							if (m_currentFunction)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								message << " for:\n";
 | 
				
			||||||
 | 
								solAssert(values.size() == expressionNames.size(), "");
 | 
				
			||||||
 | 
								for (size_t i = 0; i < values.size(); ++i)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									string formattedValue = values.at(i);
 | 
				
			||||||
 | 
									try
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// Parse and re-format nicely
 | 
				
			||||||
 | 
										formattedValue = formatNumber(bigint(formattedValue));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									catch (...) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									message << "  " << expressionNames.at(i) << " = " << formattedValue << "\n";
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								message << ".";
 | 
				
			||||||
 | 
							m_errorReporter.warning(_location, message.str());
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						case smt::CheckResult::UNSATISFIABLE:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case smt::CheckResult::UNKNOWN:
 | 
				
			||||||
 | 
							m_errorReporter.warning(_location, _description + " might happen here.");
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case smt::CheckResult::ERROR:
 | 
				
			||||||
 | 
							m_errorReporter.warning(_location, "Error trying to invoke SMT solver.");
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							solAssert(false, "");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						m_interface->pop();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::createVariable(VariableDeclaration const& _varDecl, bool _setToZero)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (dynamic_cast<IntegerType const*>(_varDecl.type().get()))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							solAssert(m_currentSequenceCounter.count(&_varDecl) == 0, "");
 | 
				
			||||||
 | 
							solAssert(m_nextFreeSequenceCounter.count(&_varDecl) == 0, "");
 | 
				
			||||||
 | 
							solAssert(m_Variables.count(&_varDecl) == 0, "");
 | 
				
			||||||
 | 
							m_currentSequenceCounter[&_varDecl] = 0;
 | 
				
			||||||
 | 
							m_nextFreeSequenceCounter[&_varDecl] = 1;
 | 
				
			||||||
 | 
							m_Variables.emplace(&_varDecl, m_interface->newFunction(uniqueSymbol(_varDecl), smt::Sort::Int, smt::Sort::Int));
 | 
				
			||||||
 | 
							setValue(_varDecl, _setToZero);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							m_errorReporter.warning(
 | 
				
			||||||
 | 
								_varDecl.location(),
 | 
				
			||||||
 | 
								"Assertion checker does not yet support the type of this variable."
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string SMTChecker::uniqueSymbol(Declaration const& _decl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return _decl.name() + "_" + to_string(_decl.id());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string SMTChecker::uniqueSymbol(Expression const& _expr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return "expr_" + to_string(_expr.id());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool SMTChecker::knownVariable(Declaration const& _decl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return m_currentSequenceCounter.count(&_decl);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					smt::Expression SMTChecker::currentValue(Declaration const& _decl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						solAssert(m_currentSequenceCounter.count(&_decl), "");
 | 
				
			||||||
 | 
						return valueAtSequence(_decl, m_currentSequenceCounter.at(&_decl));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					smt::Expression SMTChecker::valueAtSequence(const Declaration& _decl, int _sequence)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return var(_decl)(_sequence);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					smt::Expression SMTChecker::newValue(Declaration const& _decl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						solAssert(m_currentSequenceCounter.count(&_decl), "");
 | 
				
			||||||
 | 
						solAssert(m_nextFreeSequenceCounter.count(&_decl), "");
 | 
				
			||||||
 | 
						m_currentSequenceCounter[&_decl] = m_nextFreeSequenceCounter[&_decl]++;
 | 
				
			||||||
 | 
						return currentValue(_decl);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTChecker::setValue(Declaration const& _decl, bool _setToZero)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						auto const& intType = dynamic_cast<IntegerType const&>(*_decl.type());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (_setToZero)
 | 
				
			||||||
 | 
							m_interface->addAssertion(currentValue(_decl) == 0);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_interface->addAssertion(currentValue(_decl) >= minValue(intType));
 | 
				
			||||||
 | 
							m_interface->addAssertion(currentValue(_decl) <= maxValue(intType));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					smt::Expression SMTChecker::minValue(IntegerType const& _t)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return smt::Expression(_t.minValue());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					smt::Expression SMTChecker::maxValue(IntegerType const& _t)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return smt::Expression(_t.maxValue());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					smt::Expression SMTChecker::expr(Expression const& _e)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!m_Expressions.count(&_e))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							solAssert(_e.annotation().type, "");
 | 
				
			||||||
 | 
							switch (_e.annotation().type->category())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							case Type::Category::RationalNumber:
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (RationalNumberType const* rational = dynamic_cast<RationalNumberType const*>(_e.annotation().type.get()))
 | 
				
			||||||
 | 
									solAssert(!rational->isFractional(), "");
 | 
				
			||||||
 | 
								m_Expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							case Type::Category::Integer:
 | 
				
			||||||
 | 
								m_Expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case Type::Category::Bool:
 | 
				
			||||||
 | 
								m_Expressions.emplace(&_e, m_interface->newBool(uniqueSymbol(_e)));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								solAssert(false, "Type not implemented.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return m_Expressions.at(&_e);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					smt::Expression SMTChecker::var(Declaration const& _decl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						solAssert(m_Variables.count(&_decl), "");
 | 
				
			||||||
 | 
						return m_Variables.at(&_decl);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										114
									
								
								libsolidity/formal/SMTChecker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								libsolidity/formal/SMTChecker.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,114 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
						This file is part of solidity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
						it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
						the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
						(at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
						but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
						MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
						GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
						along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/ast/ASTVisitor.h>
 | 
				
			||||||
 | 
					#include <libsolidity/formal/SolverInterface.h>
 | 
				
			||||||
 | 
					#include <libsolidity/interface/ReadFile.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace dev
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					namespace solidity
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ErrorReporter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SMTChecker: private ASTConstVisitor
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						SMTChecker(ErrorReporter& _errorReporter, ReadCallback::Callback const& _readCallback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void analyze(SourceUnit const& _sources);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						// TODO: Check that we do not have concurrent reads and writes to a variable,
 | 
				
			||||||
 | 
						// because the order of expression evaluation is undefined
 | 
				
			||||||
 | 
						// TODO: or just force a certain order, but people might have a different idea about that.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual void endVisit(VariableDeclaration const& _node) override;
 | 
				
			||||||
 | 
						virtual bool visit(FunctionDefinition const& _node) override;
 | 
				
			||||||
 | 
						virtual void endVisit(FunctionDefinition const& _node) override;
 | 
				
			||||||
 | 
						virtual bool visit(IfStatement const& _node) override;
 | 
				
			||||||
 | 
						virtual bool visit(WhileStatement const& _node) override;
 | 
				
			||||||
 | 
						virtual void endVisit(VariableDeclarationStatement const& _node) override;
 | 
				
			||||||
 | 
						virtual void endVisit(ExpressionStatement const& _node) override;
 | 
				
			||||||
 | 
						virtual void endVisit(Assignment const& _node) override;
 | 
				
			||||||
 | 
						virtual void endVisit(TupleExpression const& _node) override;
 | 
				
			||||||
 | 
						virtual void endVisit(BinaryOperation const& _node) override;
 | 
				
			||||||
 | 
						virtual void endVisit(FunctionCall const& _node) override;
 | 
				
			||||||
 | 
						virtual void endVisit(Identifier const& _node) override;
 | 
				
			||||||
 | 
						virtual void endVisit(Literal const& _node) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void arithmeticOperation(BinaryOperation const& _op);
 | 
				
			||||||
 | 
						void compareOperation(BinaryOperation const& _op);
 | 
				
			||||||
 | 
						void booleanOperation(BinaryOperation const& _op);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void checkCondition(
 | 
				
			||||||
 | 
							smt::Expression _condition,
 | 
				
			||||||
 | 
							SourceLocation const& _location,
 | 
				
			||||||
 | 
							std::string const& _description,
 | 
				
			||||||
 | 
							std::string const& _additionalValueName = "",
 | 
				
			||||||
 | 
							smt::Expression* _additionalValue = nullptr
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void createVariable(VariableDeclaration const& _varDecl, bool _setToZero);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static std::string uniqueSymbol(Declaration const& _decl);
 | 
				
			||||||
 | 
						static std::string uniqueSymbol(Expression const& _expr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// @returns true if _delc is a variable that is known at the current point, i.e.
 | 
				
			||||||
 | 
						/// has a valid sequence number
 | 
				
			||||||
 | 
						bool knownVariable(Declaration const& _decl);
 | 
				
			||||||
 | 
						/// @returns an expression denoting the value of the variable declared in @a _decl
 | 
				
			||||||
 | 
						/// at the current point.
 | 
				
			||||||
 | 
						smt::Expression currentValue(Declaration const& _decl);
 | 
				
			||||||
 | 
						/// @returns an expression denoting the value of the variable declared in @a _decl
 | 
				
			||||||
 | 
						/// at the given sequence point. Does not ensure that this sequence point exists.
 | 
				
			||||||
 | 
						smt::Expression valueAtSequence(Declaration const& _decl, int _sequence);
 | 
				
			||||||
 | 
						/// Allocates a new sequence number for the declaration, updates the current
 | 
				
			||||||
 | 
						/// sequence number to this value and returns the expression.
 | 
				
			||||||
 | 
						smt::Expression newValue(Declaration const& _decl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Sets the value of the declaration either to zero or to its intrinsic range.
 | 
				
			||||||
 | 
						void setValue(Declaration const& _decl, bool _setToZero);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static smt::Expression minValue(IntegerType const& _t);
 | 
				
			||||||
 | 
						static smt::Expression maxValue(IntegerType const& _t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Returns the expression corresponding to the AST node. Creates a new expression
 | 
				
			||||||
 | 
						/// if it does not exist yet.
 | 
				
			||||||
 | 
						smt::Expression expr(Expression const& _e);
 | 
				
			||||||
 | 
						/// Returns the function declaration corresponding to the given variable.
 | 
				
			||||||
 | 
						/// The function takes one argument which is the "sequence number".
 | 
				
			||||||
 | 
						smt::Expression var(Declaration const& _decl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::shared_ptr<smt::SolverInterface> m_interface;
 | 
				
			||||||
 | 
						std::map<Declaration const*, int> m_currentSequenceCounter;
 | 
				
			||||||
 | 
						std::map<Declaration const*, int> m_nextFreeSequenceCounter;
 | 
				
			||||||
 | 
						std::map<Expression const*, smt::Expression> m_Expressions;
 | 
				
			||||||
 | 
						std::map<Declaration const*, smt::Expression> m_Variables;
 | 
				
			||||||
 | 
						ErrorReporter& m_errorReporter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FunctionDefinition const* m_currentFunction = nullptr;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										187
									
								
								libsolidity/formal/SMTLib2Interface.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								libsolidity/formal/SMTLib2Interface.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,187 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
						This file is part of solidity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
						it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
						the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
						(at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
						but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
						MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
						GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
						along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/formal/SMTLib2Interface.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/interface/Exceptions.h>
 | 
				
			||||||
 | 
					#include <libsolidity/interface/ReadFile.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/algorithm/string/predicate.hpp>
 | 
				
			||||||
 | 
					#include <boost/algorithm/string/join.hpp>
 | 
				
			||||||
 | 
					#include <boost/filesystem/operations.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdio>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <stdexcept>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <array>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace std;
 | 
				
			||||||
 | 
					using namespace dev;
 | 
				
			||||||
 | 
					using namespace dev::solidity;
 | 
				
			||||||
 | 
					using namespace dev::solidity::smt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SMTLib2Interface::SMTLib2Interface(ReadCallback::Callback const& _queryCallback):
 | 
				
			||||||
 | 
						m_queryCallback(_queryCallback)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						reset();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTLib2Interface::reset()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_accumulatedOutput.clear();
 | 
				
			||||||
 | 
						m_accumulatedOutput.emplace_back();
 | 
				
			||||||
 | 
						write("(set-option :produce-models true)");
 | 
				
			||||||
 | 
						write("(set-logic QF_UFLIA)");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTLib2Interface::push()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_accumulatedOutput.emplace_back();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTLib2Interface::pop()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						solAssert(!m_accumulatedOutput.empty(), "");
 | 
				
			||||||
 | 
						m_accumulatedOutput.pop_back();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expression SMTLib2Interface::newFunction(string _name, Sort _domain, Sort _codomain)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						write(
 | 
				
			||||||
 | 
							"(declare-fun |" +
 | 
				
			||||||
 | 
							_name +
 | 
				
			||||||
 | 
							"| (" +
 | 
				
			||||||
 | 
							(_domain == Sort::Int ? "Int" : "Bool") +
 | 
				
			||||||
 | 
							") " +
 | 
				
			||||||
 | 
							(_codomain == Sort::Int ? "Int" : "Bool") +
 | 
				
			||||||
 | 
							")"
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
						return SolverInterface::newFunction(move(_name), _domain, _codomain);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expression SMTLib2Interface::newInteger(string _name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						write("(declare-const |" + _name + "| Int)");
 | 
				
			||||||
 | 
						return SolverInterface::newInteger(move(_name));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expression SMTLib2Interface::newBool(string _name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						write("(declare-const |" + _name + "| Bool)");
 | 
				
			||||||
 | 
						return SolverInterface::newBool(std::move(_name));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTLib2Interface::addAssertion(Expression const& _expr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						write("(assert " + toSExpr(_expr) + ")");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pair<CheckResult, vector<string>> SMTLib2Interface::check(vector<Expression> const& _expressionsToEvaluate)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						string response = querySolver(
 | 
				
			||||||
 | 
							boost::algorithm::join(m_accumulatedOutput, "\n") +
 | 
				
			||||||
 | 
							checkSatAndGetValuesCommand(_expressionsToEvaluate)
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CheckResult result;
 | 
				
			||||||
 | 
						// TODO proper parsing
 | 
				
			||||||
 | 
						if (boost::starts_with(response, "sat\n"))
 | 
				
			||||||
 | 
							result = CheckResult::SATISFIABLE;
 | 
				
			||||||
 | 
						else if (boost::starts_with(response, "unsat\n"))
 | 
				
			||||||
 | 
							result = CheckResult::UNSATISFIABLE;
 | 
				
			||||||
 | 
						else if (boost::starts_with(response, "unknown\n"))
 | 
				
			||||||
 | 
							result = CheckResult::UNKNOWN;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							result = CheckResult::ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vector<string> values;
 | 
				
			||||||
 | 
						if (result != CheckResult::UNSATISFIABLE && result != CheckResult::ERROR)
 | 
				
			||||||
 | 
							values = parseValues(find(response.cbegin(), response.cend(), '\n'), response.cend());
 | 
				
			||||||
 | 
						return make_pair(result, values);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string SMTLib2Interface::toSExpr(Expression const& _expr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (_expr.arguments.empty())
 | 
				
			||||||
 | 
							return _expr.name;
 | 
				
			||||||
 | 
						std::string sexpr = "(" + _expr.name;
 | 
				
			||||||
 | 
						for (auto const& arg: _expr.arguments)
 | 
				
			||||||
 | 
							sexpr += " " + toSExpr(arg);
 | 
				
			||||||
 | 
						sexpr += ")";
 | 
				
			||||||
 | 
						return sexpr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SMTLib2Interface::write(string _data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						solAssert(!m_accumulatedOutput.empty(), "");
 | 
				
			||||||
 | 
						m_accumulatedOutput.back() += move(_data) + "\n";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string SMTLib2Interface::checkSatAndGetValuesCommand(vector<Expression> const& _expressionsToEvaluate)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						string command;
 | 
				
			||||||
 | 
						if (_expressionsToEvaluate.empty())
 | 
				
			||||||
 | 
							command = "(check-sat)\n";
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// TODO make sure these are unique
 | 
				
			||||||
 | 
							for (size_t i = 0; i < _expressionsToEvaluate.size(); i++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								auto const& e = _expressionsToEvaluate.at(i);
 | 
				
			||||||
 | 
								// TODO they don't have to be ints...
 | 
				
			||||||
 | 
								command += "(declare-const |EVALEXPR_" + to_string(i) + "| Int)\n";
 | 
				
			||||||
 | 
								command += "(assert (= |EVALEXPR_" + to_string(i) + "| " + toSExpr(e) + "))\n";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							command += "(check-sat)\n";
 | 
				
			||||||
 | 
							command += "(get-value (";
 | 
				
			||||||
 | 
							for (size_t i = 0; i < _expressionsToEvaluate.size(); i++)
 | 
				
			||||||
 | 
								command += "|EVALEXPR_" + to_string(i) + "| ";
 | 
				
			||||||
 | 
							command += "))\n";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return command;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vector<string> SMTLib2Interface::parseValues(string::const_iterator _start, string::const_iterator _end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						vector<string> values;
 | 
				
			||||||
 | 
						while (_start < _end)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto valStart = find(_start, _end, ' ');
 | 
				
			||||||
 | 
							if (valStart < _end)
 | 
				
			||||||
 | 
								++valStart;
 | 
				
			||||||
 | 
							auto valEnd = find(valStart, _end, ')');
 | 
				
			||||||
 | 
							values.emplace_back(valStart, valEnd);
 | 
				
			||||||
 | 
							_start = find(valEnd, _end, '(');
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return values;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string SMTLib2Interface::querySolver(string const& _input)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!m_queryCallback)
 | 
				
			||||||
 | 
							BOOST_THROW_EXCEPTION(SolverError() << errinfo_comment("No SMT solver available."));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ReadCallback::Result queryResult = m_queryCallback(_input);
 | 
				
			||||||
 | 
						if (!queryResult.success)
 | 
				
			||||||
 | 
							BOOST_THROW_EXCEPTION(SolverError() << errinfo_comment(queryResult.responseOrErrorMessage));
 | 
				
			||||||
 | 
						return queryResult.responseOrErrorMessage;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										75
									
								
								libsolidity/formal/SMTLib2Interface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								libsolidity/formal/SMTLib2Interface.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,75 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
						This file is part of solidity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
						it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
						the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
						(at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
						but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
						MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
						GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
						along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/formal/SolverInterface.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/interface/Exceptions.h>
 | 
				
			||||||
 | 
					#include <libsolidity/interface/ReadFile.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libdevcore/Common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/noncopyable.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <cstdio>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace dev
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					namespace solidity
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					namespace smt
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SMTLib2Interface: public SolverInterface, public boost::noncopyable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						SMTLib2Interface(ReadCallback::Callback const& _queryCallback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void reset() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void push() override;
 | 
				
			||||||
 | 
						void pop() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Expression newFunction(std::string _name, Sort _domain, Sort _codomain) override;
 | 
				
			||||||
 | 
						Expression newInteger(std::string _name) override;
 | 
				
			||||||
 | 
						Expression newBool(std::string _name) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void addAssertion(Expression const& _expr) override;
 | 
				
			||||||
 | 
						std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						std::string toSExpr(Expression const& _expr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void write(std::string _data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string checkSatAndGetValuesCommand(std::vector<Expression> const& _expressionsToEvaluate);
 | 
				
			||||||
 | 
						std::vector<std::string> parseValues(std::string::const_iterator _start, std::string::const_iterator _end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Communicates with the solver via the callback. Throws SMTSolverError on error.
 | 
				
			||||||
 | 
						std::string querySolver(std::string const& _input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ReadCallback::Callback m_queryCallback;
 | 
				
			||||||
 | 
						std::vector<std::string> m_accumulatedOutput;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										178
									
								
								libsolidity/formal/SolverInterface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								libsolidity/formal/SolverInterface.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,178 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
						This file is part of solidity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
						it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
						the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
						(at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
						but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
						MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
						GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
						along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/interface/Exceptions.h>
 | 
				
			||||||
 | 
					#include <libsolidity/interface/ReadFile.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libdevcore/Common.h>
 | 
				
			||||||
 | 
					#include <libdevcore/Exceptions.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/noncopyable.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <cstdio>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace dev
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					namespace solidity
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					namespace smt
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class CheckResult
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						SATISFIABLE, UNSATISFIABLE, UNKNOWN, ERROR
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class Sort
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Int, Bool
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// C++ representation of an SMTLIB2 expression.
 | 
				
			||||||
 | 
					class Expression
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						friend class SolverInterface;
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						Expression(size_t _number): name(std::to_string(_number)) {}
 | 
				
			||||||
 | 
						Expression(u256 const& _number): name(_number.str()) {}
 | 
				
			||||||
 | 
						Expression(bigint const& _number): name(_number.str()) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Expression(Expression const& _other) = default;
 | 
				
			||||||
 | 
						Expression(Expression&& _other) = default;
 | 
				
			||||||
 | 
						Expression& operator=(Expression const& _other) = default;
 | 
				
			||||||
 | 
						Expression& operator=(Expression&& _other) = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Expression ite(Expression _condition, Expression _trueValue, Expression _falseValue)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return Expression("ite", std::vector<Expression>{
 | 
				
			||||||
 | 
								std::move(_condition), std::move(_trueValue), std::move(_falseValue)
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						friend Expression operator!(Expression _a)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return Expression("not", std::move(_a));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						friend Expression operator&&(Expression _a, Expression _b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return Expression("and", std::move(_a), std::move(_b));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						friend Expression operator||(Expression _a, Expression _b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return Expression("or", std::move(_a), std::move(_b));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						friend Expression operator==(Expression _a, Expression _b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return Expression("=", std::move(_a), std::move(_b));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						friend Expression operator!=(Expression _a, Expression _b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return !(std::move(_a) == std::move(_b));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						friend Expression operator<(Expression _a, Expression _b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return Expression("<", std::move(_a), std::move(_b));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						friend Expression operator<=(Expression _a, Expression _b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return Expression("<=", std::move(_a), std::move(_b));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						friend Expression operator>(Expression _a, Expression _b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return Expression(">", std::move(_a), std::move(_b));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						friend Expression operator>=(Expression _a, Expression _b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return Expression(">=", std::move(_a), std::move(_b));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						friend Expression operator+(Expression _a, Expression _b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return Expression("+", std::move(_a), std::move(_b));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						friend Expression operator-(Expression _a, Expression _b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return Expression("-", std::move(_a), std::move(_b));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						friend Expression operator*(Expression _a, Expression _b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return Expression("*", std::move(_a), std::move(_b));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						Expression operator()(Expression _a) const
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							solAssert(arguments.empty(), "Attempted function application to non-function.");
 | 
				
			||||||
 | 
							return Expression(name, _a);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string const name;
 | 
				
			||||||
 | 
						std::vector<Expression> const arguments;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						/// Manual constructor, should only be used by SolverInterface and this class itself.
 | 
				
			||||||
 | 
						Expression(std::string _name, std::vector<Expression> _arguments):
 | 
				
			||||||
 | 
							name(std::move(_name)), arguments(std::move(_arguments)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						explicit Expression(std::string _name):
 | 
				
			||||||
 | 
							Expression(std::move(_name), std::vector<Expression>{}) {}
 | 
				
			||||||
 | 
						Expression(std::string _name, Expression _arg):
 | 
				
			||||||
 | 
							Expression(std::move(_name), std::vector<Expression>{std::move(_arg)}) {}
 | 
				
			||||||
 | 
						Expression(std::string _name, Expression _arg1, Expression _arg2):
 | 
				
			||||||
 | 
							Expression(std::move(_name), std::vector<Expression>{std::move(_arg1), std::move(_arg2)}) {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEV_SIMPLE_EXCEPTION(SolverError);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SolverInterface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						virtual void reset() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual void push() = 0;
 | 
				
			||||||
 | 
						virtual void pop() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual Expression newFunction(std::string _name, Sort /*_domain*/, Sort /*_codomain*/)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// Subclasses should do something here
 | 
				
			||||||
 | 
							return Expression(std::move(_name), {});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						virtual Expression newInteger(std::string _name)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// Subclasses should do something here
 | 
				
			||||||
 | 
							return Expression(std::move(_name), {});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						virtual Expression newBool(std::string _name)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// Subclasses should do something here
 | 
				
			||||||
 | 
							return Expression(std::move(_name), {});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual void addAssertion(Expression const& _expr) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Checks for satisfiability, evaluates the expressions if a model
 | 
				
			||||||
 | 
						/// is available. Throws SMTSolverError on error.
 | 
				
			||||||
 | 
						virtual std::pair<CheckResult, std::vector<std::string>>
 | 
				
			||||||
 | 
						check(std::vector<Expression> const& _expressionsToEvaluate) = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										189
									
								
								libsolidity/formal/Z3Interface.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								libsolidity/formal/Z3Interface.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,189 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
						This file is part of solidity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
						it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
						the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
						(at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
						but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
						MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
						GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
						along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/formal/Z3Interface.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/interface/Exceptions.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libdevcore/CommonIO.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace std;
 | 
				
			||||||
 | 
					using namespace dev;
 | 
				
			||||||
 | 
					using namespace dev::solidity::smt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Z3Interface::Z3Interface():
 | 
				
			||||||
 | 
						m_solver(m_context)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Z3Interface::reset()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_constants.clear();
 | 
				
			||||||
 | 
						m_functions.clear();
 | 
				
			||||||
 | 
						m_solver.reset();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Z3Interface::push()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_solver.push();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Z3Interface::pop()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_solver.pop();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expression Z3Interface::newFunction(string _name, Sort _domain, Sort _codomain)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_functions.insert({_name, m_context.function(_name.c_str(), z3Sort(_domain), z3Sort(_codomain))});
 | 
				
			||||||
 | 
						return SolverInterface::newFunction(move(_name), _domain, _codomain);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expression Z3Interface::newInteger(string _name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_constants.insert({_name, m_context.int_const(_name.c_str())});
 | 
				
			||||||
 | 
						return SolverInterface::newInteger(move(_name));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expression Z3Interface::newBool(string _name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_constants.insert({_name, m_context.bool_const(_name.c_str())});
 | 
				
			||||||
 | 
						return SolverInterface::newBool(std::move(_name));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Z3Interface::addAssertion(Expression const& _expr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_solver.add(toZ3Expr(_expr));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pair<CheckResult, vector<string>> Z3Interface::check(vector<Expression> const& _expressionsToEvaluate)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					//	cout << "---------------------------------" << endl;
 | 
				
			||||||
 | 
					//	cout << m_solver << endl;
 | 
				
			||||||
 | 
						CheckResult result;
 | 
				
			||||||
 | 
						switch (m_solver.check())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						case z3::check_result::sat:
 | 
				
			||||||
 | 
							result = CheckResult::SATISFIABLE;
 | 
				
			||||||
 | 
							cout << "sat" << endl;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case z3::check_result::unsat:
 | 
				
			||||||
 | 
							result = CheckResult::UNSATISFIABLE;
 | 
				
			||||||
 | 
							cout << "unsat" << endl;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case z3::check_result::unknown:
 | 
				
			||||||
 | 
							result = CheckResult::UNKNOWN;
 | 
				
			||||||
 | 
							cout << "unknown" << endl;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							solAssert(false, "");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					//	cout << "---------------------------------" << endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vector<string> values;
 | 
				
			||||||
 | 
						if (result != CheckResult::UNSATISFIABLE)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							z3::model m = m_solver.get_model();
 | 
				
			||||||
 | 
							for (Expression const& e: _expressionsToEvaluate)
 | 
				
			||||||
 | 
								values.push_back(toString(m.eval(toZ3Expr(e))));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return make_pair(result, values);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (_expr.arguments.empty() && m_constants.count(_expr.name))
 | 
				
			||||||
 | 
							return m_constants.at(_expr.name);
 | 
				
			||||||
 | 
						z3::expr_vector arguments(m_context);
 | 
				
			||||||
 | 
						for (auto const& arg: _expr.arguments)
 | 
				
			||||||
 | 
							arguments.push_back(toZ3Expr(arg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static map<string, unsigned> arity{
 | 
				
			||||||
 | 
							{"ite", 3},
 | 
				
			||||||
 | 
							{"not", 1},
 | 
				
			||||||
 | 
							{"and", 2},
 | 
				
			||||||
 | 
							{"or", 2},
 | 
				
			||||||
 | 
							{"=", 2},
 | 
				
			||||||
 | 
							{"<", 2},
 | 
				
			||||||
 | 
							{"<=", 2},
 | 
				
			||||||
 | 
							{">", 2},
 | 
				
			||||||
 | 
							{">=", 2},
 | 
				
			||||||
 | 
							{"+", 2},
 | 
				
			||||||
 | 
							{"-", 2},
 | 
				
			||||||
 | 
							{"*", 2},
 | 
				
			||||||
 | 
							{">=", 2}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						string const& n = _expr.name;
 | 
				
			||||||
 | 
						if (m_functions.count(n))
 | 
				
			||||||
 | 
							return m_functions.at(n)(arguments);
 | 
				
			||||||
 | 
						else if (m_constants.count(n))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							solAssert(arguments.empty(), "");
 | 
				
			||||||
 | 
							return m_constants.at(n);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (arguments.empty())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// We assume it is an integer...
 | 
				
			||||||
 | 
							return m_context.int_val(n.c_str());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(arity.count(n) && arity.at(n) == arguments.size());
 | 
				
			||||||
 | 
						if (n == "ite")
 | 
				
			||||||
 | 
							return z3::ite(arguments[0], arguments[1], arguments[2]);
 | 
				
			||||||
 | 
						else if (n == "not")
 | 
				
			||||||
 | 
							return !arguments[0];
 | 
				
			||||||
 | 
						else if (n == "and")
 | 
				
			||||||
 | 
							return arguments[0] && arguments[1];
 | 
				
			||||||
 | 
						else if (n == "or")
 | 
				
			||||||
 | 
							return arguments[0] || arguments[1];
 | 
				
			||||||
 | 
						else if (n == "=")
 | 
				
			||||||
 | 
							return arguments[0] == arguments[1];
 | 
				
			||||||
 | 
						else if (n == "<")
 | 
				
			||||||
 | 
							return arguments[0] < arguments[1];
 | 
				
			||||||
 | 
						else if (n == "<=")
 | 
				
			||||||
 | 
							return arguments[0] <= arguments[1];
 | 
				
			||||||
 | 
						else if (n == ">")
 | 
				
			||||||
 | 
							return arguments[0] > arguments[1];
 | 
				
			||||||
 | 
						else if (n == ">=")
 | 
				
			||||||
 | 
							return arguments[0] >= arguments[1];
 | 
				
			||||||
 | 
						else if (n == "+")
 | 
				
			||||||
 | 
							return arguments[0] + arguments[1];
 | 
				
			||||||
 | 
						else if (n == "-")
 | 
				
			||||||
 | 
							return arguments[0] - arguments[1];
 | 
				
			||||||
 | 
						else if (n == "*")
 | 
				
			||||||
 | 
							return arguments[0] * arguments[1];
 | 
				
			||||||
 | 
						// Cannot reach here.
 | 
				
			||||||
 | 
						solAssert(false, "");
 | 
				
			||||||
 | 
						return arguments[0];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					z3::sort Z3Interface::z3Sort(Sort _sort)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (_sort)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						case Sort::Bool:
 | 
				
			||||||
 | 
							return m_context.bool_sort();
 | 
				
			||||||
 | 
						case Sort::Int:
 | 
				
			||||||
 | 
							return m_context.int_sort();
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						solAssert(false, "");
 | 
				
			||||||
 | 
						// Cannot be reached.
 | 
				
			||||||
 | 
						return m_context.int_sort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										65
									
								
								libsolidity/formal/Z3Interface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								libsolidity/formal/Z3Interface.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
						This file is part of solidity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
						it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
						the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
						(at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solidity is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
						but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
						MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
						GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
						along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libsolidity/formal/SolverInterface.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/noncopyable.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <z3++.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace dev
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					namespace solidity
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					namespace smt
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Z3Interface: public SolverInterface, public boost::noncopyable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						Z3Interface();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void reset() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void push() override;
 | 
				
			||||||
 | 
						void pop() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Expression newFunction(std::string _name, Sort _domain, Sort _codomain) override;
 | 
				
			||||||
 | 
						Expression newInteger(std::string _name) override;
 | 
				
			||||||
 | 
						Expression newBool(std::string _name) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void addAssertion(Expression const& _expr) override;
 | 
				
			||||||
 | 
						std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						z3::expr toZ3Expr(Expression const& _expr);
 | 
				
			||||||
 | 
						z3::sort z3Sort(smt::Sort _sort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string checkSatAndGetValuesCommand(std::vector<Expression> const& _expressionsToEvaluate);
 | 
				
			||||||
 | 
						std::vector<std::string> parseValues(std::string::const_iterator _start, std::string::const_iterator _end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						z3::context m_context;
 | 
				
			||||||
 | 
						z3::solver m_solver;
 | 
				
			||||||
 | 
						std::map<std::string, z3::expr> m_constants;
 | 
				
			||||||
 | 
						std::map<std::string, z3::func_decl> m_functions;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -52,7 +52,7 @@ using namespace dev::solidity::assembly;
 | 
				
			|||||||
class EthAssemblyAdapter: public julia::AbstractAssembly
 | 
					class EthAssemblyAdapter: public julia::AbstractAssembly
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	EthAssemblyAdapter(eth::Assembly& _assembly):
 | 
						explicit EthAssemblyAdapter(eth::Assembly& _assembly):
 | 
				
			||||||
		m_assembly(_assembly)
 | 
							m_assembly(_assembly)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -127,7 +127,7 @@ public:
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	LabelID assemblyTagToIdentifier(eth::AssemblyItem const& _tag) const
 | 
						static LabelID assemblyTagToIdentifier(eth::AssemblyItem const& _tag)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		u256 id = _tag.data();
 | 
							u256 id = _tag.data();
 | 
				
			||||||
		solAssert(id <= std::numeric_limits<LabelID>::max(), "Tag id too large.");
 | 
							solAssert(id <= std::numeric_limits<LabelID>::max(), "Tag id too large.");
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,9 @@
 | 
				
			|||||||
#include <libsolidity/inlineasm/AsmParser.h>
 | 
					#include <libsolidity/inlineasm/AsmParser.h>
 | 
				
			||||||
#include <libsolidity/parsing/Scanner.h>
 | 
					#include <libsolidity/parsing/Scanner.h>
 | 
				
			||||||
#include <libsolidity/interface/ErrorReporter.h>
 | 
					#include <libsolidity/interface/ErrorReporter.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/algorithm/string.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -33,6 +36,7 @@ using namespace dev::solidity::assembly;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner)
 | 
					shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						m_recursionDepth = 0;
 | 
				
			||||||
	try
 | 
						try
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_scanner = _scanner;
 | 
							m_scanner = _scanner;
 | 
				
			||||||
@ -48,6 +52,7 @@ shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scann
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
assembly::Block Parser::parseBlock()
 | 
					assembly::Block Parser::parseBlock()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						RecursionGuard recursionGuard(*this);
 | 
				
			||||||
	assembly::Block block = createWithLocation<Block>();
 | 
						assembly::Block block = createWithLocation<Block>();
 | 
				
			||||||
	expectToken(Token::LBrace);
 | 
						expectToken(Token::LBrace);
 | 
				
			||||||
	while (currentToken() != Token::RBrace)
 | 
						while (currentToken() != Token::RBrace)
 | 
				
			||||||
@ -59,6 +64,7 @@ assembly::Block Parser::parseBlock()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
assembly::Statement Parser::parseStatement()
 | 
					assembly::Statement Parser::parseStatement()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						RecursionGuard recursionGuard(*this);
 | 
				
			||||||
	switch (currentToken())
 | 
						switch (currentToken())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	case Token::Let:
 | 
						case Token::Let:
 | 
				
			||||||
@ -155,6 +161,7 @@ assembly::Statement Parser::parseStatement()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
assembly::Case Parser::parseCase()
 | 
					assembly::Case Parser::parseCase()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						RecursionGuard recursionGuard(*this);
 | 
				
			||||||
	assembly::Case _case = createWithLocation<assembly::Case>();
 | 
						assembly::Case _case = createWithLocation<assembly::Case>();
 | 
				
			||||||
	if (m_scanner->currentToken() == Token::Default)
 | 
						if (m_scanner->currentToken() == Token::Default)
 | 
				
			||||||
		m_scanner->next();
 | 
							m_scanner->next();
 | 
				
			||||||
@ -175,6 +182,7 @@ assembly::Case Parser::parseCase()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
assembly::ForLoop Parser::parseForLoop()
 | 
					assembly::ForLoop Parser::parseForLoop()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						RecursionGuard recursionGuard(*this);
 | 
				
			||||||
	ForLoop forLoop = createWithLocation<ForLoop>();
 | 
						ForLoop forLoop = createWithLocation<ForLoop>();
 | 
				
			||||||
	expectToken(Token::For);
 | 
						expectToken(Token::For);
 | 
				
			||||||
	forLoop.pre = parseBlock();
 | 
						forLoop.pre = parseBlock();
 | 
				
			||||||
@ -189,6 +197,7 @@ assembly::ForLoop Parser::parseForLoop()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
assembly::Statement Parser::parseExpression()
 | 
					assembly::Statement Parser::parseExpression()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						RecursionGuard recursionGuard(*this);
 | 
				
			||||||
	Statement operation = parseElementaryOperation(true);
 | 
						Statement operation = parseElementaryOperation(true);
 | 
				
			||||||
	if (operation.type() == typeid(Instruction))
 | 
						if (operation.type() == typeid(Instruction))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -251,6 +260,7 @@ std::map<dev::solidity::Instruction, string> const& Parser::instructionNames()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
 | 
					assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						RecursionGuard recursionGuard(*this);
 | 
				
			||||||
	Statement ret;
 | 
						Statement ret;
 | 
				
			||||||
	switch (currentToken())
 | 
						switch (currentToken())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -297,6 +307,8 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
 | 
				
			|||||||
			kind = LiteralKind::String;
 | 
								kind = LiteralKind::String;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case Token::Number:
 | 
							case Token::Number:
 | 
				
			||||||
 | 
								if (!isValidNumberLiteral(currentLiteral()))
 | 
				
			||||||
 | 
									fatalParserError("Invalid number literal.");
 | 
				
			||||||
			kind = LiteralKind::Number;
 | 
								kind = LiteralKind::Number;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case Token::TrueLiteral:
 | 
							case Token::TrueLiteral:
 | 
				
			||||||
@ -337,6 +349,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
assembly::VariableDeclaration Parser::parseVariableDeclaration()
 | 
					assembly::VariableDeclaration Parser::parseVariableDeclaration()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						RecursionGuard recursionGuard(*this);
 | 
				
			||||||
	VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
 | 
						VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
 | 
				
			||||||
	expectToken(Token::Let);
 | 
						expectToken(Token::Let);
 | 
				
			||||||
	while (true)
 | 
						while (true)
 | 
				
			||||||
@ -361,6 +374,7 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
assembly::FunctionDefinition Parser::parseFunctionDefinition()
 | 
					assembly::FunctionDefinition Parser::parseFunctionDefinition()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						RecursionGuard recursionGuard(*this);
 | 
				
			||||||
	FunctionDefinition funDef = createWithLocation<FunctionDefinition>();
 | 
						FunctionDefinition funDef = createWithLocation<FunctionDefinition>();
 | 
				
			||||||
	expectToken(Token::Function);
 | 
						expectToken(Token::Function);
 | 
				
			||||||
	funDef.name = expectAsmIdentifier();
 | 
						funDef.name = expectAsmIdentifier();
 | 
				
			||||||
@ -392,6 +406,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
 | 
					assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						RecursionGuard recursionGuard(*this);
 | 
				
			||||||
	if (_instruction.type() == typeid(Instruction))
 | 
						if (_instruction.type() == typeid(Instruction))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		solAssert(!m_julia, "Instructions are invalid in JULIA");
 | 
							solAssert(!m_julia, "Instructions are invalid in JULIA");
 | 
				
			||||||
@ -474,6 +489,7 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
TypedName Parser::parseTypedName()
 | 
					TypedName Parser::parseTypedName()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						RecursionGuard recursionGuard(*this);
 | 
				
			||||||
	TypedName typedName = createWithLocation<TypedName>();
 | 
						TypedName typedName = createWithLocation<TypedName>();
 | 
				
			||||||
	typedName.name = expectAsmIdentifier();
 | 
						typedName.name = expectAsmIdentifier();
 | 
				
			||||||
	if (m_julia)
 | 
						if (m_julia)
 | 
				
			||||||
@ -501,3 +517,19 @@ string Parser::expectAsmIdentifier()
 | 
				
			|||||||
	expectToken(Token::Identifier);
 | 
						expectToken(Token::Identifier);
 | 
				
			||||||
	return name;
 | 
						return name;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Parser::isValidNumberLiteral(string const& _literal)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						try
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							u256(_literal);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						catch (...)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (boost::starts_with(_literal, "0x"))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return _literal.find_first_not_of("0123456789") == string::npos;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -45,7 +45,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	/// Creates an inline assembly node with the given source location.
 | 
						/// Creates an inline assembly node with the given source location.
 | 
				
			||||||
	template <class T> T createWithLocation(SourceLocation const& _loc = SourceLocation())
 | 
						template <class T> T createWithLocation(SourceLocation const& _loc = SourceLocation()) const
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		T r;
 | 
							T r;
 | 
				
			||||||
		r.location = _loc;
 | 
							r.location = _loc;
 | 
				
			||||||
@ -75,6 +75,8 @@ protected:
 | 
				
			|||||||
	TypedName parseTypedName();
 | 
						TypedName parseTypedName();
 | 
				
			||||||
	std::string expectAsmIdentifier();
 | 
						std::string expectAsmIdentifier();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static bool isValidNumberLiteral(std::string const& _literal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	bool m_julia = false;
 | 
						bool m_julia = false;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -209,7 +209,7 @@ string AsmPrinter::operator()(Block const& _block)
 | 
				
			|||||||
	return "{\n    " + body + "\n}";
 | 
						return "{\n    " + body + "\n}";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
string AsmPrinter::appendTypeName(std::string const& _type)
 | 
					string AsmPrinter::appendTypeName(std::string const& _type) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (m_julia)
 | 
						if (m_julia)
 | 
				
			||||||
		return ":" + _type;
 | 
							return ":" + _type;
 | 
				
			||||||
 | 
				
			|||||||
@ -53,7 +53,7 @@ public:
 | 
				
			|||||||
	std::string operator()(assembly::Block const& _block);
 | 
						std::string operator()(assembly::Block const& _block);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	std::string appendTypeName(std::string const& _type);
 | 
						std::string appendTypeName(std::string const& _type) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool m_julia = false;
 | 
						bool m_julia = false;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -70,7 +70,7 @@ Scope::Identifier* Scope::lookup(string const& _name)
 | 
				
			|||||||
	return nullptr;
 | 
						return nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Scope::exists(string const& _name)
 | 
					bool Scope::exists(string const& _name) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (identifiers.count(_name))
 | 
						if (identifiers.count(_name))
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
				
			|||||||
@ -107,7 +107,7 @@ struct Scope
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	/// @returns true if the name exists in this scope or in super scopes (also searches
 | 
						/// @returns true if the name exists in this scope or in super scopes (also searches
 | 
				
			||||||
	/// across function and assembly boundaries).
 | 
						/// across function and assembly boundaries).
 | 
				
			||||||
	bool exists(std::string const& _name);
 | 
						bool exists(std::string const& _name) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// @returns the number of variables directly registered inside the scope.
 | 
						/// @returns the number of variables directly registered inside the scope.
 | 
				
			||||||
	size_t numberOfVariables() const;
 | 
						size_t numberOfVariables() const;
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,6 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <libsolidity/interface/ABI.h>
 | 
					#include <libsolidity/interface/ABI.h>
 | 
				
			||||||
#include <boost/range/irange.hpp>
 | 
					 | 
				
			||||||
#include <libsolidity/ast/AST.h>
 | 
					#include <libsolidity/ast/AST.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					using namespace std;
 | 
				
			||||||
@ -36,8 +35,10 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef)
 | 
				
			|||||||
		Json::Value method;
 | 
							Json::Value method;
 | 
				
			||||||
		method["type"] = "function";
 | 
							method["type"] = "function";
 | 
				
			||||||
		method["name"] = it.second->declaration().name();
 | 
							method["name"] = it.second->declaration().name();
 | 
				
			||||||
		method["constant"] = it.second->isConstant();
 | 
							// TODO: deprecate constant in a future release
 | 
				
			||||||
 | 
							method["constant"] = it.second->stateMutability() == StateMutability::Pure || it.second->stateMutability() == StateMutability::View;
 | 
				
			||||||
		method["payable"] = it.second->isPayable();
 | 
							method["payable"] = it.second->isPayable();
 | 
				
			||||||
 | 
							method["stateMutability"] = stateMutabilityToString(it.second->stateMutability());
 | 
				
			||||||
		method["inputs"] = formatTypeList(
 | 
							method["inputs"] = formatTypeList(
 | 
				
			||||||
			externalFunctionType->parameterNames(),
 | 
								externalFunctionType->parameterNames(),
 | 
				
			||||||
			externalFunctionType->parameterTypes(),
 | 
								externalFunctionType->parameterTypes(),
 | 
				
			||||||
@ -57,6 +58,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef)
 | 
				
			|||||||
		auto externalFunction = FunctionType(*_contractDef.constructor(), false).interfaceFunctionType();
 | 
							auto externalFunction = FunctionType(*_contractDef.constructor(), false).interfaceFunctionType();
 | 
				
			||||||
		solAssert(!!externalFunction, "");
 | 
							solAssert(!!externalFunction, "");
 | 
				
			||||||
		method["payable"] = externalFunction->isPayable();
 | 
							method["payable"] = externalFunction->isPayable();
 | 
				
			||||||
 | 
							method["stateMutability"] = stateMutabilityToString(externalFunction->stateMutability());
 | 
				
			||||||
		method["inputs"] = formatTypeList(
 | 
							method["inputs"] = formatTypeList(
 | 
				
			||||||
			externalFunction->parameterNames(),
 | 
								externalFunction->parameterNames(),
 | 
				
			||||||
			externalFunction->parameterTypes(),
 | 
								externalFunction->parameterTypes(),
 | 
				
			||||||
@ -71,6 +73,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef)
 | 
				
			|||||||
		Json::Value method;
 | 
							Json::Value method;
 | 
				
			||||||
		method["type"] = "fallback";
 | 
							method["type"] = "fallback";
 | 
				
			||||||
		method["payable"] = externalFunctionType->isPayable();
 | 
							method["payable"] = externalFunctionType->isPayable();
 | 
				
			||||||
 | 
							method["stateMutability"] = stateMutabilityToString(externalFunctionType->stateMutability());
 | 
				
			||||||
		abi.append(method);
 | 
							abi.append(method);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (auto const& it: _contractDef.interfaceEvents())
 | 
						for (auto const& it: _contractDef.interfaceEvents())
 | 
				
			||||||
 | 
				
			|||||||
@ -37,6 +37,7 @@
 | 
				
			|||||||
#include <libsolidity/analysis/PostTypeChecker.h>
 | 
					#include <libsolidity/analysis/PostTypeChecker.h>
 | 
				
			||||||
#include <libsolidity/analysis/SyntaxChecker.h>
 | 
					#include <libsolidity/analysis/SyntaxChecker.h>
 | 
				
			||||||
#include <libsolidity/codegen/Compiler.h>
 | 
					#include <libsolidity/codegen/Compiler.h>
 | 
				
			||||||
 | 
					#include <libsolidity/formal/SMTChecker.h>
 | 
				
			||||||
#include <libsolidity/interface/ABI.h>
 | 
					#include <libsolidity/interface/ABI.h>
 | 
				
			||||||
#include <libsolidity/interface/Natspec.h>
 | 
					#include <libsolidity/interface/Natspec.h>
 | 
				
			||||||
#include <libsolidity/interface/GasEstimator.h>
 | 
					#include <libsolidity/interface/GasEstimator.h>
 | 
				
			||||||
@ -49,8 +50,6 @@
 | 
				
			|||||||
#include <json/json.h>
 | 
					#include <json/json.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <boost/algorithm/string.hpp>
 | 
					#include <boost/algorithm/string.hpp>
 | 
				
			||||||
#include <boost/filesystem.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					using namespace std;
 | 
				
			||||||
using namespace dev;
 | 
					using namespace dev;
 | 
				
			||||||
@ -238,6 +237,13 @@ bool CompilerStack::analyze()
 | 
				
			|||||||
				noErrors = false;
 | 
									noErrors = false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (noErrors)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							SMTChecker smtChecker(m_errorReporter, m_smtQuery);
 | 
				
			||||||
 | 
							for (Source const* source: m_sourceOrder)
 | 
				
			||||||
 | 
								smtChecker.analyze(*source->ast);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (noErrors)
 | 
						if (noErrors)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_stackState = AnalysisSuccessful;
 | 
							m_stackState = AnalysisSuccessful;
 | 
				
			||||||
@ -406,39 +412,42 @@ Json::Value const& CompilerStack::contractABI(Contract const& _contract) const
 | 
				
			|||||||
	return *_contract.abi;
 | 
						return *_contract.abi;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Json::Value const& CompilerStack::natspec(string const& _contractName, DocumentationType _type) const
 | 
					Json::Value const& CompilerStack::natspecUser(string const& _contractName) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return natspec(contract(_contractName), _type);
 | 
						return natspecUser(contract(_contractName));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Json::Value const& CompilerStack::natspec(Contract const& _contract, DocumentationType _type) const
 | 
					Json::Value const& CompilerStack::natspecUser(Contract const& _contract) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (m_stackState < AnalysisSuccessful)
 | 
						if (m_stackState < AnalysisSuccessful)
 | 
				
			||||||
		BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
 | 
							BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	solAssert(_contract.contract, "");
 | 
						solAssert(_contract.contract, "");
 | 
				
			||||||
	std::unique_ptr<Json::Value const>* doc;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// checks wheather we already have the documentation
 | 
						// caches the result
 | 
				
			||||||
	switch (_type)
 | 
						if (!_contract.userDocumentation)
 | 
				
			||||||
	{
 | 
							_contract.userDocumentation.reset(new Json::Value(Natspec::userDocumentation(*_contract.contract)));
 | 
				
			||||||
	case DocumentationType::NatspecUser:
 | 
					 | 
				
			||||||
		doc = &_contract.userDocumentation;
 | 
					 | 
				
			||||||
		// caches the result
 | 
					 | 
				
			||||||
		if (!*doc)
 | 
					 | 
				
			||||||
			doc->reset(new Json::Value(Natspec::userDocumentation(*_contract.contract)));
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case DocumentationType::NatspecDev:
 | 
					 | 
				
			||||||
		doc = &_contract.devDocumentation;
 | 
					 | 
				
			||||||
		// caches the result
 | 
					 | 
				
			||||||
		if (!*doc)
 | 
					 | 
				
			||||||
			doc->reset(new Json::Value(Natspec::devDocumentation(*_contract.contract)));
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		solAssert(false, "Illegal documentation type.");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return *(*doc);
 | 
						return *_contract.userDocumentation;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Json::Value const& CompilerStack::natspecDev(string const& _contractName) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return natspecDev(contract(_contractName));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Json::Value const& CompilerStack::natspecDev(Contract const& _contract) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (m_stackState < AnalysisSuccessful)
 | 
				
			||||||
 | 
							BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						solAssert(_contract.contract, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// caches the result
 | 
				
			||||||
 | 
						if (!_contract.devDocumentation)
 | 
				
			||||||
 | 
							_contract.devDocumentation.reset(new Json::Value(Natspec::devDocumentation(*_contract.contract)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return *_contract.devDocumentation;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const
 | 
					Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const
 | 
				
			||||||
@ -526,17 +535,17 @@ StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string
 | 
				
			|||||||
			if (m_sources.count(importPath) || newSources.count(importPath))
 | 
								if (m_sources.count(importPath) || newSources.count(importPath))
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			ReadFile::Result result{false, string("File not supplied initially.")};
 | 
								ReadCallback::Result result{false, string("File not supplied initially.")};
 | 
				
			||||||
			if (m_readFile)
 | 
								if (m_readFile)
 | 
				
			||||||
				result = m_readFile(importPath);
 | 
									result = m_readFile(importPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (result.success)
 | 
								if (result.success)
 | 
				
			||||||
				newSources[importPath] = result.contentsOrErrorMessage;
 | 
									newSources[importPath] = result.responseOrErrorMessage;
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				m_errorReporter.parserError(
 | 
									m_errorReporter.parserError(
 | 
				
			||||||
					import->location(),
 | 
										import->location(),
 | 
				
			||||||
					string("Source \"" + importPath + "\" not found: " + result.contentsOrErrorMessage)
 | 
										string("Source \"" + importPath + "\" not found: " + result.responseOrErrorMessage)
 | 
				
			||||||
				);
 | 
									);
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -632,6 +641,17 @@ string CompilerStack::absolutePath(string const& _path, string const& _reference
 | 
				
			|||||||
	return result.generic_string();
 | 
						return result.generic_string();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					bool onlySafeExperimentalFeaturesActivated(set<ExperimentalFeature> const& features)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						for (auto const feature: features)
 | 
				
			||||||
 | 
							if (!ExperimentalFeatureOnlyAnalysis.count(feature))
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CompilerStack::compileContract(
 | 
					void CompilerStack::compileContract(
 | 
				
			||||||
	ContractDefinition const& _contract,
 | 
						ContractDefinition const& _contract,
 | 
				
			||||||
	map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts
 | 
						map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts
 | 
				
			||||||
@ -649,10 +669,23 @@ void CompilerStack::compileContract(
 | 
				
			|||||||
	shared_ptr<Compiler> compiler = make_shared<Compiler>(m_optimize, m_optimizeRuns);
 | 
						shared_ptr<Compiler> compiler = make_shared<Compiler>(m_optimize, m_optimizeRuns);
 | 
				
			||||||
	Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
 | 
						Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
 | 
				
			||||||
	string metadata = createMetadata(compiledContract);
 | 
						string metadata = createMetadata(compiledContract);
 | 
				
			||||||
	bytes cborEncodedMetadata =
 | 
						bytes cborEncodedHash =
 | 
				
			||||||
		// CBOR-encoding of {"bzzr0": dev::swarmHash(metadata)}
 | 
							// CBOR-encoding of the key "bzzr0"
 | 
				
			||||||
		bytes{0xa1, 0x65, 'b', 'z', 'z', 'r', '0', 0x58, 0x20} +
 | 
							bytes{0x65, 'b', 'z', 'z', 'r', '0'}+
 | 
				
			||||||
		dev::swarmHash(metadata).asBytes();
 | 
							// CBOR-encoding of the hash
 | 
				
			||||||
 | 
							bytes{0x58, 0x20} + dev::swarmHash(metadata).asBytes();
 | 
				
			||||||
 | 
						bytes cborEncodedMetadata;
 | 
				
			||||||
 | 
						if (onlySafeExperimentalFeaturesActivated(_contract.sourceUnit().annotation().experimentalFeatures))
 | 
				
			||||||
 | 
							cborEncodedMetadata =
 | 
				
			||||||
 | 
								// CBOR-encoding of {"bzzr0": dev::swarmHash(metadata)}
 | 
				
			||||||
 | 
								bytes{0xa1} +
 | 
				
			||||||
 | 
								cborEncodedHash;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							cborEncodedMetadata =
 | 
				
			||||||
 | 
								// CBOR-encoding of {"bzzr0": dev::swarmHash(metadata), "experimental": true}
 | 
				
			||||||
 | 
								bytes{0xa2} +
 | 
				
			||||||
 | 
								cborEncodedHash +
 | 
				
			||||||
 | 
								bytes{0x6c, 'e', 'x', 'p', 'e', 'r', 'i', 'm', 'e', 'n', 't', 'a', 'l', 0xf5};
 | 
				
			||||||
	solAssert(cborEncodedMetadata.size() <= 0xffff, "Metadata too large");
 | 
						solAssert(cborEncodedMetadata.size() <= 0xffff, "Metadata too large");
 | 
				
			||||||
	// 16-bit big endian length
 | 
						// 16-bit big endian length
 | 
				
			||||||
	cborEncodedMetadata += toCompactBigEndian(cborEncodedMetadata.size(), 2);
 | 
						cborEncodedMetadata += toCompactBigEndian(cborEncodedMetadata.size(), 2);
 | 
				
			||||||
@ -795,8 +828,8 @@ string CompilerStack::createMetadata(Contract const& _contract) const
 | 
				
			|||||||
		meta["settings"]["libraries"][library.first] = "0x" + toHex(library.second.asBytes());
 | 
							meta["settings"]["libraries"][library.first] = "0x" + toHex(library.second.asBytes());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	meta["output"]["abi"] = contractABI(_contract);
 | 
						meta["output"]["abi"] = contractABI(_contract);
 | 
				
			||||||
	meta["output"]["userdoc"] = natspec(_contract, DocumentationType::NatspecUser);
 | 
						meta["output"]["userdoc"] = natspecUser(_contract);
 | 
				
			||||||
	meta["output"]["devdoc"] = natspec(_contract, DocumentationType::NatspecDev);
 | 
						meta["output"]["devdoc"] = natspecDev(_contract);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return jsonCompactPrint(meta);
 | 
						return jsonCompactPrint(meta);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -63,12 +63,6 @@ class Natspec;
 | 
				
			|||||||
class Error;
 | 
					class Error;
 | 
				
			||||||
class DeclarationContainer;
 | 
					class DeclarationContainer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class DocumentationType: uint8_t
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	NatspecUser = 1,
 | 
					 | 
				
			||||||
	NatspecDev
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Easy to use and self-contained Solidity compiler with as few header dependencies as possible.
 | 
					 * Easy to use and self-contained Solidity compiler with as few header dependencies as possible.
 | 
				
			||||||
 * It holds state and can be used to either step through the compilation stages (and abort e.g.
 | 
					 * It holds state and can be used to either step through the compilation stages (and abort e.g.
 | 
				
			||||||
@ -88,13 +82,13 @@ public:
 | 
				
			|||||||
	/// Creates a new compiler stack.
 | 
						/// Creates a new compiler stack.
 | 
				
			||||||
	/// @param _readFile callback to used to read files for import statements. Must return
 | 
						/// @param _readFile callback to used to read files for import statements. Must return
 | 
				
			||||||
	/// and must not emit exceptions.
 | 
						/// and must not emit exceptions.
 | 
				
			||||||
	explicit CompilerStack(ReadFile::Callback const& _readFile = ReadFile::Callback()):
 | 
						explicit CompilerStack(ReadCallback::Callback const& _readFile = ReadCallback::Callback()):
 | 
				
			||||||
		m_readFile(_readFile),
 | 
							m_readFile(_readFile),
 | 
				
			||||||
		m_errorList(),
 | 
							m_errorList(),
 | 
				
			||||||
		m_errorReporter(m_errorList) {}
 | 
							m_errorReporter(m_errorList) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// @returns the list of errors that occured during parsing and type checking.
 | 
						/// @returns the list of errors that occured during parsing and type checking.
 | 
				
			||||||
	ErrorList const& errors() { return m_errorReporter.errors(); }
 | 
						ErrorList const& errors() const { return m_errorReporter.errors(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// @returns the current state.
 | 
						/// @returns the current state.
 | 
				
			||||||
	State state() const { return m_stackState; }
 | 
						State state() const { return m_stackState; }
 | 
				
			||||||
@ -203,11 +197,13 @@ public:
 | 
				
			|||||||
	/// Prerequisite: Successful call to parse or compile.
 | 
						/// Prerequisite: Successful call to parse or compile.
 | 
				
			||||||
	Json::Value const& contractABI(std::string const& _contractName = "") const;
 | 
						Json::Value const& contractABI(std::string const& _contractName = "") const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// @returns a JSON representing the contract's documentation.
 | 
						/// @returns a JSON representing the contract's user documentation.
 | 
				
			||||||
	/// Prerequisite: Successful call to parse or compile.
 | 
						/// Prerequisite: Successful call to parse or compile.
 | 
				
			||||||
	/// @param type The type of the documentation to get.
 | 
						Json::Value const& natspecUser(std::string const& _contractName) const;
 | 
				
			||||||
	/// Can be one of 4 types defined at @c DocumentationType
 | 
					
 | 
				
			||||||
	Json::Value const& natspec(std::string const& _contractName, DocumentationType _type) const;
 | 
						/// @returns a JSON representing the contract's developer documentation.
 | 
				
			||||||
 | 
						/// Prerequisite: Successful call to parse or compile.
 | 
				
			||||||
 | 
						Json::Value const& natspecDev(std::string const& _contractName) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// @returns a JSON representing a map of method identifiers (hashes) to function names.
 | 
						/// @returns a JSON representing a map of method identifiers (hashes) to function names.
 | 
				
			||||||
	Json::Value methodIdentifiers(std::string const& _contractName) const;
 | 
						Json::Value methodIdentifiers(std::string const& _contractName) const;
 | 
				
			||||||
@ -274,7 +270,8 @@ private:
 | 
				
			|||||||
	std::string createMetadata(Contract const& _contract) const;
 | 
						std::string createMetadata(Contract const& _contract) const;
 | 
				
			||||||
	std::string computeSourceMapping(eth::AssemblyItems const& _items) const;
 | 
						std::string computeSourceMapping(eth::AssemblyItems const& _items) const;
 | 
				
			||||||
	Json::Value const& contractABI(Contract const&) const;
 | 
						Json::Value const& contractABI(Contract const&) const;
 | 
				
			||||||
	Json::Value const& natspec(Contract const&, DocumentationType _type) const;
 | 
						Json::Value const& natspecUser(Contract const&) const;
 | 
				
			||||||
 | 
						Json::Value const& natspecDev(Contract const&) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// @returns the offset of the entry point of the given function into the list of assembly items
 | 
						/// @returns the offset of the entry point of the given function into the list of assembly items
 | 
				
			||||||
	/// or zero if it is not found or does not exist.
 | 
						/// or zero if it is not found or does not exist.
 | 
				
			||||||
@ -290,7 +287,8 @@ private:
 | 
				
			|||||||
		std::string target;
 | 
							std::string target;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ReadFile::Callback m_readFile;
 | 
						ReadCallback::Callback m_readFile;
 | 
				
			||||||
 | 
						ReadCallback::Callback m_smtQuery;
 | 
				
			||||||
	bool m_optimize = false;
 | 
						bool m_optimize = false;
 | 
				
			||||||
	unsigned m_optimizeRuns = 200;
 | 
						unsigned m_optimizeRuns = 200;
 | 
				
			||||||
	std::map<std::string, h160> m_libraries;
 | 
						std::map<std::string, h160> m_libraries;
 | 
				
			||||||
 | 
				
			|||||||
@ -36,7 +36,7 @@ class ErrorReporter
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ErrorReporter(ErrorList& _errors):
 | 
						explicit ErrorReporter(ErrorList& _errors):
 | 
				
			||||||
		m_errorList(_errors) { }
 | 
							m_errorList(_errors) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ErrorReporter& operator=(ErrorReporter const& _errorReporter);
 | 
						ErrorReporter& operator=(ErrorReporter const& _errorReporter);
 | 
				
			||||||
@ -75,8 +75,8 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	void typeError(
 | 
						void typeError(
 | 
				
			||||||
		SourceLocation const& _location,
 | 
							SourceLocation const& _location,
 | 
				
			||||||
		SecondarySourceLocation const& _secondaryLocation,
 | 
							SecondarySourceLocation const& _secondaryLocation = SecondarySourceLocation(),
 | 
				
			||||||
		std::string const& _description
 | 
							std::string const& _description = std::string()
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void typeError(SourceLocation const& _location, std::string const& _description);
 | 
						void typeError(SourceLocation const& _location, std::string const& _description);
 | 
				
			||||||
 | 
				
			|||||||
@ -27,17 +27,17 @@ namespace dev
 | 
				
			|||||||
namespace solidity
 | 
					namespace solidity
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ReadFile: boost::noncopyable
 | 
					class ReadCallback: boost::noncopyable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	/// File reading result.
 | 
						/// File reading or generic query result.
 | 
				
			||||||
	struct Result
 | 
						struct Result
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		bool success;
 | 
							bool success;
 | 
				
			||||||
		std::string contentsOrErrorMessage;
 | 
							std::string responseOrErrorMessage;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// File reading callback.
 | 
						/// File reading or generic query callback.
 | 
				
			||||||
	using Callback = std::function<Result(std::string const&)>;
 | 
						using Callback = std::function<Result(std::string const&)>;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -203,10 +203,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			for (auto const& url: sources[sourceName]["urls"])
 | 
								for (auto const& url: sources[sourceName]["urls"])
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				ReadFile::Result result = m_readFile(url.asString());
 | 
									ReadCallback::Result result = m_readFile(url.asString());
 | 
				
			||||||
				if (result.success)
 | 
									if (result.success)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					if (!hash.empty() && !hashMatchesContent(hash, result.contentsOrErrorMessage))
 | 
										if (!hash.empty() && !hashMatchesContent(hash, result.responseOrErrorMessage))
 | 
				
			||||||
						errors.append(formatError(
 | 
											errors.append(formatError(
 | 
				
			||||||
							false,
 | 
												false,
 | 
				
			||||||
							"IOError",
 | 
												"IOError",
 | 
				
			||||||
@ -215,13 +215,13 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
 | 
				
			|||||||
						));
 | 
											));
 | 
				
			||||||
					else
 | 
										else
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						m_compilerStack.addSource(sourceName, result.contentsOrErrorMessage);
 | 
											m_compilerStack.addSource(sourceName, result.responseOrErrorMessage);
 | 
				
			||||||
						found = true;
 | 
											found = true;
 | 
				
			||||||
						break;
 | 
											break;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				else
 | 
									else
 | 
				
			||||||
					failures.push_back("Cannot import url (\"" + url.asString() + "\"): " + result.contentsOrErrorMessage);
 | 
										failures.push_back("Cannot import url (\"" + url.asString() + "\"): " + result.responseOrErrorMessage);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (auto const& failure: failures)
 | 
								for (auto const& failure: failures)
 | 
				
			||||||
@ -394,8 +394,8 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
 | 
				
			|||||||
		Json::Value contractData(Json::objectValue);
 | 
							Json::Value contractData(Json::objectValue);
 | 
				
			||||||
		contractData["abi"] = m_compilerStack.contractABI(contractName);
 | 
							contractData["abi"] = m_compilerStack.contractABI(contractName);
 | 
				
			||||||
		contractData["metadata"] = m_compilerStack.metadata(contractName);
 | 
							contractData["metadata"] = m_compilerStack.metadata(contractName);
 | 
				
			||||||
		contractData["userdoc"] = m_compilerStack.natspec(contractName, DocumentationType::NatspecUser);
 | 
							contractData["userdoc"] = m_compilerStack.natspecUser(contractName);
 | 
				
			||||||
		contractData["devdoc"] = m_compilerStack.natspec(contractName, DocumentationType::NatspecDev);
 | 
							contractData["devdoc"] = m_compilerStack.natspecDev(contractName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// EVM
 | 
							// EVM
 | 
				
			||||||
		Json::Value evmData(Json::objectValue);
 | 
							Json::Value evmData(Json::objectValue);
 | 
				
			||||||
 | 
				
			|||||||
@ -40,7 +40,7 @@ public:
 | 
				
			|||||||
	/// Creates a new StandardCompiler.
 | 
						/// Creates a new StandardCompiler.
 | 
				
			||||||
	/// @param _readFile callback to used to read files for import statements. Must return
 | 
						/// @param _readFile callback to used to read files for import statements. Must return
 | 
				
			||||||
	/// and must not emit exceptions.
 | 
						/// and must not emit exceptions.
 | 
				
			||||||
	StandardCompiler(ReadFile::Callback const& _readFile = ReadFile::Callback())
 | 
						explicit StandardCompiler(ReadCallback::Callback const& _readFile = ReadCallback::Callback())
 | 
				
			||||||
		: m_compilerStack(_readFile), m_readFile(_readFile)
 | 
							: m_compilerStack(_readFile), m_readFile(_readFile)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -56,7 +56,7 @@ private:
 | 
				
			|||||||
	Json::Value compileInternal(Json::Value const& _input);
 | 
						Json::Value compileInternal(Json::Value const& _input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CompilerStack m_compilerStack;
 | 
						CompilerStack m_compilerStack;
 | 
				
			||||||
	ReadFile::Callback m_readFile;
 | 
						ReadCallback::Callback m_readFile;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user