Browse Source

Merge pull request #1274 from LianaHus/sol_ConstantFields

constant variables
cl-refactor
chriseth 10 years ago
parent
commit
42f5ae4c8b
  1. 15
      libsolidity/AST.cpp
  2. 31
      libsolidity/AST.h
  3. 5
      libsolidity/Compiler.cpp
  4. 9
      libsolidity/ExpressionCompiler.cpp
  5. 10
      libsolidity/Parser.cpp
  6. 3
      libsolidity/Parser.h
  7. 2
      libsolidity/Types.h
  8. 23
      test/SolidityEndToEndTest.cpp
  9. 3229
      test/SolidityEndToEndTest.cpp.orig
  10. 42
      test/SolidityNameAndTypeResolution.cpp
  11. 9
      test/SolidityParser.cpp

15
libsolidity/AST.cpp

@ -189,7 +189,7 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::getIn
for (ContractDefinition const* contract: getLinearizedBaseContracts())
{
for (ASTPointer<FunctionDefinition> const& f: contract->getDefinedFunctions())
if (f->isPublic() && !f->isConstructor() && !f->getName().empty() && functionsSeen.count(f->getName()) == 0)
if (functionsSeen.count(f->getName()) == 0 && f->isPartOfExternalInterface())
{
functionsSeen.insert(f->getName());
FixedHash<4> hash(dev::sha3(f->getCanonicalSignature()));
@ -197,7 +197,7 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::getIn
}
for (ASTPointer<VariableDeclaration> const& v: contract->getStateVariables())
if (v->isPublic() && functionsSeen.count(v->getName()) == 0)
if (functionsSeen.count(v->getName()) == 0 && v->isPartOfExternalInterface())
{
FunctionType ftype(*v);
functionsSeen.insert(v->getName());
@ -322,8 +322,8 @@ string FunctionDefinition::getCanonicalSignature() const
bool VariableDeclaration::isLValue() const
{
// External function parameters are Read-Only
return !isExternalFunctionParameter();
// External function parameters and constant declared variables are Read-Only
return !isExternalFunctionParameter() && !m_isConstant;
}
void VariableDeclaration::checkTypeRequirements()
@ -332,6 +332,13 @@ void VariableDeclaration::checkTypeRequirements()
// sets the type.
// Note that assignments before the first declaration are legal because of the special scoping
// rules inherited from JavaScript.
if (m_isConstant)
{
if (!dynamic_cast<ContractDefinition const*>(getScope()))
BOOST_THROW_EXCEPTION(createTypeError("Illegal use of \"constant\" specifier."));
if ((m_type && !m_type->isValueType()) || !m_value)
BOOST_THROW_EXCEPTION(createTypeError("Unitialized \"constant\" variable."));
}
if (!m_value)
return;
if (m_type)

31
libsolidity/AST.h

@ -156,6 +156,7 @@ public:
/// contract types.
virtual TypePointer getType(ContractDefinition const* m_currentContract = nullptr) const = 0;
virtual bool isLValue() const { return false; }
virtual bool isPartOfExternalInterface() const { return false; };
protected:
virtual Visibility getDefaultVisibility() const { return Visibility::Public; }
@ -415,6 +416,7 @@ public:
getVisibility() >= Visibility::Internal;
}
virtual TypePointer getType(ContractDefinition const*) const override;
virtual bool isPartOfExternalInterface() const override { return isPublic() && !m_isConstructor && !getName().empty(); }
/// Checks that all parameters have allowed types and calls checkTypeRequirements on the body.
void checkTypeRequirements();
@ -440,13 +442,23 @@ private:
class VariableDeclaration: public Declaration
{
public:
VariableDeclaration(SourceLocation const& _location, ASTPointer<TypeName> const& _type,
ASTPointer<ASTString> const& _name, ASTPointer<Expression> _value,
Visibility _visibility,
bool _isStateVar = false, bool _isIndexed = false):
Declaration(_location, _name, _visibility),
m_typeName(_type), m_value(_value),
m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {}
VariableDeclaration(
SourceLocation const& _location,
ASTPointer<TypeName> const& _type,
ASTPointer<ASTString> const& _name,
ASTPointer<Expression> _value,
Visibility _visibility,
bool _isStateVar = false,
bool _isIndexed = false,
bool _isConstant = false
):
Declaration(_location, _name, _visibility),
m_typeName(_type),
m_value(_value),
m_isStateVariable(_isStateVar),
m_isIndexed(_isIndexed),
m_isConstant(_isConstant){}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
@ -459,21 +471,24 @@ public:
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
virtual bool isLValue() const override;
virtual bool isPartOfExternalInterface() const override { return isPublic() && !m_isConstant; }
void checkTypeRequirements();
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); }
bool isExternalFunctionParameter() const;
bool isStateVariable() const { return m_isStateVariable; }
bool isIndexed() const { return m_isIndexed; }
bool isConstant() const { return m_isConstant; }
protected:
Visibility getDefaultVisibility() const override { return Visibility::Internal; }
private:
ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
ASTPointer<Expression> m_value; ///< the assigned value, can be missing
ASTPointer<Expression> m_value; ///< the assigned value, can be missing
bool m_isStateVariable; ///< Whether or not this is a contract state variable
bool m_isIndexed; ///< Whether this is an indexed variable (used by events).
bool m_isConstant; ///< Whether the variable is a compile-time constant.
std::shared_ptr<Type const> m_type; ///< derived type, initially empty
};

5
libsolidity/Compiler.cpp

