Browse Source

Merge pull request #2029 from chriseth/sol_strings

Re-introduce string type.
cl-refactor
chriseth 10 years ago
parent
commit
a50d9bf01f
  1. 2
      libsolidity/AST.cpp
  2. 3
      libsolidity/ExpressionCompiler.cpp
  3. 2
      libsolidity/Token.h
  4. 20
      libsolidity/Types.cpp
  5. 22
      libsolidity/Types.h
  6. 4
      mix/CodeModel.cpp
  7. 1
      mix/SolidityType.h
  8. 27
      test/libsolidity/SolidityABIJSON.cpp
  9. 33
      test/libsolidity/SolidityNameAndTypeResolution.cpp

2
libsolidity/AST.cpp

@ -890,6 +890,8 @@ void IndexAccess::checkTypeRequirements(TypePointers const*)
ArrayType const& type = dynamic_cast<ArrayType const&>(*m_base->getType()); ArrayType const& type = dynamic_cast<ArrayType const&>(*m_base->getType());
if (!m_index) if (!m_index)
BOOST_THROW_EXCEPTION(createTypeError("Index expression cannot be omitted.")); BOOST_THROW_EXCEPTION(createTypeError("Index expression cannot be omitted."));
if (type.isString())
BOOST_THROW_EXCEPTION(createTypeError("Index access for string is not possible."));
m_index->expectType(IntegerType(256)); m_index->expectType(IntegerType(256));
if (type.isByteArray()) if (type.isByteArray())
m_type = make_shared<FixedBytesType>(1); m_type = make_shared<FixedBytesType>(1);

3
libsolidity/ExpressionCompiler.cpp

@ -824,7 +824,10 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
if (arrayType.getLocation() == ArrayType::Location::Storage) if (arrayType.getLocation() == ArrayType::Location::Storage)
{ {
if (arrayType.isByteArray()) if (arrayType.isByteArray())
{
solAssert(!arrayType.isString(), "Index access to string is not allowed.");
setLValue<StorageByteArrayElement>(_indexAccess); setLValue<StorageByteArrayElement>(_indexAccess);
}
else else
setLValueToStorageItem(_indexAccess); setLValueToStorageItem(_indexAccess);
} }

2
libsolidity/Token.h

@ -286,6 +286,7 @@ namespace solidity
K(Bytes32, "bytes32", 0) \ K(Bytes32, "bytes32", 0) \
K(Bytes, "bytes", 0) \ K(Bytes, "bytes", 0) \
K(Byte, "byte", 0) \ K(Byte, "byte", 0) \
K(String, "string", 0) \
K(Address, "address", 0) \ K(Address, "address", 0) \
K(Bool, "bool", 0) \ K(Bool, "bool", 0) \
K(Real, "real", 0) \ K(Real, "real", 0) \
@ -312,7 +313,6 @@ namespace solidity
K(Match, "match", 0) \ K(Match, "match", 0) \
K(Of, "of", 0) \ K(Of, "of", 0) \
K(Relocatable, "relocatable", 0) \ K(Relocatable, "relocatable", 0) \
T(String, "string", 0) \
K(Switch, "switch", 0) \ K(Switch, "switch", 0) \
K(Throw, "throw", 0) \ K(Throw, "throw", 0) \
K(Try, "try", 0) \ K(Try, "try", 0) \

20
libsolidity/Types.cpp

