diff options
-rw-r--r-- | AST.cpp | 22 | ||||
-rw-r--r-- | AST.h | 2 | ||||
-rw-r--r-- | AST_accept.h | 6 | ||||
-rw-r--r-- | ExpressionCompiler.cpp | 3 | ||||
-rw-r--r-- | Parser.cpp | 11 | ||||
-rw-r--r-- | grammar.txt | 5 |
6 files changed, 36 insertions, 13 deletions
@@ -614,6 +614,8 @@ void IndexAccess::checkTypeRequirements() case Type::Category::Array: { ArrayType const& type = dynamic_cast<ArrayType const&>(*m_base->getType()); + if (!m_index) + BOOST_THROW_EXCEPTION(createTypeError("Index expression cannot be omitted.")); m_index->expectType(IntegerType(256)); m_type = type.getBaseType(); m_isLValue = true; @@ -622,14 +624,32 @@ void IndexAccess::checkTypeRequirements() case Type::Category::Mapping: { MappingType const& type = dynamic_cast<MappingType const&>(*m_base->getType()); + if (!m_index) + BOOST_THROW_EXCEPTION(createTypeError("Index expression cannot be omitted.")); m_index->expectType(*type.getKeyType()); m_type = type.getValueType(); m_isLValue = true; break; } + case Type::Category::TypeType: + { + TypeType const& type = dynamic_cast<TypeType const&>(*m_base->getType()); + if (!m_index) + m_type = make_shared<TypeType>(make_shared<ArrayType>(ArrayType::Location::Memory, type.getActualType())); + else + { + m_index->checkTypeRequirements(); + auto length = dynamic_cast<IntegerConstantType const*>(m_index->getType().get()); + if (!length) + BOOST_THROW_EXCEPTION(m_index->createTypeError("Integer constant expected.")); + m_type = make_shared<TypeType>(make_shared<ArrayType>( + ArrayType::Location::Memory, type.getActualType(), length->literalValue(nullptr))); + } + break; + } default: BOOST_THROW_EXCEPTION(m_base->createTypeError( - "Indexed expression has to be a mapping or array (is " + m_base->getType()->toString() + ")")); + "Indexed expression has to be a type, mapping or array (is " + m_base->getType()->toString() + ")")); } } @@ -1102,7 +1102,7 @@ public: virtual void checkTypeRequirements() override; Expression const& getBaseExpression() const { return *m_base; } - Expression const& getIndexExpression() const { return *m_index; } + Expression const* getIndexExpression() const { return m_index.get(); } private: ASTPointer<Expression> m_base; diff --git a/AST_accept.h b/AST_accept.h index 61b8280d..81ede8fc 100644 --- a/AST_accept.h +++ b/AST_accept.h @@ -626,7 +626,8 @@ void IndexAccess::accept(ASTVisitor& _visitor) if (_visitor.visit(*this)) { m_base->accept(_visitor); - m_index->accept(_visitor); + if (m_index) + m_index->accept(_visitor); } _visitor.endVisit(*this); } @@ -636,7 +637,8 @@ void IndexAccess::accept(ASTConstVisitor& _visitor) const if (_visitor.visit(*this)) { m_base->accept(_visitor); - m_index->accept(_visitor); + if (m_index) + m_index->accept(_visitor); } _visitor.endVisit(*this); } diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index cdad4840..94f65b93 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -562,7 +562,8 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) solAssert(baseType.getCategory() == Type::Category::Mapping, ""); Type const& keyType = *dynamic_cast<MappingType const&>(baseType).getKeyType(); m_context << u256(0); - appendExpressionCopyToMemory(keyType, _indexAccess.getIndexExpression()); + solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); + appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression()); solAssert(baseType.getSizeOnStack() == 1, "Unexpected: Not exactly one stack slot taken by subscriptable expression."); m_context << eth::Instruction::SWAP1; @@ -645,14 +645,11 @@ ASTPointer<Statement> Parser::parseSimpleStatement() vector<pair<ASTPointer<Expression>, Location>> indices; solAssert(m_scanner->getCurrentToken() == Token::LBrack, ""); Location indexLocation = primary->getLocation(); - bool encounteredEmptyBrackets = false; do { expectToken(Token::LBrack); ASTPointer<Expression> index; - if (m_scanner->getCurrentToken() == Token::RBrack) - encounteredEmptyBrackets = true; - else + if (m_scanner->getCurrentToken() != Token::RBrack) index = parseExpression(); indexLocation.end = getEndPosition(); indices.push_back(make_pair(index, indexLocation)); @@ -660,7 +657,7 @@ ASTPointer<Statement> Parser::parseSimpleStatement() } while (m_scanner->getCurrentToken() == Token::LBrack); - if (m_scanner->getCurrentToken() == Token::Identifier || encounteredEmptyBrackets) + if (m_scanner->getCurrentToken() == Token::Identifier) return parseVariableDeclarationStatement(typeNameFromArrayIndexStructure(primary, indices)); else return parseExpressionStatement(expressionFromArrayIndexStructure(primary, indices)); @@ -768,7 +765,9 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression( case Token::LBrack: { m_scanner->next(); - ASTPointer<Expression> index = parseExpression(); + ASTPointer<Expression> index; + if (m_scanner->getCurrentToken() != Token::RBrack) + index = parseExpression(); nodeFactory.markEndPosition(); expectToken(Token::RBrack); expression = nodeFactory.createNode<IndexAccess>(expression, index); diff --git a/grammar.txt b/grammar.txt index a3b24687..6503516c 100644 --- a/grammar.txt +++ b/grammar.txt @@ -18,8 +18,9 @@ ParameterList = '(' ( VariableDeclaration (',' VariableDeclaration)* )? ')' // semantic restriction: mappings and structs (recursively) containing mappings // are not allowed in argument lists VariableDeclaration = TypeName Identifier -TypeName = ElementaryTypeName | Identifier | Mapping +TypeName = ElementaryTypeName | Identifier | Mapping | ArrayTypeName Mapping = 'mapping' '(' ElementaryTypeName '=>' TypeName ')' +ArrayTypeName = TypeName '[' (Expression)? ']' Block = '{' Statement* '}' Statement = IfStatement | WhileStatement | Block | @@ -42,5 +43,5 @@ Assignment = Expression (AssignmentOp Expression) FunctionCall = Expression '(' Expression ( ',' Expression )* ')' NewExpression = 'new' Identifier MemberAccess = Expression '.' Identifier -IndexAccess = Expression '[' Expresison ']' +IndexAccess = Expression '[' (Expresison)? ']' PrimaryExpression = Identifier | NumberLiteral | StringLiteral | ElementaryTypeName | '(' Expression ')' |