@ -276,13 +276,14 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract)
{
for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.getLinearizedBaseContracts()))
for (ASTPointer<VariableDeclaration> const& variable: contract->getStateVariables())
m_context.addStateVariable(*variable);
if (!variable->isConstant())
m_context.addStateVariable(*variable);
}
void Compiler::initializeStateVariables(ContractDefinition const& _contract)
{
for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables())
if (variable->getValue())
if (variable->getValue() && !variable->isConstant())
ExpressionCompiler(m_context, m_optimize).appendStateVariableInitialization(*variable);
}

9
libsolidity/ExpressionCompiler.cpp

@ -855,8 +855,13 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
}
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag();
else if (dynamic_cast<VariableDeclaration const*>(declaration))
setLValueFromDeclaration(*declaration, _identifier);
else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration))
{
if (!variable->isConstant())
setLValueFromDeclaration(*declaration, _identifier);
else
variable->getValue()->accept(*this);
}
else if (dynamic_cast<ContractDefinition const*>(declaration))
{
// no-op

10
libsolidity/Parser.cpp

@ -317,6 +317,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
nodeFactory.setEndPositionFromNode(type);
}
bool isIndexed = false;
bool isDeclaredConst = false;
ASTPointer<ASTString> identifier;
Token::Value token = m_scanner->getCurrentToken();
Declaration::Visibility visibility(Declaration::Visibility::Default);
@ -327,7 +328,13 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
isIndexed = true;
m_scanner->next();
}
if (token == Token::Const)
{
isDeclaredConst = true;
m_scanner->next();
}
nodeFactory.markEndPosition();
if (_options.allowEmptyName && m_scanner->getCurrentToken() != Token::Identifier)
{
identifier = make_shared<ASTString>("");
@ -348,7 +355,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
}
return nodeFactory.createNode<VariableDeclaration>(type, identifier, value,
visibility, _options.isStateVariable,
isIndexed);
isIndexed, isDeclaredConst);
}
ASTPointer<ModifierDefinition> Parser::parseModifierDefinition()
@ -913,6 +920,7 @@ Parser::LookAheadInfo Parser::peekStatementType() const
// In all other cases, we have an expression statement.
Token::Value token(m_scanner->getCurrentToken());
bool mightBeTypeName = (Token::isElementaryTypeName(token) || token == Token::Identifier);
if (token == Token::Mapping || token == Token::Var ||
(mightBeTypeName && m_scanner->peekNextToken() == Token::Identifier))
return LookAheadInfo::VariableDeclarationStatement;

3
libsolidity/Parser.h

@ -66,8 +66,7 @@ private:
ASTPointer<StructDefinition> parseStructDefinition();
ASTPointer<EnumDefinition> parseEnumDefinition();
ASTPointer<EnumValue> parseEnumValue();
ASTPointer<VariableDeclaration> parseVariableDeclaration(
VarDeclParserOptions const& _options = VarDeclParserOptions(),
ASTPointer<VariableDeclaration> parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions(),
ASTPointer<TypeName> const& _lookAheadArrayType = ASTPointer<TypeName>());
ASTPointer<ModifierDefinition> parseModifierDefinition();
ASTPointer<EventDefinition> parseEventDefinition();

2
libsolidity/Types.h

@ -516,7 +516,7 @@ private:
std::vector<std::string> m_parameterNames;
std::vector<std::string> m_returnParameterNames;
Location const m_location;
/// true iff the function takes an arbitrary number of arguments of arbitrary types
/// true if the function takes an arbitrary number of arguments of arbitrary types
bool const m_arbitraryParameters = false;
bool const m_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

23
test/SolidityEndToEndTest.cpp

@ -3196,6 +3196,29 @@ BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base_with_gap)
BOOST_CHECK(callContractFunction("m_i()") == encodeArgs(4));
}
BOOST_AUTO_TEST_CASE(simple_constant_variables_test)
{
char const* sourceCode = R"(
contract Foo {
function getX() returns (uint r) { return x; }
uint constant x = 56;
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("getX()") == encodeArgs(56));
}
BOOST_AUTO_TEST_CASE(constant_variables)
{
//for now constant specifier is valid only for uint bytesXX and enums
char const* sourceCode = R"(
contract Foo {
uint constant x = 56;
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
ActionChoices constant choices = ActionChoices.GoLeft;
bytes32 constant st = "abc\x00\xff__";
})";
compileAndRun(sourceCode);
}
BOOST_AUTO_TEST_SUITE_END()
}

3229
test/SolidityEndToEndTest.cpp.orig

File diff suppressed because it is too large

42
test/SolidityNameAndTypeResolution.cpp

@ -1404,6 +1404,48 @@ BOOST_AUTO_TEST_CASE(test_byte_is_alias_of_byte1)
ETH_TEST_REQUIRE_NO_THROW(parseTextAndResolveNames(text), "Type resolving failed");
}
BOOST_AUTO_TEST_CASE(assigning_value_to_const_variable)
{
char const* text = R"(
contract Foo {
function changeIt() { x = 9; }
uint constant x = 56;
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(complex_const_variable)
{
//for now constant specifier is valid only for uint bytesXX and enums
char const* text = R"(
contract Foo {
mapping(uint => bool) constant mapVar;
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(uninitialized_const_variable)
{
char const* text = R"(
contract Foo {
uint constant y;
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(local_const_variable)
{
char const* text = R"(
contract Foo {
function localConst() returns (uint ret)
{
uint constant local = 4;
return local;
}
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), ParserError);
}
BOOST_AUTO_TEST_SUITE_END()
}

9
test/SolidityParser.cpp

@ -822,6 +822,15 @@ BOOST_AUTO_TEST_CASE(multi_arrays)
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(constant_is_keyword)
{
char const* text = R"(
contract Foo {
uint constant = 4;
})";
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_SUITE_END()
}

Loading…
Cancel
Save