@ -145,6 +145,8 @@ TypePointer Type::fromElementaryTypeName(Token::Value _typeToken)
return make_shared<BoolType>(); return make_shared<BoolType>();
else if (_typeToken == Token::Bytes) else if (_typeToken == Token::Bytes)
return make_shared<ArrayType>(ArrayType::Location::Storage); return make_shared<ArrayType>(ArrayType::Location::Storage);
else if (_typeToken == Token::String)
return make_shared<ArrayType>(ArrayType::Location::Storage, true);
else else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " +
std::string(Token::toString(_typeToken)) + " to type.")); std::string(Token::toString(_typeToken)) + " to type."));
@ -663,7 +665,7 @@ bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
// let us not allow assignment to memory arrays for now // let us not allow assignment to memory arrays for now
if (convertTo.getLocation() != Location::Storage) if (convertTo.getLocation() != Location::Storage)
return false; return false;
if (convertTo.isByteArray() != isByteArray()) if (convertTo.isByteArray() != isByteArray() || convertTo.isString() != isString())
return false; return false;
if (!getBaseType()->isImplicitlyConvertibleTo(*convertTo.getBaseType())) if (!getBaseType()->isImplicitlyConvertibleTo(*convertTo.getBaseType()))
return false; return false;
@ -684,8 +686,12 @@ bool ArrayType::operator==(Type const& _other) const
if (_other.getCategory() != getCategory()) if (_other.getCategory() != getCategory())
return false; return false;
ArrayType const& other = dynamic_cast<ArrayType const&>(_other); ArrayType const& other = dynamic_cast<ArrayType const&>(_other);
if (other.m_location != m_location || other.isByteArray() != isByteArray() || if (
other.isDynamicallySized() != isDynamicallySized()) other.m_location != m_location ||
other.isByteArray() != isByteArray() ||
other.isString() != isString() ||
other.isDynamicallySized() != isDynamicallySized()
)
return false; return false;
return isDynamicallySized() || getLength() == other.getLength(); return isDynamicallySized() || getLength() == other.getLength();
} }
@ -736,7 +742,9 @@ unsigned ArrayType::getSizeOnStack() const
string ArrayType::toString() const string ArrayType::toString() const
{ {
if (isByteArray()) if (isString())
return "string";
else if (isByteArray())
return "bytes"; return "bytes";
string ret = getBaseType()->toString() + "["; string ret = getBaseType()->toString() + "[";
if (!isDynamicallySized()) if (!isDynamicallySized())
@ -746,7 +754,7 @@ string ArrayType::toString() const
TypePointer ArrayType::externalType() const TypePointer ArrayType::externalType() const
{ {
if (m_isByteArray) if (m_arrayKind != ArrayKind::Ordinary)
return shared_from_this(); return shared_from_this();
if (!m_baseType->externalType()) if (!m_baseType->externalType())
return TypePointer(); return TypePointer();
@ -762,7 +770,7 @@ TypePointer ArrayType::externalType() const
shared_ptr<ArrayType> ArrayType::copyForLocation(ArrayType::Location _location) const shared_ptr<ArrayType> ArrayType::copyForLocation(ArrayType::Location _location) const
{ {
auto copy = make_shared<ArrayType>(_location); auto copy = make_shared<ArrayType>(_location);
copy->m_isByteArray = m_isByteArray; copy->m_arrayKind = m_arrayKind;
if (m_baseType->getCategory() == Type::Category::Array) if (m_baseType->getCategory() == Type::Category::Array)
copy->m_baseType = dynamic_cast<ArrayType const&>(*m_baseType).copyForLocation(_location); copy->m_baseType = dynamic_cast<ArrayType const&>(*m_baseType).copyForLocation(_location);
else else

22
libsolidity/Types.h

@ -367,10 +367,10 @@ public:
virtual Category getCategory() const override { return Category::Array; } virtual Category getCategory() const override { return Category::Array; }
/// Constructor for a byte array ("bytes") /// Constructor for a byte array ("bytes") and string.
explicit ArrayType(Location _location): explicit ArrayType(Location _location, bool _isString = false):
m_location(_location), m_location(_location),
m_isByteArray(true), m_arrayKind(_isString ? ArrayKind::String : ArrayKind::Bytes),
m_baseType(std::make_shared<FixedBytesType>(1)) m_baseType(std::make_shared<FixedBytesType>(1))
{} {}
/// Constructor for a dynamically sized array type ("type[]") /// Constructor for a dynamically sized array type ("type[]")
@ -394,11 +394,17 @@ public:
virtual u256 getStorageSize() const override; virtual u256 getStorageSize() const override;
virtual unsigned getSizeOnStack() const override; virtual unsigned getSizeOnStack() const override;
virtual std::string toString() const override; virtual std::string toString() const override;
virtual MemberList const& getMembers() const override { return s_arrayTypeMemberList; } virtual MemberList const& getMembers() const override
{
return isString() ? EmptyMemberList : s_arrayTypeMemberList;
}
virtual TypePointer externalType() const override; virtual TypePointer externalType() const override;
Location getLocation() const { return m_location; } Location getLocation() const { return m_location; }
bool isByteArray() const { return m_isByteArray; } /// @returns true if this is a byte array or a string
bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; }
/// @returns true if this is a string
bool isString() const { return m_arrayKind == ArrayKind::String; }
TypePointer const& getBaseType() const { solAssert(!!m_baseType, ""); return m_baseType;} TypePointer const& getBaseType() const { solAssert(!!m_baseType, ""); return m_baseType;}
u256 const& getLength() const { return m_length; } u256 const& getLength() const { return m_length; }
@ -407,8 +413,12 @@ public:
std::shared_ptr<ArrayType> copyForLocation(Location _location) const; std::shared_ptr<ArrayType> copyForLocation(Location _location) const;
private: private:
/// String is interpreted as a subtype of Bytes.
enum class ArrayKind { Ordinary, Bytes, String };
Location m_location; Location m_location;
bool m_isByteArray = false; ///< Byte arrays ("bytes") have different semantics from ordinary arrays. ///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays.
ArrayKind m_arrayKind = ArrayKind::Ordinary;
TypePointer m_baseType; TypePointer m_baseType;
bool m_hasDynamicLength = true; bool m_hasDynamicLength = true;
u256 m_length; u256 m_length;

4
mix/CodeModel.cpp

@ -523,7 +523,9 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type)
case Type::Category::Array: case Type::Category::Array:
{ {
ArrayType const* array = dynamic_cast<ArrayType const*>(_type); ArrayType const* array = dynamic_cast<ArrayType const*>(_type);
if (array->isByteArray()) if (array->isString())
r.type = SolidityType::Type::String;
else if (array->isByteArray())
r.type = SolidityType::Type::Bytes; r.type = SolidityType::Type::Bytes;
else else
{ {

1
mix/SolidityType.h

@ -45,6 +45,7 @@ struct SolidityType
Bool, Bool,
Address, Address,
Bytes, Bytes,
String,
Enum, Enum,
Struct Struct
}; };

27
test/libsolidity/SolidityABIJSON.cpp

@ -568,6 +568,33 @@ BOOST_AUTO_TEST_CASE(return_param_in_abi)
checkInterface(sourceCode, interface); checkInterface(sourceCode, interface);
} }
BOOST_AUTO_TEST_CASE(strings_and_arrays)
{
// bug #1801
char const* sourceCode = R"(
contract test {
function f(string a, bytes b, uint[] c) external {}
}
)";
char const* interface = R"(
[
{
"constant" : false,
"name": "f",
"inputs": [
{ "name": "a", "type": "string" },
{ "name": "b", "type": "bytes" },
{ "name": "c", "type": "uint256[]" }
],
"outputs": [],
"type" : "function"
}
]
)";
checkInterface(sourceCode, interface);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

33
test/libsolidity/SolidityNameAndTypeResolution.cpp

@ -1783,6 +1783,39 @@ BOOST_AUTO_TEST_CASE(uninitialized_var)
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
} }
BOOST_AUTO_TEST_CASE(string)
{
char const* sourceCode = R"(
contract C {
string s;
function f(string x) external { s = x; }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode));
}
BOOST_AUTO_TEST_CASE(string_index)
{
char const* sourceCode = R"(
contract C {
string s;
function f() { var a = s[2]; }
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(string_length)
{
char const* sourceCode = R"(
contract C {
string s;
function f() { var a = s.length; }
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

Loading…
Cancel
Save