mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'ethereum/develop' into sol_optimizer
This commit is contained in:
commit
dc8fb45e1f
18
AST.cpp
18
AST.cpp
@ -337,9 +337,11 @@ void ExpressionStatement::checkTypeRequirements()
|
||||
void Expression::expectType(Type const& _expectedType)
|
||||
{
|
||||
checkTypeRequirements();
|
||||
if (!getType()->isImplicitlyConvertibleTo(_expectedType))
|
||||
BOOST_THROW_EXCEPTION(createTypeError("Type not implicitly convertible to expected type."));
|
||||
//@todo provide more information to the exception
|
||||
Type const& type = *getType();
|
||||
if (!type.isImplicitlyConvertibleTo(_expectedType))
|
||||
BOOST_THROW_EXCEPTION(createTypeError("Type " + type.toString() +
|
||||
" not implicitly convertible to expected type "
|
||||
+ _expectedType.toString() + "."));
|
||||
}
|
||||
|
||||
void UnaryOperation::checkTypeRequirements()
|
||||
@ -363,14 +365,18 @@ void BinaryOperation::checkTypeRequirements()
|
||||
else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType()))
|
||||
m_commonType = m_right->getType();
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation."));
|
||||
BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation: " +
|
||||
m_left->getType()->toString() + " vs. " +
|
||||
m_right->getType()->toString()));
|
||||
if (Token::isCompareOp(m_operator))
|
||||
m_type = make_shared<BoolType>();
|
||||
else
|
||||
{
|
||||
m_type = m_commonType;
|
||||
if (!m_commonType->acceptsBinaryOperator(m_operator))
|
||||
BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type."));
|
||||
BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_operator)) +
|
||||
" not compatible with type " +
|
||||
m_commonType->toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -479,6 +485,8 @@ void ElementaryTypeNameExpression::checkTypeRequirements()
|
||||
void Literal::checkTypeRequirements()
|
||||
{
|
||||
m_type = Type::forLiteral(*this);
|
||||
if (!m_type)
|
||||
BOOST_THROW_EXCEPTION(createTypeError("Literal value too large."));
|
||||
}
|
||||
|
||||
}
|
||||
|
3
AST.h
3
AST.h
@ -565,12 +565,15 @@ public:
|
||||
Expression& getLeftExpression() const { return *m_left; }
|
||||
Expression& getRightExpression() const { return *m_right; }
|
||||
Token::Value getOperator() const { return m_operator; }
|
||||
Type const& getCommonType() const { return *m_commonType; }
|
||||
|
||||
private:
|
||||
ASTPointer<Expression> m_left;
|
||||
Token::Value m_operator;
|
||||
ASTPointer<Expression> m_right;
|
||||
|
||||
/// The common type that is used for the operation, not necessarily the result type (e.g. for
|
||||
/// comparisons, this is always bool).
|
||||
std::shared_ptr<Type const> m_commonType;
|
||||
};
|
||||
|
||||
|
@ -272,7 +272,7 @@ bool Compiler::visit(Return& _return)
|
||||
{
|
||||
ExpressionCompiler::compileExpression(m_context, *expression);
|
||||
VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front();
|
||||
ExpressionCompiler::cleanHigherOrderBitsIfNeeded(*expression->getType(), *firstVariable.getType());
|
||||
ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType());
|
||||
int stackPosition = m_context.getStackPositionOfVariable(firstVariable);
|
||||
m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP;
|
||||
}
|
||||
@ -285,8 +285,9 @@ bool Compiler::visit(VariableDefinition& _variableDefinition)
|
||||
if (Expression* expression = _variableDefinition.getExpression())
|
||||
{
|
||||
ExpressionCompiler::compileExpression(m_context, *expression);
|
||||
ExpressionCompiler::cleanHigherOrderBitsIfNeeded(*expression->getType(),
|
||||
*_variableDefinition.getDeclaration().getType());
|
||||
ExpressionCompiler::appendTypeConversion(m_context,
|
||||
*expression->getType(),
|
||||
*_variableDefinition.getDeclaration().getType());
|
||||
int stackPosition = m_context.getStackPositionOfVariable(_variableDefinition.getDeclaration());
|
||||
m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP;
|
||||
}
|
||||
|
@ -37,6 +37,13 @@ void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression
|
||||
_expression.accept(compiler);
|
||||
}
|
||||
|
||||
void ExpressionCompiler::appendTypeConversion(CompilerContext& _context,
|
||||
Type const& _typeOnStack, Type const& _targetType)
|
||||
{
|
||||
ExpressionCompiler compiler(_context);
|
||||
compiler.appendTypeConversion(_typeOnStack, _targetType);
|
||||
}
|
||||
|
||||
bool ExpressionCompiler::visit(Assignment& _assignment)
|
||||
{
|
||||
m_currentLValue = nullptr;
|
||||
@ -44,7 +51,7 @@ bool ExpressionCompiler::visit(Assignment& _assignment)
|
||||
Expression& rightHandSide = _assignment.getRightHandSide();
|
||||
rightHandSide.accept(*this);
|
||||
Type const& resultType = *_assignment.getType();
|
||||
cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType);
|
||||
appendTypeConversion(*rightHandSide.getType(), resultType);
|
||||
_assignment.getLeftHandSide().accept(*this);
|
||||
|
||||
Token::Value op = _assignment.getAssignmentOperator();
|
||||
@ -113,7 +120,7 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation)
|
||||
{
|
||||
Expression& leftExpression = _binaryOperation.getLeftExpression();
|
||||
Expression& rightExpression = _binaryOperation.getRightExpression();
|
||||
Type const& resultType = *_binaryOperation.getType();
|
||||
Type const& commonType = _binaryOperation.getCommonType();
|
||||
Token::Value const op = _binaryOperation.getOperator();
|
||||
|
||||
if (op == Token::AND || op == Token::OR)
|
||||
@ -121,23 +128,21 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation)
|
||||
// special case: short-circuiting
|
||||
appendAndOrOperatorCode(_binaryOperation);
|
||||
}
|
||||
else if (Token::isCompareOp(op))
|
||||
{
|
||||
leftExpression.accept(*this);
|
||||
rightExpression.accept(*this);
|
||||
|
||||
// the types to compare have to be the same, but the resulting type is always bool
|
||||
if (asserts(*leftExpression.getType() == *rightExpression.getType()))
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError());
|
||||
appendCompareOperatorCode(op, *leftExpression.getType());
|
||||
}
|
||||
else
|
||||
{
|
||||
bool cleanupNeeded = false;
|
||||
if (commonType.getCategory() == Type::Category::INTEGER)
|
||||
if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD)
|
||||
cleanupNeeded = true;
|
||||
|
||||
leftExpression.accept(*this);
|
||||
cleanHigherOrderBitsIfNeeded(*leftExpression.getType(), resultType);
|
||||
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded);
|
||||
rightExpression.accept(*this);
|
||||
cleanHigherOrderBitsIfNeeded(*rightExpression.getType(), resultType);
|
||||
appendOrdinaryBinaryOperatorCode(op, resultType);
|
||||
appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded);
|
||||
if (Token::isCompareOp(op))
|
||||
appendCompareOperatorCode(op, commonType);
|
||||
else
|
||||
appendOrdinaryBinaryOperatorCode(op, commonType);
|
||||
}
|
||||
|
||||
// do not visit the child nodes, we already did that explicitly
|
||||
@ -153,7 +158,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError());
|
||||
Expression& firstArgument = *_functionCall.getArguments().front();
|
||||
firstArgument.accept(*this);
|
||||
cleanHigherOrderBitsIfNeeded(*firstArgument.getType(), *_functionCall.getType());
|
||||
appendTypeConversion(*firstArgument.getType(), *_functionCall.getType());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -170,7 +175,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
|
||||
for (unsigned i = 0; i < arguments.size(); ++i)
|
||||
{
|
||||
arguments[i]->accept(*this);
|
||||
cleanHigherOrderBitsIfNeeded(*arguments[i]->getType(),
|
||||
appendTypeConversion(*arguments[i]->getType(),
|
||||
*function.getParameters()[i]->getType());
|
||||
}
|
||||
|
||||
@ -233,28 +238,6 @@ void ExpressionCompiler::endVisit(Literal& _literal)
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType)
|
||||
{
|
||||
// If the type of one of the operands is extended, we need to remove all
|
||||
// higher-order bits that we might have ignored in previous operations.
|
||||
// @todo: store in the AST whether the operand might have "dirty" higher
|
||||
// order bits
|
||||
|
||||
if (_typeOnStack == _targetType)
|
||||
return;
|
||||
if (_typeOnStack.getCategory() == Type::Category::INTEGER &&
|
||||
_targetType.getCategory() == Type::Category::INTEGER)
|
||||
{
|
||||
//@todo
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we get here, there is either an implementation missing to clean higher oder bits
|
||||
// for non-integer types that are explicitly convertible or we got here in error.
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested."));
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation)
|
||||
{
|
||||
Token::Value const op = _binaryOperation.getOperator();
|
||||
@ -379,6 +362,32 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator)
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded)
|
||||
{
|
||||
// If the type of one of the operands is extended, we need to remove all
|
||||
// higher-order bits that we might have ignored in previous operations.
|
||||
// @todo: store in the AST whether the operand might have "dirty" higher
|
||||
// order bits
|
||||
|
||||
if (_typeOnStack == _targetType && !_cleanupNeeded)
|
||||
return;
|
||||
if (_typeOnStack.getCategory() == Type::Category::INTEGER)
|
||||
appendHighBitsCleanup(dynamic_cast<IntegerType const&>(_typeOnStack));
|
||||
else if (_typeOnStack != _targetType)
|
||||
// All other types should not be convertible to non-equal types.
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested."));
|
||||
}
|
||||
|
||||
void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack)
|
||||
{
|
||||
if (_typeOnStack.getNumBits() == 256)
|
||||
return;
|
||||
else if (_typeOnStack.isSigned())
|
||||
m_context << u256(_typeOnStack.getNumBits() / 8 - 1) << eth::Instruction::SIGNEXTEND;
|
||||
else
|
||||
m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND;
|
||||
}
|
||||
|
||||
void ExpressionCompiler::storeInLValue(Expression const& _expression)
|
||||
{
|
||||
moveToLValue(_expression);
|
||||
|
@ -26,6 +26,8 @@ namespace dev {
|
||||
namespace solidity {
|
||||
|
||||
class CompilerContext; // forward
|
||||
class Type; // forward
|
||||
class IntegerType; // forward
|
||||
|
||||
/// Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream
|
||||
/// of EVM instructions. It needs a compiler context that is the same for the whole compilation
|
||||
@ -37,7 +39,7 @@ public:
|
||||
static void compileExpression(CompilerContext& _context, Expression& _expression);
|
||||
|
||||
/// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type.
|
||||
static void cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType);
|
||||
static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType);
|
||||
|
||||
private:
|
||||
ExpressionCompiler(CompilerContext& _compilerContext): m_currentLValue(nullptr), m_context(_compilerContext) {}
|
||||
@ -62,6 +64,14 @@ private:
|
||||
void appendShiftOperatorCode(Token::Value _operator);
|
||||
/// @}
|
||||
|
||||
/// Appends an implicit or explicit type conversion. For now this comprises only erasing
|
||||
/// higher-order bits (@see appendHighBitCleanup) when widening integer types.
|
||||
/// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be
|
||||
/// necessary.
|
||||
void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false);
|
||||
//// Appends code that cleans higher-order bits for integer types.
|
||||
void appendHighBitsCleanup(IntegerType const& _typeOnStack);
|
||||
|
||||
/// Stores the value on top of the stack in the current lvalue and copies that value to the
|
||||
/// top of the stack again
|
||||
void storeInLValue(Expression const& _expression);
|
||||
|
106
Scanner.cpp
106
Scanner.cpp
@ -271,7 +271,7 @@ void Scanner::scanToken()
|
||||
token = Token::ADD;
|
||||
break;
|
||||
case '-':
|
||||
// - -- -=
|
||||
// - -- -= Number
|
||||
advance();
|
||||
if (m_char == '-')
|
||||
{
|
||||
@ -280,6 +280,8 @@ void Scanner::scanToken()
|
||||
}
|
||||
else if (m_char == '=')
|
||||
token = selectToken(Token::ASSIGN_SUB);
|
||||
else if (m_char == '.' || IsDecimalDigit(m_char))
|
||||
token = scanNumber('-');
|
||||
else
|
||||
token = Token::SUB;
|
||||
break;
|
||||
@ -331,7 +333,7 @@ void Scanner::scanToken()
|
||||
// . Number
|
||||
advance();
|
||||
if (IsDecimalDigit(m_char))
|
||||
token = scanNumber(true);
|
||||
token = scanNumber('.');
|
||||
else
|
||||
token = Token::PERIOD;
|
||||
break;
|
||||
@ -372,7 +374,7 @@ void Scanner::scanToken()
|
||||
if (IsIdentifierStart(m_char))
|
||||
token = scanIdentifierOrKeyword();
|
||||
else if (IsDecimalDigit(m_char))
|
||||
token = scanNumber(false);
|
||||
token = scanNumber();
|
||||
else if (skipWhitespace())
|
||||
token = Token::WHITESPACE;
|
||||
else if (isSourcePastEndOfInput())
|
||||
@ -461,14 +463,11 @@ void Scanner::scanDecimalDigits()
|
||||
}
|
||||
|
||||
|
||||
Token::Value Scanner::scanNumber(bool _periodSeen)
|
||||
Token::Value Scanner::scanNumber(char _charSeen)
|
||||
{
|
||||
// the first digit of the number or the fraction
|
||||
if (asserts(IsDecimalDigit(m_char)))
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Number does not start with decimal digit."));
|
||||
enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL;
|
||||
enum { DECIMAL, HEX, BINARY } kind = DECIMAL;
|
||||
LiteralScope literal(this);
|
||||
if (_periodSeen)
|
||||
if (_charSeen == '.')
|
||||
{
|
||||
// we have already seen a decimal point of the float
|
||||
addLiteralChar('.');
|
||||
@ -476,12 +475,13 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_charSeen == '-')
|
||||
addLiteralChar('-');
|
||||
// if the first character is '0' we must check for octals and hex
|
||||
if (m_char == '0')
|
||||
{
|
||||
addLiteralCharAndAdvance();
|
||||
// either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or
|
||||
// an octal number.
|
||||
// either 0, 0exxx, 0Exxx, 0.xxx or a hex number
|
||||
if (m_char == 'x' || m_char == 'X')
|
||||
{
|
||||
// hex number
|
||||
@ -556,17 +556,73 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
|
||||
KEYWORD("function", Token::FUNCTION) \
|
||||
KEYWORD_GROUP('h') \
|
||||
KEYWORD("hash", Token::HASH) \
|
||||
KEYWORD("hash8", Token::HASH8) \
|
||||
KEYWORD("hash16", Token::HASH16) \
|
||||
KEYWORD("hash24", Token::HASH24) \
|
||||
KEYWORD("hash32", Token::HASH32) \
|
||||
KEYWORD("hash40", Token::HASH40) \
|
||||
KEYWORD("hash48", Token::HASH48) \
|
||||
KEYWORD("hash56", Token::HASH56) \
|
||||
KEYWORD("hash64", Token::HASH64) \
|
||||
KEYWORD("hash72", Token::HASH72) \
|
||||
KEYWORD("hash80", Token::HASH80) \
|
||||
KEYWORD("hash88", Token::HASH88) \
|
||||
KEYWORD("hash96", Token::HASH96) \
|
||||
KEYWORD("hash104", Token::HASH104) \
|
||||
KEYWORD("hash112", Token::HASH112) \
|
||||
KEYWORD("hash120", Token::HASH120) \
|
||||
KEYWORD("hash128", Token::HASH128) \
|
||||
KEYWORD("hash136", Token::HASH136) \
|
||||
KEYWORD("hash144", Token::HASH144) \
|
||||
KEYWORD("hash152", Token::HASH152) \
|
||||
KEYWORD("hash160", Token::HASH160) \
|
||||
KEYWORD("hash168", Token::HASH168) \
|
||||
KEYWORD("hash178", Token::HASH176) \
|
||||
KEYWORD("hash184", Token::HASH184) \
|
||||
KEYWORD("hash192", Token::HASH192) \
|
||||
KEYWORD("hash200", Token::HASH200) \
|
||||
KEYWORD("hash208", Token::HASH208) \
|
||||
KEYWORD("hash216", Token::HASH216) \
|
||||
KEYWORD("hash224", Token::HASH224) \
|
||||
KEYWORD("hash232", Token::HASH232) \
|
||||
KEYWORD("hash240", Token::HASH240) \
|
||||
KEYWORD("hash248", Token::HASH248) \
|
||||
KEYWORD("hash256", Token::HASH256) \
|
||||
KEYWORD_GROUP('i') \
|
||||
KEYWORD("if", Token::IF) \
|
||||
KEYWORD("in", Token::IN) \
|
||||
KEYWORD("int", Token::INT) \
|
||||
KEYWORD("int8", Token::INT8) \
|
||||
KEYWORD("int16", Token::INT16) \
|
||||
KEYWORD("int24", Token::INT24) \
|
||||
KEYWORD("int32", Token::INT32) \
|
||||
KEYWORD("int40", Token::INT40) \
|
||||
KEYWORD("int48", Token::INT48) \
|
||||
KEYWORD("int56", Token::INT56) \
|
||||
KEYWORD("int64", Token::INT64) \
|
||||
KEYWORD("int72", Token::INT72) \
|
||||
KEYWORD("int80", Token::INT80) \
|
||||
KEYWORD("int88", Token::INT88) \
|
||||
KEYWORD("int96", Token::INT96) \
|
||||
KEYWORD("int104", Token::INT104) \
|
||||
KEYWORD("int112", Token::INT112) \
|
||||
KEYWORD("int120", Token::INT120) \
|
||||
KEYWORD("int128", Token::INT128) \
|
||||
KEYWORD("int136", Token::INT136) \
|
||||
KEYWORD("int144", Token::INT144) \
|
||||
KEYWORD("int152", Token::INT152) \
|
||||
KEYWORD("int160", Token::INT160) \
|
||||
KEYWORD("int168", Token::INT168) \
|
||||
KEYWORD("int178", Token::INT176) \
|
||||
KEYWORD("int184", Token::INT184) \
|
||||
KEYWORD("int192", Token::INT192) \
|
||||
KEYWORD("int200", Token::INT200) \
|
||||
KEYWORD("int208", Token::INT208) \
|
||||
KEYWORD("int216", Token::INT216) \
|
||||
KEYWORD("int224", Token::INT224) \
|
||||
KEYWORD("int232", Token::INT232) \
|
||||
KEYWORD("int240", Token::INT240) \
|
||||
KEYWORD("int248", Token::INT248) \
|
||||
KEYWORD("int256", Token::INT256) \
|
||||
KEYWORD_GROUP('l') \
|
||||
KEYWORD_GROUP('m') \
|
||||
@ -591,9 +647,37 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
|
||||
KEYWORD("true", Token::TRUE_LITERAL) \
|
||||
KEYWORD_GROUP('u') \
|
||||
KEYWORD("uint", Token::UINT) \
|
||||
KEYWORD("uint8", Token::UINT8) \
|
||||
KEYWORD("uint16", Token::UINT16) \
|
||||
KEYWORD("uint24", Token::UINT24) \
|
||||
KEYWORD("uint32", Token::UINT32) \
|
||||
KEYWORD("uint40", Token::UINT40) \
|
||||
KEYWORD("uint48", Token::UINT48) \
|
||||
KEYWORD("uint56", Token::UINT56) \
|
||||
KEYWORD("uint64", Token::UINT64) \
|
||||
KEYWORD("uint72", Token::UINT72) \
|
||||
KEYWORD("uint80", Token::UINT80) \
|
||||
KEYWORD("uint88", Token::UINT88) \
|
||||
KEYWORD("uint96", Token::UINT96) \
|
||||
KEYWORD("uint104", Token::UINT104) \
|
||||
KEYWORD("uint112", Token::UINT112) \
|
||||
KEYWORD("uint120", Token::UINT120) \
|
||||
KEYWORD("uint128", Token::UINT128) \
|
||||
KEYWORD("uint136", Token::UINT136) \
|
||||
KEYWORD("uint144", Token::UINT144) \
|
||||
KEYWORD("uint152", Token::UINT152) \
|
||||
KEYWORD("uint160", Token::UINT160) \
|
||||
KEYWORD("uint168", Token::UINT168) \
|
||||
KEYWORD("uint178", Token::UINT176) \
|
||||
KEYWORD("uint184", Token::UINT184) \
|
||||
KEYWORD("uint192", Token::UINT192) \
|
||||
KEYWORD("uint200", Token::UINT200) \
|
||||
KEYWORD("uint208", Token::UINT208) \
|
||||
KEYWORD("uint216", Token::UINT216) \
|
||||
KEYWORD("uint224", Token::UINT224) \
|
||||
KEYWORD("uint232", Token::UINT232) \
|
||||
KEYWORD("uint240", Token::UINT240) \
|
||||
KEYWORD("uint248", Token::UINT248) \
|
||||
KEYWORD("uint256", Token::UINT256) \
|
||||
KEYWORD("ureal", Token::UREAL) \
|
||||
KEYWORD_GROUP('v') \
|
||||
|
@ -180,7 +180,7 @@ private:
|
||||
Token::Value skipMultiLineComment();
|
||||
|
||||
void scanDecimalDigits();
|
||||
Token::Value scanNumber(bool _periodSeen);
|
||||
Token::Value scanNumber(char _charSeen = 0);
|
||||
Token::Value scanIdentifierOrKeyword();
|
||||
|
||||
Token::Value scanString();
|
||||
|
84
Token.h
84
Token.h
@ -169,19 +169,103 @@ namespace solidity
|
||||
* the implementation in Types.cpp has to be synced to this here
|
||||
* TODO more to be added */ \
|
||||
K(INT, "int", 0) \
|
||||
K(INT8, "int8", 0) \
|
||||
K(INT16, "int16", 0) \
|
||||
K(INT24, "int24", 0) \
|
||||
K(INT32, "int32", 0) \
|
||||
K(INT40, "int40", 0) \
|
||||
K(INT48, "int48", 0) \
|
||||
K(INT56, "int56", 0) \
|
||||
K(INT64, "int64", 0) \
|
||||
K(INT72, "int72", 0) \
|
||||
K(INT80, "int80", 0) \
|
||||
K(INT88, "int88", 0) \
|
||||
K(INT96, "int96", 0) \
|
||||
K(INT104, "int104", 0) \
|
||||
K(INT112, "int112", 0) \
|
||||
K(INT120, "int120", 0) \
|
||||
K(INT128, "int128", 0) \
|
||||
K(INT136, "int136", 0) \
|
||||
K(INT144, "int144", 0) \
|
||||
K(INT152, "int152", 0) \
|
||||
K(INT160, "int160", 0) \
|
||||
K(INT168, "int168", 0) \
|
||||
K(INT176, "int178", 0) \
|
||||
K(INT184, "int184", 0) \
|
||||
K(INT192, "int192", 0) \
|
||||
K(INT200, "int200", 0) \
|
||||
K(INT208, "int208", 0) \
|
||||
K(INT216, "int216", 0) \
|
||||
K(INT224, "int224", 0) \
|
||||
K(INT232, "int232", 0) \
|
||||
K(INT240, "int240", 0) \
|
||||
K(INT248, "int248", 0) \
|
||||
K(INT256, "int256", 0) \
|
||||
K(UINT, "uint", 0) \
|
||||
K(UINT8, "uint8", 0) \
|
||||
K(UINT16, "uint16", 0) \
|
||||
K(UINT24, "uint24", 0) \
|
||||
K(UINT32, "uint32", 0) \
|
||||
K(UINT40, "uint40", 0) \
|
||||
K(UINT48, "uint48", 0) \
|
||||
K(UINT56, "uint56", 0) \
|
||||
K(UINT64, "uint64", 0) \
|
||||
K(UINT72, "uint72", 0) \
|
||||
K(UINT80, "uint80", 0) \
|
||||
K(UINT88, "uint88", 0) \
|
||||
K(UINT96, "uint96", 0) \
|
||||
K(UINT104, "uint104", 0) \
|
||||
K(UINT112, "uint112", 0) \
|
||||
K(UINT120, "uint120", 0) \
|
||||
K(UINT128, "uint128", 0) \
|
||||
K(UINT136, "uint136", 0) \
|
||||
K(UINT144, "uint144", 0) \
|
||||
K(UINT152, "uint152", 0) \
|
||||
K(UINT160, "uint160", 0) \
|
||||
K(UINT168, "uint168", 0) \
|
||||
K(UINT176, "uint178", 0) \
|
||||
K(UINT184, "uint184", 0) \
|
||||
K(UINT192, "uint192", 0) \
|
||||
K(UINT200, "uint200", 0) \
|
||||
K(UINT208, "uint208", 0) \
|
||||
K(UINT216, "uint216", 0) \
|
||||
K(UINT224, "uint224", 0) \
|
||||
K(UINT232, "uint232", 0) \
|
||||
K(UINT240, "uint240", 0) \
|
||||
K(UINT248, "uint248", 0) \
|
||||
K(UINT256, "uint256", 0) \
|
||||
K(HASH, "hash", 0) \
|
||||
K(HASH8, "hash8", 0) \
|
||||
K(HASH16, "hash16", 0) \
|
||||
K(HASH24, "hash24", 0) \
|
||||
K(HASH32, "hash32", 0) \
|
||||
K(HASH40, "hash40", 0) \
|
||||
K(HASH48, "hash48", 0) \
|
||||
K(HASH56, "hash56", 0) \
|
||||
K(HASH64, "hash64", 0) \
|
||||
K(HASH72, "hash72", 0) \
|
||||
K(HASH80, "hash80", 0) \
|
||||
K(HASH88, "hash88", 0) \
|
||||
K(HASH96, "hash96", 0) \
|
||||
K(HASH104, "hash104", 0) \
|
||||
K(HASH112, "hash112", 0) \
|
||||
K(HASH120, "hash120", 0) \
|
||||
K(HASH128, "hash128", 0) \
|
||||
K(HASH136, "hash136", 0) \
|
||||
K(HASH144, "hash144", 0) \
|
||||
K(HASH152, "hash152", 0) \
|
||||
K(HASH160, "hash160", 0) \
|
||||
K(HASH168, "hash168", 0) \
|
||||
K(HASH176, "hash178", 0) \
|
||||
K(HASH184, "hash184", 0) \
|
||||
K(HASH192, "hash192", 0) \
|
||||
K(HASH200, "hash200", 0) \
|
||||
K(HASH208, "hash208", 0) \
|
||||
K(HASH216, "hash216", 0) \
|
||||
K(HASH224, "hash224", 0) \
|
||||
K(HASH232, "hash232", 0) \
|
||||
K(HASH240, "hash240", 0) \
|
||||
K(HASH248, "hash248", 0) \
|
||||
K(HASH256, "hash256", 0) \
|
||||
K(ADDRESS, "address", 0) \
|
||||
K(BOOL, "bool", 0) \
|
||||
|
63
Types.cpp
63
Types.cpp
@ -25,12 +25,14 @@
|
||||
#include <libsolidity/Types.h>
|
||||
#include <libsolidity/AST.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
|
||||
std::shared_ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken)
|
||||
shared_ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken)
|
||||
{
|
||||
if (asserts(Token::isElementaryTypeName(_typeToken)))
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError());
|
||||
@ -38,58 +40,63 @@ std::shared_ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken)
|
||||
if (Token::INT <= _typeToken && _typeToken <= Token::HASH256)
|
||||
{
|
||||
int offset = _typeToken - Token::INT;
|
||||
int bits = offset % 5;
|
||||
if (bits == 0)
|
||||
bits = 256;
|
||||
else
|
||||
bits = (1 << (bits - 1)) * 32;
|
||||
int modifier = offset / 5;
|
||||
return std::make_shared<IntegerType>(bits,
|
||||
modifier == 0 ? IntegerType::Modifier::SIGNED :
|
||||
modifier == 1 ? IntegerType::Modifier::UNSIGNED :
|
||||
IntegerType::Modifier::HASH);
|
||||
int bytes = offset % 33;
|
||||
if (bytes == 0)
|
||||
bytes = 32;
|
||||
int modifier = offset / 33;
|
||||
return make_shared<IntegerType>(bytes * 8,
|
||||
modifier == 0 ? IntegerType::Modifier::SIGNED :
|
||||
modifier == 1 ? IntegerType::Modifier::UNSIGNED :
|
||||
IntegerType::Modifier::HASH);
|
||||
}
|
||||
else if (_typeToken == Token::ADDRESS)
|
||||
return std::make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS);
|
||||
return make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS);
|
||||
else if (_typeToken == Token::BOOL)
|
||||
return std::make_shared<BoolType>();
|
||||
return make_shared<BoolType>();
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " +
|
||||
std::string(Token::toString(_typeToken)) + " to type."));
|
||||
return std::shared_ptr<Type>();
|
||||
return shared_ptr<Type>();
|
||||
}
|
||||
|
||||
std::shared_ptr<Type> Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName)
|
||||
shared_ptr<Type> Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName)
|
||||
{
|
||||
return std::make_shared<StructType>(*_typeName.getReferencedStruct());
|
||||
return make_shared<StructType>(*_typeName.getReferencedStruct());
|
||||
}
|
||||
|
||||
std::shared_ptr<Type> Type::fromMapping(Mapping const&)
|
||||
shared_ptr<Type> Type::fromMapping(Mapping const&)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Mapping types not yet implemented."));
|
||||
return std::shared_ptr<Type>();
|
||||
return shared_ptr<Type>();
|
||||
}
|
||||
|
||||
std::shared_ptr<Type> Type::forLiteral(Literal const& _literal)
|
||||
shared_ptr<Type> Type::forLiteral(Literal const& _literal)
|
||||
{
|
||||
switch (_literal.getToken())
|
||||
{
|
||||
case Token::TRUE_LITERAL:
|
||||
case Token::FALSE_LITERAL:
|
||||
return std::make_shared<BoolType>();
|
||||
return make_shared<BoolType>();
|
||||
case Token::NUMBER:
|
||||
return IntegerType::smallestTypeForLiteral(_literal.getValue());
|
||||
case Token::STRING_LITERAL:
|
||||
return std::shared_ptr<Type>(); // @todo
|
||||
return shared_ptr<Type>(); // @todo
|
||||
default:
|
||||
return std::shared_ptr<Type>();
|
||||
return shared_ptr<Type>();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<IntegerType> IntegerType::smallestTypeForLiteral(std::string const&)
|
||||
shared_ptr<IntegerType> IntegerType::smallestTypeForLiteral(string const& _literal)
|
||||
{
|
||||
//@todo
|
||||
return std::make_shared<IntegerType>(256, Modifier::UNSIGNED);
|
||||
bigint value(_literal);
|
||||
bool isSigned = value < 0 || (!_literal.empty() && _literal.front() == '-');
|
||||
if (isSigned)
|
||||
// convert to positive number of same bit requirements
|
||||
value = ((-value) - 1) << 1;
|
||||
unsigned bytes = max(bytesRequired(value), 1u);
|
||||
if (bytes > 32)
|
||||
return shared_ptr<IntegerType>();
|
||||
return make_shared<IntegerType>(bytes * 8, isSigned ? Modifier::SIGNED : Modifier::UNSIGNED);
|
||||
}
|
||||
|
||||
IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
|
||||
@ -155,19 +162,17 @@ bool IntegerType::operator==(Type const& _other) const
|
||||
return other.m_bits == m_bits && other.m_modifier == m_modifier;
|
||||
}
|
||||
|
||||
std::string IntegerType::toString() const
|
||||
string IntegerType::toString() const
|
||||
{
|
||||
if (isAddress())
|
||||
return "address";
|
||||
std::string prefix = isHash() ? "hash" : (isSigned() ? "int" : "uint");
|
||||
string prefix = isHash() ? "hash" : (isSigned() ? "int" : "uint");
|
||||
return prefix + dev::toString(m_bits);
|
||||
}
|
||||
|
||||
u256 IntegerType::literalValue(Literal const& _literal) const
|
||||
{
|
||||
bigint value(_literal.getValue());
|
||||
//@todo check that the number is not too large
|
||||
//@todo does this work for signed numbers?
|
||||
return u256(value);
|
||||
}
|
||||
|
||||
|
5
Types.h
5
Types.h
@ -56,7 +56,8 @@ public:
|
||||
static std::shared_ptr<Type> fromMapping(Mapping const& _typeName);
|
||||
/// @}
|
||||
|
||||
/// Auto-detect the proper type for a literal
|
||||
/// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does
|
||||
/// not fit any type.
|
||||
static std::shared_ptr<Type> forLiteral(Literal const& _literal);
|
||||
|
||||
virtual Category getCategory() const = 0;
|
||||
@ -95,6 +96,8 @@ public:
|
||||
};
|
||||
virtual Category getCategory() const override { return Category::INTEGER; }
|
||||
|
||||
/// @returns the smallest integer type for the given literal or an empty pointer
|
||||
/// if no type fits.
|
||||
static std::shared_ptr<IntegerType> smallestTypeForLiteral(std::string const& _literal);
|
||||
|
||||
explicit IntegerType(int _bits, Modifier _modifier = Modifier::UNSIGNED);
|
||||
|
Loading…
Reference in New Issue
Block a user