mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #382 from chriseth/bytesIndex
Index access for bytesXX.
This commit is contained in:
commit
c6c3c78327
@ -110,6 +110,11 @@ Operators:
|
||||
|
||||
* Comparisons: `<=`, `<`, `==`, `!=`, `>=`, `>` (evaluate to `bool`)
|
||||
* Bit operators: `&`, `|`, `^` (bitwise exclusive or), `~` (bitwise negation)
|
||||
* Index access: If `x` is of type `bytesI`, then `x[k]` for `0 <= k < I` returns the `k` th byte (read-only).
|
||||
|
||||
Members:
|
||||
|
||||
* `.length` yields the fixed length of the byte array (read-only).
|
||||
|
||||
Dynamically-sized byte array
|
||||
----------------------------
|
||||
|
@ -1253,6 +1253,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
arrayType.isDynamicallySized()
|
||||
);
|
||||
}
|
||||
else if (exprType->category() == Type::Category::FixedBytes)
|
||||
annotation.isLValue = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -1317,6 +1319,22 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::Category::FixedBytes:
|
||||
{
|
||||
FixedBytesType const& bytesType = dynamic_cast<FixedBytesType const&>(*baseType);
|
||||
if (!index)
|
||||
typeError(_access.location(), "Index expression cannot be omitted.");
|
||||
else
|
||||
{
|
||||
expectType(*index, IntegerType(256));
|
||||
if (auto integerType = dynamic_cast<IntegerConstantType const*>(type(*index).get()))
|
||||
if (bytesType.numBytes() <= integerType->literalValue(nullptr))
|
||||
typeError(_access.location(), "Out of bounds array access.");
|
||||
}
|
||||
resultType = make_shared<FixedBytesType>(1);
|
||||
isLValue = false; // @todo this heavily depends on how it is embedded
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fatalTypeError(
|
||||
_access.baseExpression().location(),
|
||||
|
@ -638,6 +638,11 @@ TypePointer FixedBytesType::binaryOperatorResult(Token::Value _operator, TypePoi
|
||||
return TypePointer();
|
||||
}
|
||||
|
||||
MemberList::MemberMap FixedBytesType::nativeMembers(const ContractDefinition*) const
|
||||
{
|
||||
return MemberList::MemberMap{MemberList::Member{"length", make_shared<IntegerType>(8)}};
|
||||
}
|
||||
|
||||
bool FixedBytesType::operator==(Type const& _other) const
|
||||
{
|
||||
if (_other.category() != category())
|
||||
|
@ -399,6 +399,7 @@ public:
|
||||
virtual bool isValueType() const override { return true; }
|
||||
|
||||
virtual std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
|
||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||
virtual TypePointer encodingType() const override { return shared_from_this(); }
|
||||
virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
|
||||
|
||||
|
@ -1004,6 +1004,16 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
||||
solAssert(false, "Illegal array member.");
|
||||
break;
|
||||
}
|
||||
case Type::Category::FixedBytes:
|
||||
{
|
||||
auto const& type = dynamic_cast<FixedBytesType const&>(*_memberAccess.expression().annotation().type);
|
||||
utils().popStackElement(type);
|
||||
if (member == "length")
|
||||
m_context << u256(type.numBytes());
|
||||
else
|
||||
solAssert(false, "Illegal fixed bytes member.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to unknown type."));
|
||||
}
|
||||
@ -1085,6 +1095,22 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (baseType.category() == Type::Category::FixedBytes)
|
||||
{
|
||||
FixedBytesType const& fixedBytesType = dynamic_cast<FixedBytesType const&>(baseType);
|
||||
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
|
||||
|
||||
_indexAccess.indexExpression()->accept(*this);
|
||||
// stack layout: <value> <index>
|
||||
// check out-of-bounds access
|
||||
m_context << u256(fixedBytesType.numBytes());
|
||||
m_context << eth::Instruction::DUP2 << eth::Instruction::LT << eth::Instruction::ISZERO;
|
||||
// out-of-bounds access throws exception
|
||||
m_context.appendConditionalJumpTo(m_context.errorTag());
|
||||
|
||||
m_context << eth::Instruction::BYTE;
|
||||
m_context << (u256(1) << (256 - 8)) << eth::Instruction::MUL;
|
||||
}
|
||||
else if (baseType.category() == Type::Category::TypeType)
|
||||
{
|
||||
solAssert(baseType.sizeOnStack() == 0, "");
|
||||
|
@ -6394,6 +6394,42 @@ BOOST_AUTO_TEST_CASE(inline_long_string_return)
|
||||
compileAndRun(sourceCode, 0, "C");
|
||||
BOOST_CHECK(callContractFunction("f()") == encodeDyn(strLong));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fixed_bytes_index_access)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
bytes16[] public data;
|
||||
function f(bytes32 x) returns (byte) {
|
||||
return x[2];
|
||||
}
|
||||
function g(bytes32 x) returns (uint) {
|
||||
data = [x[0], x[1], x[2]];
|
||||
data[0] = "12345";
|
||||
return uint(data[0][4]);
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "C");
|
||||
BOOST_CHECK(callContractFunction("f(bytes32)", "789") == encodeArgs("9"));
|
||||
BOOST_CHECK(callContractFunction("g(bytes32)", "789") == encodeArgs(u256(int('5'))));
|
||||
BOOST_CHECK(callContractFunction("data(uint256)", u256(1)) == encodeArgs("8"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fixed_bytes_length_access)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
byte a;
|
||||
function f(bytes32 x) returns (uint, uint, uint) {
|
||||
return (x.length, bytes16(2).length, a.length + 7);
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "C");
|
||||
BOOST_CHECK(callContractFunction("f(bytes32)", "789") == encodeArgs(u256(32), u256(16), u256(8)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
@ -3136,6 +3136,19 @@ BOOST_AUTO_TEST_CASE(conditional_with_all_types)
|
||||
BOOST_CHECK(success(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(index_access_for_bytes)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
bytes20 x;
|
||||
function f(bytes16 b) {
|
||||
b[uint(x[2])];
|
||||
}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK(success(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user