diff --git a/BuildInfo.h.in b/BuildInfo.h.in new file mode 100644 index 000000000..7d2bfc1c8 --- /dev/null +++ b/BuildInfo.h.in @@ -0,0 +1,7 @@ +#pragma once + +#define ETH_COMMIT_HASH @ETH_COMMIT_HASH@ +#define ETH_CLEAN_REPO @ETH_CLEAN_REPO@ +#define ETH_BUILD_TYPE @ETH_BUILD_TYPE@ +#define ETH_BUILD_PLATFORM @ETH_BUILD_PLATFORM@ + diff --git a/BuildInfo.sh b/BuildInfo.sh deleted file mode 100644 index 0370297df..000000000 --- a/BuildInfo.sh +++ /dev/null @@ -1,55 +0,0 @@ -CURRENT_SOURCE_DIR=$1 -CURRENT_BINARY_DIR=$2 -BUILD_TYPE=$3 -BUILD_PLATFORM=$4 - -echo "Current source dir: $CURRENT_SOURCE_DIR" -echo "Current binary dir: $CURRENT_BINARY_DIR" -echo "Build type: $BUILD_TYPE" -echo "Build platform: $BUILD_PLATFORM" - -if [[ -e "$CURRENT_SOURCE_DIR/BuildInfo.h" ]] -then - echo "Using existing BuildInfo.h" - cp $CURRENT_SOURCE_DIR/BuildInfo.h $CURRENT_BINARY_DIR/BuildInfo.h.tmp -else - if [[ -e "$CURRENT_SOURCE_DIR/.git" ]] - then - ETH_COMMIT_HASH=$(git --git-dir=$CURRENT_SOURCE_DIR/.git --work-tree=$CURRENT_SOURCE_DIR rev-parse HEAD) - ETH_LOCAL_CHANGES=$(git --git-dir=$CURRENT_SOURCE_DIR/.git --work-tree=$CURRENT_SOURCE_DIR diff --shortstat) - if [[ -z "$ETH_LOCAL_CHANGES" ]] - then - ETH_CLEAN_REPO=1 - else - ETH_CLEAN_REPO=0 - fi - - echo "Commit hash: ${ETH_COMMIT_HASH} (Clean: ${ETH_CLEAN_REPO} - ${ETH_LOCAL_CHANGES})" - else - echo "Unknown repo." - ETH_COMMIT_HASH=0 - ETH_CLEAN_REPO=1 - fi - - echo "// This file was automatically generated by cmake" > $CURRENT_BINARY_DIR/BuildInfo.h.tmp - echo "" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp - echo "#pragma once" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp - echo "" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp - echo "#define ETH_COMMIT_HASH $ETH_COMMIT_HASH" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp - echo "#define ETH_CLEAN_REPO $ETH_CLEAN_REPO" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp - echo "#define ETH_BUILD_TYPE $BUILD_TYPE" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp - echo "#define ETH_BUILD_PLATFORM $BUILD_PLATFORM" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp -fi - -if [[ -e "$CURRENT_BINARY_DIR/BuildInfo.h" ]] -then - DIFF=$(diff $CURRENT_BINARY_DIR/BuildInfo.h $CURRENT_BINARY_DIR/BuildInfo.h.tmp) - if [[ -z "$DIFF" ]] - then - rm $CURRENT_BINARY_DIR/BuildInfo.h.tmp - else - mv $CURRENT_BINARY_DIR/BuildInfo.h.tmp $CURRENT_BINARY_DIR/BuildInfo.h - fi -else - mv $CURRENT_BINARY_DIR/BuildInfo.h.tmp $CURRENT_BINARY_DIR/BuildInfo.h -fi diff --git a/CMakeLists.txt b/CMakeLists.txt index a3adde425..5aa1f5fcd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,12 @@ function(createBuildInfo) endif() # Generate header file containing useful build information - add_custom_target(BuildInfo.h ALL COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/BuildInfo.sh ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${_cmake_build_type} ${ETH_BUILD_PLATFORM}) + add_custom_target(BuildInfo.h ALL + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND ${CMAKE_COMMAND} -DETH_SOURCE_DIR="${CMAKE_SOURCE_DIR}" -DETH_DST_DIR="${CMAKE_BINARY_DIR}" + -DETH_BUILD_TYPE="${_cmake_build_type}" -DETH_BUILD_PLATFORM="${ETH_BUILD_PLATFORM}" + -P "${ETH_SCRIPTS_DIR}/buildinfo.cmake" + ) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 8ff3d1460..bcb0780c1 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -7,6 +7,14 @@ string(TOLOWER ${CMAKE_SYSTEM_NAME} _system_name) set (ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extdep/install/${_system_name}") set (CMAKE_PREFIX_PATH ${ETH_DEPENDENCY_INSTALL_DIR}) +# setup directory for cmake generated files and include it globally +# it's not used yet, but if we have more generated files, consider moving them to ETH_GENERATED_DIR +set(ETH_GENERATED_DIR "${PROJECT_BINARY_DIR}/gen") +include_directories(${ETH_GENERATED_DIR}) + +# custom cmake scripts +set(ETH_SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/cmake/scripts) + # Qt5 requires opengl # TODO use proper version of windows SDK (32 vs 64) # TODO make it possible to use older versions of windows SDK (7.0+ should also work) @@ -87,6 +95,10 @@ find_package (CURL) message(" - curl header: ${CURL_INCLUDE_DIRS}") message(" - curl lib : ${CURL_LIBRARIES}") +# find location of jsonrpcstub +find_program(ETH_JSON_RPC_STUB jsonrpcstub) +message(" - jsonrpcstub location : ${ETH_JSON_RPC_STUB}") + # do not compile GUI if (NOT HEADLESS) @@ -122,8 +134,6 @@ if (NOT HEADLESS) string(REGEX REPLACE "npm" "" ETH_NPM_DIRECTORY ${ETH_NPM}) message(" - npm location : ${ETH_NPM}") - find_program(ETH_JSON_RPC_STUB jsonrpcstub) - endif() #HEADLESS # use multithreaded boost libraries, with -mt suffix diff --git a/cmake/EthUtils.cmake b/cmake/EthUtils.cmake new file mode 100644 index 000000000..c6fd43ed4 --- /dev/null +++ b/cmake/EthUtils.cmake @@ -0,0 +1,24 @@ +# +# renames the file if it is different from its destination +include(CMakeParseArguments) +# +macro(replace_if_different SOURCE DST) + set(extra_macro_args ${ARGN}) + set(options CREATE) + set(one_value_args) + set(multi_value_args) + cmake_parse_arguments(REPLACE_IF_DIFFERENT "${options}" "${one_value_args}" "${multi_value_args}" "${extra_macro_args}") + + if (REPLACE_IF_DIFFERENT_CREATE AND (NOT (EXISTS "${DST}"))) + file(WRITE "${DST}" "") + endif() + + execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files "${SOURCE}" "${DST}" RESULT_VARIABLE DIFFERENT) + + if (DIFFERENT) + execute_process(COMMAND ${CMAKE_COMMAND} -E rename "${SOURCE}" "${DST}") + else() + execute_process(COMMAND ${CMAKE_COMMAND} -E remove "${SOURCE}") + endif() +endmacro() + diff --git a/cmake/scripts/buildinfo.cmake b/cmake/scripts/buildinfo.cmake new file mode 100644 index 000000000..a0666c9f5 --- /dev/null +++ b/cmake/scripts/buildinfo.cmake @@ -0,0 +1,48 @@ +# generates BuildInfo.h +# +# this module expects +# ETH_SOURCE_DIR - main CMAKE_SOURCE_DIR +# ETH_DST_DIR - main CMAKE_BINARY_DIR +# ETH_BUILD_TYPE +# ETH_BUILD_PLATFORM +# +# example usage: +# cmake -DETH_SOURCE_DIR=. -DETH_DST_DIR=build -DETH_BUILD_TYPE=Debug -DETH_BUILD_PLATFORM=mac -P scripts/buildinfo.cmake + +if (NOT ETH_BUILD_TYPE) + set(ETH_BUILD_TYPE "unknown") +endif() + +if (NOT ETH_BUILD_PLATFORM) + set(ETH_BUILD_PLATFORM "unknown") +endif() + +execute_process( + COMMAND git --git-dir=${ETH_SOURCE_DIR}/.git --work-tree=${ETH_SOURCE_DIR} rev-parse HEAD + OUTPUT_VARIABLE ETH_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET +) + +if (NOT ETH_COMMIT_HASH) + set(ETH_COMMIT_HASH 0) +endif() + +execute_process( + COMMAND git --git-dir=${ETH_SOURCE_DIR}/.git --work-tree=${ETH_SOURCE_DIR} diff --shortstat + OUTPUT_VARIABLE ETH_LOCAL_CHANGES OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET +) + +if (ETH_LOCAL_CHANGES) + set(ETH_CLEAN_REPO 0) +else() + set(ETH_CLEAN_REPO 1) +endif() + +set(INFILE "${ETH_SOURCE_DIR}/BuildInfo.h.in") +set(TMPFILE "${ETH_DST_DIR}/BuildInfo.h.tmp") +set(OUTFILE "${ETH_DST_DIR}/BuildInfo.h") + +configure_file("${INFILE}" "${TMPFILE}") + +include("${ETH_SOURCE_DIR}/cmake/EthUtils.cmake") +replace_if_different("${TMPFILE}" "${OUTFILE}" CREATE) + diff --git a/cmake/scripts/configure.cmake b/cmake/scripts/configure.cmake new file mode 100644 index 000000000..76fb7b757 --- /dev/null +++ b/cmake/scripts/configure.cmake @@ -0,0 +1,14 @@ +# adds possibility to run configure_file as buildstep +# reference: +# http://www.cmake.org/pipermail/cmake/2012-May/050227.html +# +# This module expects +# INFILE +# OUTFILE +# other custom vars +# +# example usage: +# cmake -DINFILE=blah.in -DOUTFILE=blah.out -Dvar1=value1 -Dvar2=value2 -P scripts/configure.cmake + +configure_file(${INFILE} ${OUTFILE}) + diff --git a/cmake/scripts/jsonrpcstub.cmake b/cmake/scripts/jsonrpcstub.cmake new file mode 100644 index 000000000..a9b2c44ab --- /dev/null +++ b/cmake/scripts/jsonrpcstub.cmake @@ -0,0 +1,36 @@ +# generates JSONRPC Stub Server && Client +# +# this script expects +# ETH_SOURCE_DIR - main CMAKE_SOURCE_DIR +# ETH_SPEC_PATH +# ETH_SERVER_DIR +# ETH_CLIENT_DIR +# ETH_SERVER_NAME +# ETH_CLIENT_NAME +# ETH_JSON_RPC_STUB +# +# example usage: +# cmake -DETH_SPEC_PATH=spec.json -DETH_SERVER_DIR=libweb3jsonrpc -DETH_CLIENT_DIR=test +# -DETH_SERVER_NAME=AbstractWebThreeStubServer -DETH_CLIENT_NAME=WebThreeStubClient -DETH_JSON_RPC_STUB=/usr/local/bin/jsonrpcstub + +# by default jsonrpcstub produces files in lowercase, we want to stick to this +string(TOLOWER ${ETH_SERVER_NAME} ETH_SERVER_NAME_LOWER) +string(TOLOWER ${ETH_CLIENT_NAME} ETH_CLIENT_NAME_LOWER) + +# setup names +set(SERVER_TMPFILE "${ETH_SERVER_DIR}/${ETH_SERVER_NAME_LOWER}.h.tmp") +set(SERVER_OUTFILE "${ETH_SERVER_DIR}/${ETH_SERVER_NAME_LOWER}.h") +set(CLIENT_TMPFILE "${ETH_CLIENT_DIR}/${ETH_CLIENT_NAME_LOWER}.h.tmp") +set(CLIENT_OUTFILE "${ETH_CLIENT_DIR}/${ETH_CLIENT_NAME_LOWER}.h") + +# create tmp files +execute_process( + COMMAND ${ETH_JSON_RPC_STUB} ${ETH_SPEC_PATH} + --cpp-server=${ETH_SERVER_NAME} --cpp-server-file=${SERVER_TMPFILE} + --cpp-client=${ETH_CLIENT_NAME} --cpp-client-file=${CLIENT_TMPFILE} +) + +include("${ETH_SOURCE_DIR}/cmake/EthUtils.cmake") +replace_if_different("${SERVER_TMPFILE}" "${SERVER_OUTFILE}") +replace_if_different("${CLIENT_TMPFILE}" "${CLIENT_OUTFILE}") + diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index f71969525..47344a156 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -35,12 +35,12 @@ namespace eth const unsigned c_protocolVersion = 53; const unsigned c_databaseVersion = 5; -template constexpr u256 exp10() +template u256 exp10() { return exp10() * u256(10); } -template <> constexpr u256 exp10<0>() +template <> u256 exp10<0>() { return u256(1); } diff --git a/libnatspec/NatspecExpressionEvaluator.h b/libnatspec/NatspecExpressionEvaluator.h index fc122084e..2ea224027 100644 --- a/libnatspec/NatspecExpressionEvaluator.h +++ b/libnatspec/NatspecExpressionEvaluator.h @@ -19,6 +19,8 @@ * @date 2015 */ +#pragma once + #include #include #include diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 86f54e25c..041b6277d 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -497,20 +497,21 @@ void FunctionCall::checkTypeRequirements() // and then ask if that is implicitly convertible to the struct represented by the // function parameters TypePointers const& parameterTypes = functionType->getParameterTypes(); - if (functionType->getLocation() != FunctionType::Location::SHA3 && parameterTypes.size() != m_arguments.size()) + if (!functionType->takesArbitraryParameters() && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); if (m_names.empty()) { for (size_t i = 0; i < m_arguments.size(); ++i) - if (functionType->getLocation() != FunctionType::Location::SHA3 && + if (!functionType->takesArbitraryParameters() && !m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError("Invalid type for argument in function call.")); } else { - if (functionType->getLocation() == FunctionType::Location::SHA3) - BOOST_THROW_EXCEPTION(createTypeError("Named arguments cannnot be used for SHA3.")); + if (functionType->takesArbitraryParameters()) + BOOST_THROW_EXCEPTION(createTypeError("Named arguments cannnot be used for functions " + "that take arbitrary parameters.")); auto const& parameterNames = functionType->getParameterNames(); if (parameterNames.size() != m_names.size()) BOOST_THROW_EXCEPTION(createTypeError("Some argument names are missing.")); diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index f649f1a4f..beda01322 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -206,7 +206,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) TypePointers const& parameterTypes = function.getParameterTypes(); vector> const& callArguments = _functionCall.getArguments(); vector> const& callArgumentNames = _functionCall.getNames(); - if (function.getLocation() != Location::SHA3) + if (!function.takesArbitraryParameters()) solAssert(callArguments.size() == parameterTypes.size(), ""); vector> arguments; @@ -318,7 +318,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); appendExternalFunctionCall(FunctionType(TypePointers{}, TypePointers{}, - Location::External, true, true), {}, true); + Location::External, false, true, true), {}, true); break; case Location::Suicide: arguments.front()->accept(*this); @@ -327,7 +327,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) break; case Location::SHA3: { - unsigned length = appendArgumentsCopyToMemory(arguments, TypePointers(), 0, false); + unsigned length = appendArgumentsCopyToMemory(arguments, TypePointers(), 0, function.padArguments()); m_context << u256(length) << u256(0) << eth::Instruction::SHA3; break; } @@ -650,6 +650,9 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty case Token::Mod: m_context << (c_isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); break; + case Token::Exp: + m_context << eth::Instruction::EXP; + break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); } @@ -700,21 +703,30 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con if (stackTypeCategory == Type::Category::String) { + StaticStringType const& typeOnStack = dynamic_cast(_typeOnStack); if (targetTypeCategory == Type::Category::Integer) { // conversion from string to hash. no need to clean the high bit // only to shift right because of opposite alignment IntegerType const& targetIntegerType = dynamic_cast(_targetType); - StaticStringType const& typeOnStack = dynamic_cast(_typeOnStack); solAssert(targetIntegerType.isHash(), "Only conversion between String and Hash is allowed."); solAssert(targetIntegerType.getNumBits() == typeOnStack.getNumBytes() * 8, "The size should be the same."); m_context << (u256(1) << (256 - typeOnStack.getNumBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV; } else { + // clear lower-order bytes for conversion to shorter strings - we always clean solAssert(targetTypeCategory == Type::Category::String, "Invalid type conversion requested."); - // nothing to do, strings are high-order-bit-aligned - //@todo clear lower-order bytes if we allow explicit conversion to shorter strings + StaticStringType const& targetType = dynamic_cast(_targetType); + if (targetType.getNumBytes() < typeOnStack.getNumBytes()) + { + if (targetType.getNumBytes() == 0) + m_context << eth::Instruction::DUP1 << eth::Instruction::XOR; + else + m_context << (u256(1) << (256 - targetType.getNumBytes() * 8)) + << eth::Instruction::DUP1 << eth::Instruction::SWAP2 + << eth::Instruction::DIV << eth::Instruction::MUL; + } } } else if (stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::Contract || @@ -776,7 +788,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio vector> const& _arguments, bool bare) { - solAssert(_arguments.size() == _functionType.getParameterTypes().size(), ""); + solAssert(_functionType.takesArbitraryParameters() || + _arguments.size() == _functionType.getParameterTypes().size(), ""); // Assumed stack content here: // @@ -800,7 +813,10 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio // reserve space for the function identifier unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset; - dataOffset += appendArgumentsCopyToMemory(_arguments, _functionType.getParameterTypes(), dataOffset); + // For bare call, activate "4 byte pad exception": If the first argument has exactly 4 bytes, + // do not pad it to 32 bytes. + dataOffset += appendArgumentsCopyToMemory(_arguments, _functionType.getParameterTypes(), dataOffset, + _functionType.padArguments(), bare); //@todo only return the first return value for now Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : @@ -839,7 +855,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vector> const& _arguments, TypePointers const& _types, unsigned _memoryOffset, - bool _padToWordBoundaries) + bool _padToWordBoundaries, + bool _padExceptionIfFourBytes) { solAssert(_types.empty() || _types.size() == _arguments.size(), ""); unsigned length = 0; @@ -848,8 +865,12 @@ unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vectoraccept(*this); TypePointer const& expectedType = _types.empty() ? _arguments[i]->getType()->getRealType() : _types[i]; appendTypeConversion(*_arguments[i]->getType(), *expectedType, true); + bool pad = _padToWordBoundaries; + // Do not pad if the first argument has exactly four bytes + if (i == 0 && pad && _padExceptionIfFourBytes && expectedType->getCalldataEncodedSize() == 4) + pad = false; length += appendTypeMoveToMemory(*expectedType, _arguments[i]->getLocation(), - _memoryOffset + length, _padToWordBoundaries); + _memoryOffset + length, pad); } return length; } diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index df8a0516e..3c94d74c2 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -97,7 +97,8 @@ private: unsigned appendArgumentsCopyToMemory(std::vector> const& _arguments, TypePointers const& _types = {}, unsigned _memoryOffset = 0, - bool _padToWordBoundaries = true); + bool _padToWordBoundaries = true, + bool _padExceptionIfFourBytes = false); /// Appends code that moves a stack element of the given type to memory /// @returns the number of bytes moved to memory unsigned appendTypeMoveToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset, diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp index 8443e7bd9..60de5105f 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/GlobalContext.cpp @@ -40,7 +40,7 @@ m_magicVariables(vector>{make_shared< make_shared("suicide", make_shared(strings{"address"}, strings{}, FunctionType::Location::Suicide)), make_shared("sha3", - make_shared(strings{"hash"}, strings{"hash"}, FunctionType::Location::SHA3)), + make_shared(strings(), strings{"hash"}, FunctionType::Location::SHA3, true)), make_shared("log0", make_shared(strings{"hash"},strings{}, FunctionType::Location::Log0)), make_shared("log1", @@ -52,11 +52,11 @@ m_magicVariables(vector>{make_shared< make_shared("log4", make_shared(strings{"hash", "hash", "hash", "hash", "hash"},strings{}, FunctionType::Location::Log4)), make_shared("sha256", - make_shared(strings{"hash"}, strings{"hash"}, FunctionType::Location::SHA256)), + make_shared(strings(), strings{"hash"}, FunctionType::Location::SHA256, true)), make_shared("ecrecover", make_shared(strings{"hash", "hash8", "hash", "hash"}, strings{"address"}, FunctionType::Location::ECRecover)), make_shared("ripemd160", - make_shared(strings{"hash"}, strings{"hash160"}, FunctionType::Location::RIPEMD160))}) + make_shared(strings(), strings{"hash160"}, FunctionType::Location::RIPEMD160, true))}) { } diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index fc4bdb6b5..fbe3ea974 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -465,8 +465,14 @@ void Scanner::scanToken() token = Token::Sub; break; case '*': - // * *= - token = selectToken('=', Token::AssignMul, Token::Mul); + // * ** *= + advance(); + if (m_char == '*') + token = selectToken(Token::Exp); + else if (m_char == '=') + token = selectToken(Token::AssignMul); + else + token = Token::Mul; break; case '%': // % %= diff --git a/libsolidity/Token.h b/libsolidity/Token.h index b913f0cec..ac8c618fa 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -118,6 +118,7 @@ namespace solidity T(Mul, "*", 13) \ T(Div, "/", 13) \ T(Mod, "%", 13) \ + T(Exp, "**", 14) \ \ /* Compare operators sorted by precedence. */ \ /* IsCompareOp() relies on this block of enum values */ \ @@ -361,10 +362,10 @@ public: // Predicates static bool isElementaryTypeName(Value tok) { return Int <= tok && tok < TypesEnd; } static bool isAssignmentOp(Value tok) { return Assign <= tok && tok <= AssignMod; } - static bool isBinaryOp(Value op) { return Comma <= op && op <= Mod; } + static bool isBinaryOp(Value op) { return Comma <= op && op <= Exp; } static bool isCommutativeOp(Value op) { return op == BitOr || op == BitXor || op == BitAnd || op == Add || op == Mul || op == Equal || op == NotEqual; } - static bool isArithmeticOp(Value op) { return Add <= op && op <= Mod; } + static bool isArithmeticOp(Value op) { return Add <= op && op <= Exp; } static bool isCompareOp(Value op) { return Equal <= op && op <= In; } static Value AssignmentToBinaryOp(Value op) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 02c293b7d..5f573a6da 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -26,6 +26,8 @@ #include #include +#include + using namespace std; namespace dev @@ -210,10 +212,7 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe const MemberList IntegerType::AddressMemberList = MemberList({{"balance", make_shared(256)}, - {"callstring32", make_shared(strings{"string32"}, strings{}, - FunctionType::Location::Bare)}, - {"callstring32string32", make_shared(strings{"string32", "string32"}, - strings{}, FunctionType::Location::Bare)}, + {"call", make_shared(strings(), strings(), FunctionType::Location::Bare, true)}, {"send", make_shared(strings{"uint"}, strings{}, FunctionType::Location::Send)}}); IntegerConstantType::IntegerConstantType(Literal const& _literal) @@ -323,6 +322,14 @@ TypePointer IntegerConstantType::binaryOperatorResult(Token::Value _operator, Ty return TypePointer(); value = m_value % other.m_value; break; + case Token::Exp: + if (other.m_value < 0) + return TypePointer(); + else if (other.m_value > std::numeric_limits::max()) + return TypePointer(); + else + value = boost::multiprecision::pow(m_value, other.m_value.convert_to()); + break; default: return TypePointer(); } @@ -401,13 +408,16 @@ bool StaticStringType::isImplicitlyConvertibleTo(Type const& _convertTo) const bool StaticStringType::isExplicitlyConvertibleTo(Type const& _convertTo) const { + if (_convertTo.getCategory() == getCategory()) + return true; if (_convertTo.getCategory() == Category::Integer) { IntegerType const& convertTo = dynamic_cast(_convertTo); if (convertTo.isHash() && (m_bytes * 8 == convertTo.getNumBits())) return true; } - return isImplicitlyConvertibleTo(_convertTo); + + return false; } bool StaticStringType::operator==(Type const& _other) const @@ -766,10 +776,10 @@ MemberList const& FunctionType::getMembers() const map members{ {"gas", make_shared(parseElementaryTypeVector({"uint"}), TypePointers{copyAndSetGasOrValue(true, false)}, - Location::SetGas, m_gasSet, m_valueSet)}, + Location::SetGas, false, m_gasSet, m_valueSet)}, {"value", make_shared(parseElementaryTypeVector({"uint"}), TypePointers{copyAndSetGasOrValue(false, true)}, - Location::SetValue, m_gasSet, m_valueSet)}}; + Location::SetValue, false, m_gasSet, m_valueSet)}}; if (m_location == Location::Creation) members.erase("gas"); m_members.reset(new MemberList(members)); @@ -808,6 +818,7 @@ TypePointers FunctionType::parseElementaryTypeVector(strings const& _types) TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) const { return make_shared(m_parameterTypes, m_returnParameterTypes, m_location, + m_arbitraryParameters, m_gasSet || _setGas, m_valueSet || _setValue); } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index d09782954..05090c7a2 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -367,14 +367,15 @@ public: explicit FunctionType(VariableDeclaration const& _varDecl); explicit FunctionType(EventDefinition const& _event); FunctionType(strings const& _parameterTypes, strings const& _returnParameterTypes, - Location _location = Location::Internal): + Location _location = Location::Internal, bool _arbitraryParameters = false): FunctionType(parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), - _location) {} + _location, _arbitraryParameters) {} FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, Location _location = Location::Internal, - bool _gasSet = false, bool _valueSet = false): + bool _arbitraryParameters = false, bool _gasSet = false, bool _valueSet = false): m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), - m_location(_location), m_gasSet(_gasSet), m_valueSet(_valueSet) {} + m_location(_location), + m_arbitraryParameters(_arbitraryParameters), m_gasSet(_gasSet), m_valueSet(_valueSet) {} TypePointers const& getParameterTypes() const { return m_parameterTypes; } std::vector const& getParameterNames() const { return m_parameterNames; } @@ -407,6 +408,9 @@ public: /// Can contain a nullptr in which case indicates absence of documentation ASTPointer getDocumentation() const; + /// true iff arguments are to be padded to multiples of 32 bytes for external calls + bool padArguments() const { return !(m_location == Location::SHA3 || m_location == Location::SHA256 || m_location == Location::RIPEMD160); } + bool takesArbitraryParameters() const { return m_arbitraryParameters; } bool gasSet() const { return m_gasSet; } bool valueSet() const { return m_valueSet; } @@ -422,6 +426,8 @@ private: std::vector m_parameterNames; std::vector m_returnParameterNames; Location const m_location; + /// true iff the function takes an arbitrary number of arguments of arbitrary types + 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_valueSet = false; ///< true iff the value to be sent is on the stack bool m_isConstant; diff --git a/libweb3jsonrpc/CMakeLists.txt b/libweb3jsonrpc/CMakeLists.txt index e18a53cd8..c9b2aa39d 100644 --- a/libweb3jsonrpc/CMakeLists.txt +++ b/libweb3jsonrpc/CMakeLists.txt @@ -37,8 +37,11 @@ if (ETH_JSON_RPC_STUB) add_custom_command(TARGET jsonrpcstub POST_BUILD WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND ${ETH_JSON_RPC_STUB} spec.json --cpp-server=AbstractWebThreeStubServer --cpp-client=WebThreeStubClient - COMMAND cmake -E rename webthreestubclient.h ../test/webthreestubclient.h + COMMAND ${CMAKE_COMMAND} -DETH_SPEC_PATH="${CMAKE_CURRENT_SOURCE_DIR}/spec.json" -DETH_SOURCE_DIR="${CMAKE_SOURCE_DIR}" + -DETH_SERVER_DIR="${CMAKE_CURRENT_SOURCE_DIR}" -DETH_CLIENT_DIR="${CMAKE_SOURCE_DIR}/test" + -DETH_SERVER_NAME=AbstractWebThreeStubServer -DETH_CLIENT_NAME=WebThreeStubClient + -DETH_JSON_RPC_STUB="${ETH_JSON_RPC_STUB}" + -P "${ETH_SCRIPTS_DIR}/jsonrpcstub.cmake" ) add_dependencies(${EXECUTABLE} jsonrpcstub) endif() diff --git a/mix/AppContext.cpp b/mix/AppContext.cpp index a806a39f4..7fe22106f 100644 --- a/mix/AppContext.cpp +++ b/mix/AppContext.cpp @@ -81,6 +81,8 @@ void AppContext::load() BOOST_THROW_EXCEPTION(exception); } m_applicationEngine->rootContext()->setContextProperty("projectModel", projectModel); + QFont f; + m_applicationEngine->rootContext()->setContextProperty("systemPointSize", f.pointSize()); qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); qmlRegisterType("HttpServer", 1, 0, "HttpServer"); m_applicationEngine->load(QUrl("qrc:/qml/main.qml")); diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 10a60811f..b7be8988a 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -89,7 +89,6 @@ ClientModel::ClientModel(AppContext* _context): m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), std::vector { m_client->userAccount() }, m_client.get())); connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection); - _context->appEngine()->rootContext()->setContextProperty("clientModel", this); } diff --git a/mix/qml/BasicContent.qml b/mix/qml/BasicContent.qml deleted file mode 100644 index ff31dc86f..000000000 --- a/mix/qml/BasicContent.qml +++ /dev/null @@ -1,35 +0,0 @@ -import QtQuick 2.2 -import QtQuick.Controls 1.1 - -Rectangle { - anchors.fill: parent - width: parent.width - height: parent.height - color: "lightgray" - Text { - font.pointSize: 9 - anchors.left: parent.left - anchors.top: parent.top - anchors.topMargin: 3 - anchors.leftMargin: 3 - height: 9 - font.family: "Monospace" - objectName: "status" - id: status - } - TextArea { - readOnly: true - anchors.left: parent.left - anchors.leftMargin: 10 - anchors.top: status.bottom - anchors.topMargin: 3 - font.pointSize: 9 - font.family: "Monospace" - height: parent.height * 0.8 - width: parent.width - 20 - wrapMode: Text.Wrap - backgroundVisible: false - objectName: "content" - id: content - } -} diff --git a/mix/qml/CodeEditor.qml b/mix/qml/CodeEditor.qml index 0c554b379..9d3df69e5 100644 --- a/mix/qml/CodeEditor.qml +++ b/mix/qml/CodeEditor.qml @@ -3,6 +3,7 @@ import QtQuick.Window 2.0 import QtQuick.Layouts 1.0 import QtQuick.Controls 1.0 import QtQuick.Controls.Styles 1.1 +import "." Item { signal editorTextChanged @@ -65,7 +66,7 @@ Item { height: parent.height font.family: "Monospace" - font.pointSize: 12 + font.pointSize: CodeEditorStyle.general.basicFontSize width: parent.width tabChangesFocus: false diff --git a/mix/qml/CodeEditorStyle.qml b/mix/qml/CodeEditorStyle.qml new file mode 100644 index 000000000..c9740957c --- /dev/null +++ b/mix/qml/CodeEditorStyle.qml @@ -0,0 +1,14 @@ +pragma Singleton +import QtQuick 2.0 + +QtObject { + + function absoluteSize(rel) + { + return systemPointSize + rel; + } + + property QtObject general: QtObject { + property int basicFontSize: absoluteSize(1) + } +} diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index e9c718f70..2bf23ccef 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -6,6 +6,7 @@ import QtQuick.Layouts 1.1 import Qt.labs.settings 1.0 import "js/Debugger.js" as Debugger import "js/ErrorLocationFormater.js" as ErrorLocationFormater +import "." Rectangle { id: debugPanel @@ -346,7 +347,7 @@ Rectangle { color: "#b2b3ae" text: styleData.value.split(' ')[0] font.family: "monospace" - font.pointSize: 9 + font.pointSize: DebuggerPaneStyle.general.basicFontSize wrapMode: Text.NoWrap id: id } @@ -356,7 +357,7 @@ Rectangle { color: styleData.selected ? "white" : "black" font.family: "monospace" text: styleData.value.replace(styleData.value.split(' ')[0], '') - font.pointSize: 9 + font.pointSize: DebuggerPaneStyle.general.basicFontSize } } } @@ -425,11 +426,11 @@ Rectangle { Layout.minimumHeight: parent.height Text { anchors.centerIn: parent - anchors.leftMargin: 5 + anchors.leftMargin: 5() font.family: "monospace" color: "#4a4a4a" text: styleData.row; - font.pointSize: 9 + font.pointSize: DebuggerPaneStyle.general.basicFontSize } } @@ -447,7 +448,7 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter color: "#4a4a4a" text: styleData.value - font.pointSize: 9 + font.pointSize: DebuggerPaneStyle.general.basicFontSize } } } @@ -514,7 +515,7 @@ Rectangle { anchors.leftMargin: 5 color: "#4a4a4a" text: styleData.row; - font.pointSize: 9 + font.pointSize: DebuggerPaneStyle.general.basicFontSize width: parent.width - 5 elide: Text.ElideRight } @@ -535,7 +536,7 @@ Rectangle { color: "#4a4a4a" text: styleData.value; elide: Text.ElideRight - font.pointSize: 9 + font.pointSize: DebuggerPaneStyle.general.basicFontSize } } } @@ -585,7 +586,7 @@ Rectangle { anchors.leftMargin: 5 color: "#4a4a4a" text: styleData.value.split('\t')[0]; - font.pointSize: 9 + font.pointSize: DebuggerPaneStyle.general.basicFontSize width: parent.width - 5 elide: Text.ElideRight } @@ -606,7 +607,7 @@ Rectangle { color: "#4a4a4a" text: styleData.value.split('\t')[1]; elide: Text.ElideRight - font.pointSize: 9 + font.pointSize: DebuggerPaneStyle.general.basicFontSize } } } diff --git a/mix/qml/DebuggerPaneStyle.qml b/mix/qml/DebuggerPaneStyle.qml new file mode 100644 index 000000000..1078df2f9 --- /dev/null +++ b/mix/qml/DebuggerPaneStyle.qml @@ -0,0 +1,15 @@ +pragma Singleton +import QtQuick 2.0 + +QtObject { + + function absoluteSize(rel) + { + return systemPointSize + rel; + } + + property QtObject general: QtObject { + property int basicFontSize: absoluteSize(-2) + property int dataDumpFontSize: absoluteSize(-3) + } +} diff --git a/mix/qml/FilesSection.qml b/mix/qml/FilesSection.qml index 32202f839..76e235e7d 100644 --- a/mix/qml/FilesSection.qml +++ b/mix/qml/FilesSection.qml @@ -20,17 +20,17 @@ ColumnLayout { function hiddenHeightTopLevel() { - return section.state === "hidden" ? Style.documentsList.height : Style.documentsList.fileNameHeight * model.count + Style.documentsList.height; + return section.state === "hidden" ? ProjectFilesStyle.documentsList.height : ProjectFilesStyle.documentsList.fileNameHeight * model.count + ProjectFilesStyle.documentsList.height; } function hiddenHeightRepeater() { - return section.state === "hidden" ? 0 : Style.documentsList.fileNameHeight * wrapperItem.model.count; + return section.state === "hidden" ? 0 : ProjectFilesStyle.documentsList.fileNameHeight * wrapperItem.model.count; } function hiddenHeightElement() { - return section.state === "hidden" ? 0 : Style.documentsList.fileNameHeight; + return section.state === "hidden" ? 0 : ProjectFilesStyle.documentsList.fileNameHeight; } function getDocumentIndex(documentId) @@ -65,7 +65,7 @@ ColumnLayout { anchors.top: parent.top id: rowCol width: parent.width - height: Style.documentsList.height + height: ProjectFilesStyle.documentsList.height Image { source: "qrc:/qml/img/opentriangleindicator_filesproject.png" @@ -83,15 +83,15 @@ ColumnLayout { id: section text: sectionName anchors.left: parent.left - anchors.leftMargin: Style.general.leftMargin - color: Style.documentsList.sectionColor + anchors.leftMargin: ProjectFilesStyle.general.leftMargin + color: ProjectFilesStyle.documentsList.sectionColor font.family: boldFont.name - font.pointSize: Style.documentsList.sectionFontSize + font.pointSize: ProjectFilesStyle.documentsList.sectionFontSize states: [ State { name: "hidden" PropertyChanges { target: filesList; visible: false; } - PropertyChanges { target: rowCol; Layout.minimumHeight: Style.documentsList.height; Layout.maximumHeight: Style.documentsList.height; height: Style.documentsList.height; } + PropertyChanges { target: rowCol; Layout.minimumHeight: ProjectFilesStyle.documentsList.height; Layout.maximumHeight: ProjectFilesStyle.documentsList.height; height: ProjectFilesStyle.documentsList.height; } PropertyChanges { target: imgArrow; source: "qrc:/qml/img/closedtriangleindicator_filesproject.png" } } ] @@ -132,21 +132,21 @@ ColumnLayout { Layout.preferredHeight: wrapperItem.hiddenHeightElement() Layout.maximumHeight: wrapperItem.hiddenHeightElement() height: wrapperItem.hiddenHeightElement() - color: isSelected ? Style.documentsList.highlightColor : Style.documentsList.background + color: isSelected ? ProjectFilesStyle.documentsList.highlightColor : ProjectFilesStyle.documentsList.background property bool isSelected property bool renameMode Text { id: nameText height: parent.height visible: !renameMode - color: rootItem.isSelected ? Style.documentsList.selectedColor : Style.documentsList.color + color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color text: name; font.family: fileNameFont.name - font.pointSize: Style.documentsList.fontSize + font.pointSize: ProjectFilesStyle.documentsList.fontSize anchors.verticalCenter: parent.verticalCenter verticalAlignment: Text.AlignVCenter anchors.left: parent.left - anchors.leftMargin: Style.general.leftMargin + 2 + anchors.leftMargin: ProjectFilesStyle.general.leftMargin + 2 width: parent.width Connections { @@ -171,7 +171,7 @@ ColumnLayout { visible: renameMode anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left - anchors.leftMargin: Style.general.leftMargin + anchors.leftMargin: ProjectFilesStyle.general.leftMargin MouseArea { id: textMouseArea anchors.fill: parent diff --git a/mix/qml/ItemDelegateDataDump.qml b/mix/qml/ItemDelegateDataDump.qml index a57a61b03..9aa6d00db 100644 --- a/mix/qml/ItemDelegateDataDump.qml +++ b/mix/qml/ItemDelegateDataDump.qml @@ -2,6 +2,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Layouts 1.0 import QtQuick.Controls.Styles 1.1 +import "." Rectangle { anchors.fill: parent @@ -27,7 +28,7 @@ Rectangle { font.bold: true color: "#4a4a4a" text: modelData[0] - font.pointSize: 8; + font.pointSize: DebuggerPaneStyle.general.dataDumpFontSize; } } @@ -46,7 +47,7 @@ Rectangle { anchors.leftMargin: 4 color: "#4a4a4a" text: modelData[1] - font.pointSize: 8 + font.pointSize: DebuggerPaneStyle.general.dataDumpFontSize } } } diff --git a/mix/qml/Style.qml b/mix/qml/ProjectFilesStyle.qml similarity index 72% rename from mix/qml/Style.qml rename to mix/qml/ProjectFilesStyle.qml index 348d8c4d1..cb8225e0d 100644 --- a/mix/qml/Style.qml +++ b/mix/qml/ProjectFilesStyle.qml @@ -1,10 +1,13 @@ pragma Singleton import QtQuick 2.0 -/* - * Project Files - */ QtObject { + + function absoluteSize(rel) + { + return systemPointSize + rel; + } + property QtObject general: QtObject { property int leftMargin: 45 } @@ -13,7 +16,7 @@ QtObject { property string color: "#808080" property string background: "#f0f0f0" property int height: 55 - property int pointSize: 18 + property int fontSize: absoluteSize(7);// 18 } property QtObject documentsList: QtObject { @@ -24,7 +27,7 @@ QtObject { property string highlightColor: "#4a90e2" property int height: 25 property int fileNameHeight: 30 - property int fontSize: 13 - property int sectionFontSize: 13 + property int fontSize: absoluteSize(2)// 13 + property int sectionFontSize: absoluteSize(2)// 13 } } diff --git a/mix/qml/ProjectList.qml b/mix/qml/ProjectList.qml index 138e86fe9..0297c2441 100644 --- a/mix/qml/ProjectList.qml +++ b/mix/qml/ProjectList.qml @@ -20,8 +20,8 @@ Item { Rectangle { - color: Style.title.background - height: Style.title.height + color: ProjectFilesStyle.title.background + height: ProjectFilesStyle.title.height Layout.fillWidth: true Image { id: projectIcon @@ -35,14 +35,14 @@ Item { Text { id: projectTitle - color: Style.title.color + color: ProjectFilesStyle.title.color text: projectModel.projectTitle anchors.verticalCenter: parent.verticalCenter visible: !projectModel.isEmpty; anchors.left: parent.left - anchors.leftMargin: Style.general.leftMargin + anchors.leftMargin: ProjectFilesStyle.general.leftMargin font.family: srcSansProLight.name - font.pointSize: Style.title.pointSize + font.pointSize: ProjectFilesStyle.title.fontSize font.weight: Font.Light } @@ -52,7 +52,7 @@ Item { anchors.right: parent.right anchors.rightMargin: 15 font.family: srcSansProLight.name - font.pointSize: Style.title.pointSize + font.pointSize: ProjectFilesStyle.title.fontSize anchors.verticalCenter: parent.verticalCenter font.weight: Font.Light } @@ -62,7 +62,7 @@ Item { { Layout.fillWidth: true height: 10 - color: Style.documentsList.background + color: ProjectFilesStyle.documentsList.background } @@ -71,7 +71,7 @@ Item { { Layout.fillWidth: true Layout.fillHeight: true - color: Style.documentsList.background + color: ProjectFilesStyle.documentsList.background ColumnLayout { @@ -137,7 +137,12 @@ Item { sectionModel.clear(); } + onProjectClosed: { + sectionModel.clear(); + } + onProjectLoaded: { + sectionModel.clear(); addDocToSubModel(); if (modelData === "Contracts") { diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 42bf91d9d..10dde5b41 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -34,11 +34,9 @@ Item { //interface function saveAll() { ProjectModelCode.saveAll(); } function createProject() { ProjectModelCode.createProject(); } - function browseProject() { ProjectModelCode.browseProject(); } function closeProject() { ProjectModelCode.closeProject(); } function saveProject() { ProjectModelCode.saveProject(); } function loadProject(path) { ProjectModelCode.loadProject(path); } - function addExistingFile() { ProjectModelCode.addExistingFile(); } function newHtmlFile() { ProjectModelCode.newHtmlFile(); } function newJsFile() { ProjectModelCode.newJsFile(); } function newCssFile() { ProjectModelCode.newCssFile(); } @@ -50,6 +48,7 @@ Item { function removeDocument(documentId) { ProjectModelCode.removeDocument(documentId); } function getDocument(documentId) { return ProjectModelCode.getDocument(documentId); } function getDocumentIndex(documentId) { return ProjectModelCode.getDocumentIndex(documentId); } + function doAddExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); } Connections { target: appContext @@ -96,27 +95,4 @@ Item { id: projectSettings property string lastProjectPath; } - - FileDialog { - id: openProjectFileDialog - visible: false - title: qsTr("Open a Project") - selectFolder: true - onAccepted: { - var path = openProjectFileDialog.fileUrl.toString(); - path += "/"; - loadProject(path); - } - } - - FileDialog { - id: addExistingFileDialog - visible: false - title: qsTr("Add a File") - selectFolder: false - onAccepted: { - var paths = addExistingFileDialog.fileUrls; - ProjectModelCode.doAddExistingFiles(paths); - } - } } diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index fa48c640e..4384b81a6 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -5,6 +5,7 @@ import QtQuick.Window 2.0 import org.ethereum.qml.QEther 1.0 import "js/QEtherHelper.js" as QEtherHelper import "js/TransactionHelper.js" as TransactionHelper +import "." Window { id: modalStateDialog @@ -158,7 +159,7 @@ Window { Layout.fillWidth: true Layout.fillHeight: true text: functionId - font.pointSize: 12 + font.pointSize: StateStyle.general.basicFontSize //12 verticalAlignment: Text.AlignBottom } ToolButton { diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml index 059b35bc2..f6f778cd9 100644 --- a/mix/qml/StateList.qml +++ b/mix/qml/StateList.qml @@ -4,6 +4,7 @@ import QtQuick.Controls 1.1 import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.0 +import "." Window { id: stateListContainer @@ -45,7 +46,7 @@ Window { Layout.fillWidth: true Layout.fillHeight: true text: styleData.value - font.pointSize: 12 + font.pointSize: StateStyle.general.basicFontSize verticalAlignment: Text.AlignBottom } ToolButton { diff --git a/mix/qml/StateStyle.qml b/mix/qml/StateStyle.qml new file mode 100644 index 000000000..c9740957c --- /dev/null +++ b/mix/qml/StateStyle.qml @@ -0,0 +1,14 @@ +pragma Singleton +import QtQuick 2.0 + +QtObject { + + function absoluteSize(rel) + { + return systemPointSize + rel; + } + + property QtObject general: QtObject { + property int basicFontSize: absoluteSize(1) + } +} diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 57ade7a3a..956d3f2ec 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -2,6 +2,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import "js/ErrorLocationFormater.js" as ErrorLocationFormater +import "." Rectangle { id: statusHeader @@ -59,7 +60,7 @@ Rectangle { spacing: 5 Text { - font.pointSize: 10 + font.pointSize: StatusPaneStyle.general.statusFontSize height: 9 font.family: "sans serif" objectName: "status" @@ -81,7 +82,7 @@ Rectangle { Text { visible: false - font.pointSize: 9 + font.pointSize: StatusPaneStyle.general.logLinkFontSize height: 9 text: qsTr("See Log.") font.family: "Monospace" diff --git a/mix/qml/StatusPaneStyle.qml b/mix/qml/StatusPaneStyle.qml new file mode 100644 index 000000000..e6a1c9910 --- /dev/null +++ b/mix/qml/StatusPaneStyle.qml @@ -0,0 +1,15 @@ +pragma Singleton +import QtQuick 2.0 + +QtObject { + + function absoluteSize(rel) + { + return systemPointSize + rel; + } + + property QtObject general: QtObject { + property int statusFontSize: absoluteSize(-1) + property int logLinkFontSize: absoluteSize(-2) + } +} diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index ac44dffa9..7c7a8ae4c 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -28,10 +28,6 @@ function createProject() { newProjectDialog.open(); } -function browseProject() { - openProjectFileDialog.open(); -} - function closeProject() { if (!isEmpty) { if (haveUnsavedChanges) @@ -77,10 +73,6 @@ function loadProject(path) { projectLoaded() } -function addExistingFile() { - addExistingFileDialog.open(); -} - function addFile(fileName) { var p = projectPath + fileName; var extension = fileName.substring(fileName.lastIndexOf("."), fileName.length); diff --git a/mix/qml/main.qml b/mix/qml/main.qml index ea5d6dd04..79430eb59 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -203,7 +203,19 @@ ApplicationWindow { text: qsTr("&Open Project") shortcut: "Ctrl+O" enabled: true; - onTriggered: projectModel.browseProject(); + onTriggered: openProjectFileDialog.open() + } + + FileDialog { + id: openProjectFileDialog + visible: false + title: qsTr("Open a Project") + selectFolder: true + onAccepted: { + var path = openProjectFileDialog.fileUrl.toString(); + path += "/"; + projectModel.loadProject(path); + } } Action { @@ -243,7 +255,18 @@ ApplicationWindow { text: qsTr("Add Existing File") shortcut: "Ctrl+Alt+A" enabled: !projectModel.isEmpty - onTriggered: projectModel.addExistingFile(); + onTriggered: addExistingFileDialog.open() + } + + FileDialog { + id: addExistingFileDialog + visible: false + title: qsTr("Add a File") + selectFolder: false + onAccepted: { + var paths = addExistingFileDialog.fileUrls; + projectModel.doAddExistingFiles(paths); + } } Action { diff --git a/mix/qml/qmldir b/mix/qml/qmldir index 819842274..9eb0effd0 100644 --- a/mix/qml/qmldir +++ b/mix/qml/qmldir @@ -1 +1,4 @@ -singleton Style 1.0 Style.qml +singleton ProjectFilesStyle 1.0 ProjectFilesStyle.qml +singleton DebuggerPaneStyle 1.0 DebuggerPaneStyle.qml +singleton StateStyle 1.0 StateStyle.qml +singleton StatusPaneStyle 1.0 StatusPaneStyle.qml diff --git a/mix/res.qrc b/mix/res.qrc index a33323870..cc37b1d32 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -2,7 +2,6 @@ qml/main.qml qml/AlertMessageDialog.qml - qml/BasicContent.qml qml/BasicMessage.qml qml/Debugger.qml qml/MainContent.qml @@ -62,7 +61,6 @@ qml/TransactionLog.qml res/mix_256x256x32.png qml/QVariableDeclaration.qml - qml/Style.qml qml/qmldir qml/FilesSection.qml qml/fonts/SourceSansPro-Black.ttf @@ -83,5 +81,10 @@ qml/img/closedtriangleindicator_filesproject.png qml/img/opentriangleindicator_filesproject.png qml/img/projecticon.png + qml/ProjectFilesStyle.qml + qml/DebuggerPaneStyle.qml + qml/CodeEditorStyle.qml + qml/StatusPaneStyle.qml + qml/StateStyle.qml diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 5bd1e8578..13a666fbf 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -56,6 +56,36 @@ BOOST_AUTO_TEST_CASE(empty_contract) BOOST_CHECK(callContractFunction("i_am_not_there()", bytes()).empty()); } +BOOST_AUTO_TEST_CASE(exp_operator) +{ + char const* sourceCode = R"( + contract test { + function f(uint a) returns(uint d) { return 2 ** a; } + })"; + compileAndRun(sourceCode); + testSolidityAgainstCppOnRange("f(uint256)", [](u256 const& a) -> u256 { return u256(1 << a.convert_to()); }, 0, 16); +} + +BOOST_AUTO_TEST_CASE(exp_operator_const) +{ + char const* sourceCode = R"( + contract test { + function f() returns(uint d) { return 2 ** 3; } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("f()", bytes()) == toBigEndian(u256(8))); +} + +BOOST_AUTO_TEST_CASE(exp_operator_const_signed) +{ + char const* sourceCode = R"( + contract test { + function f() returns(int d) { return (-2) ** 3; } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("f()", bytes()) == toBigEndian(u256(-8))); +} + BOOST_AUTO_TEST_CASE(recursive_calls) { char const* sourceCode = "contract test {\n" @@ -2201,6 +2231,29 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_string_literals) bytes({0x66, 0x6f, 0x6f})))); } +BOOST_AUTO_TEST_CASE(generic_call) +{ + char const* sourceCode = R"**( + contract receiver { + uint public received; + function receive(uint256 x) { received = x; } + } + contract sender { + function doSend(address rec) returns (uint d) + { + string4 signature = string4(string32(sha3("receive(uint256)"))); + rec.call.value(2)(signature, 23); + return receiver(rec).received(); + } + } + )**"; + compileAndRun(sourceCode, 0, "receiver"); + u160 const c_receiverAddress = m_contractAddress; + compileAndRun(sourceCode, 50, "sender"); + BOOST_REQUIRE(callContractFunction("doSend(address)", c_receiverAddress) == encodeArgs(23)); + BOOST_CHECK_EQUAL(m_state.balance(m_contractAddress), 50 - 2); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index f4be31f4b..d013f5c5e 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -974,6 +974,24 @@ BOOST_AUTO_TEST_CASE(overflow_caused_by_ether_units) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(exp_operator_negative_exponent) +{ + char const* sourceCode = R"( + contract test { + function f() returns(uint d) { return 2 ** -3; } + })"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(exp_operator_exponent_too_big) +{ + char const* sourceCode = R"( + contract test { + function f() returns(uint d) { return 2 ** 10000000000; } + })"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index 7af99567b..84f36170f 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -387,6 +387,17 @@ BOOST_AUTO_TEST_CASE(complex_expression) BOOST_CHECK_NO_THROW(parseText(text)); } +BOOST_AUTO_TEST_CASE(exp_expression) +{ + char const* text = R"( + contract test { + function fun(uint256 a) { + uint256 x = 3 ** a; + } + })"; + BOOST_CHECK_NO_THROW(parseText(text)); +} + BOOST_AUTO_TEST_CASE(while_loop) { char const* text = "contract test {\n" diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 8e4c493eb..8a00a5462 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -64,6 +64,9 @@ void connectClients(Client& c1, Client& c2) namespace test { +struct ValueTooLarge: virtual Exception {}; +bigint const c_max256plus1 = bigint(1) << 256; + ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller): m_TestObject(_o) { importEnv(_o["env"].get_obj()); diff --git a/test/TestHelper.h b/test/TestHelper.h index 2b93bccfb..ae6ea20cc 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -42,9 +42,6 @@ void connectClients(Client& c1, Client& c2); namespace test { -struct ValueTooLarge: virtual Exception {}; -bigint const c_max256plus1 = bigint(1) << 256; - class ImportTest { public: