diff --git a/AST.cpp b/AST.cpp index 761427db4..a18785ae1 100644 --- a/AST.cpp +++ b/AST.cpp @@ -77,6 +77,9 @@ void ContractDefinition::checkTypeRequirements() for (ASTPointer const& function: getDefinedFunctions()) function->checkTypeRequirements(); + for (ASTPointer const& variable: m_stateVariables) + variable->checkTypeRequirements(); + // check for hash collisions in function signatures set> hashes; for (auto const& it: getInterfaceFunctionList()) @@ -294,6 +297,12 @@ bool VariableDeclaration::isLValue() const return !isExternalFunctionParameter(); } +void VariableDeclaration::checkTypeRequirements() +{ + if (m_value) + m_value->checkTypeRequirements(); +} + bool VariableDeclaration::isExternalFunctionParameter() const { auto const* function = dynamic_cast(getScope()); @@ -390,26 +399,26 @@ void Return::checkTypeRequirements() m_expression->expectType(*m_returnParameters->getParameters().front()->getType()); } -void VariableDefinition::checkTypeRequirements() +void VariableDeclarationStatement::checkTypeRequirements() { // Variables can be declared without type (with "var"), in which case the first assignment // sets the type. // Note that assignments before the first declaration are legal because of the special scoping // rules inherited from JavaScript. - if (m_value) + if (m_variable->getValue()) { if (m_variable->getType()) - m_value->expectType(*m_variable->getType()); + m_variable->getValue()->expectType(*m_variable->getType()); else { // no type declared and no previous assignment, infer the type - m_value->checkTypeRequirements(); - TypePointer type = m_value->getType(); + m_variable->getValue()->checkTypeRequirements(); + TypePointer type = m_variable->getValue()->getType(); if (type->getCategory() == Type::Category::IntegerConstant) { auto intType = dynamic_pointer_cast(type)->getIntegerType(); if (!intType) - BOOST_THROW_EXCEPTION(m_value->createTypeError("Invalid integer constant " + type->toString())); + BOOST_THROW_EXCEPTION(m_variable->getValue()->createTypeError("Invalid integer constant " + type->toString())); type = intType; } else if (type->getCategory() == Type::Category::Void) @@ -418,7 +427,6 @@ void VariableDefinition::checkTypeRequirements() } } } - void Assignment::checkTypeRequirements() { m_leftHandSide->checkTypeRequirements(); diff --git a/AST.h b/AST.h index 64dac594d..064457d3b 100644 --- a/AST.h +++ b/AST.h @@ -432,14 +432,17 @@ class VariableDeclaration: public Declaration { public: VariableDeclaration(Location const& _location, ASTPointer const& _type, - ASTPointer const& _name, Visibility _visibility, - bool _isStateVar = false, bool _isIndexed = false): - Declaration(_location, _name, _visibility), m_typeName(_type), - m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {} + ASTPointer const& _name, ASTPointer _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) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; TypeName const* getTypeName() const { return m_typeName.get(); } + ASTPointer const& getValue() const { return m_value; } /// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly /// declared and there is no assignment to the variable that fixes the type. @@ -447,6 +450,9 @@ public: void setType(std::shared_ptr const& _type) { m_type = _type; } virtual bool isLValue() const override; + + /// Calls checkTypeRequirments for all state variables. + void checkTypeRequirements(); bool isLocalVariable() const { return !!dynamic_cast(getScope()); } bool isExternalFunctionParameter() const; bool isStateVariable() const { return m_isStateVariable; } @@ -457,6 +463,7 @@ protected: private: ASTPointer m_typeName; ///< can be empty ("var") + ASTPointer 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). @@ -833,22 +840,20 @@ private: * also be "var") but the actual assignment can be missing. * Examples: var a = 2; uint256 a; */ -class VariableDefinition: public Statement +class VariableDeclarationStatement: public Statement { public: - VariableDefinition(Location const& _location, ASTPointer _variable, - ASTPointer _value): - Statement(_location), m_variable(_variable), m_value(_value) {} + VariableDeclarationStatement(Location const& _location, ASTPointer _variable): + Statement(_location), m_variable(_variable) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; VariableDeclaration const& getDeclaration() const { return *m_variable; } - Expression const* getExpression() const { return m_value.get(); } + Expression const* getExpression() const { return m_variable->getValue().get(); } private: ASTPointer m_variable; - ASTPointer m_value; ///< the assigned value, can be missing }; /** diff --git a/ASTForward.h b/ASTForward.h index 0b6817e45..3a151b63e 100644 --- a/ASTForward.h +++ b/ASTForward.h @@ -63,7 +63,7 @@ class ForStatement; class Continue; class Break; class Return; -class VariableDefinition; +class VariableDeclarationStatement; class ExpressionStatement; class Expression; class Assignment; diff --git a/ASTJsonConverter.cpp b/ASTJsonConverter.cpp index 04feafe2f..c30e4ca2b 100644 --- a/ASTJsonConverter.cpp +++ b/ASTJsonConverter.cpp @@ -198,7 +198,7 @@ bool ASTJsonConverter::visit(Return const&) return true; } -bool ASTJsonConverter::visit(VariableDefinition const&) +bool ASTJsonConverter::visit(VariableDeclarationStatement const&) { addJsonNode("VariableDefinition", {}, true); return true; @@ -394,7 +394,7 @@ void ASTJsonConverter::endVisit(Return const&) goUp(); } -void ASTJsonConverter::endVisit(VariableDefinition const&) +void ASTJsonConverter::endVisit(VariableDeclarationStatement const&) { goUp(); } diff --git a/ASTJsonConverter.h b/ASTJsonConverter.h index 466801e9c..30a92e66c 100644 --- a/ASTJsonConverter.h +++ b/ASTJsonConverter.h @@ -64,7 +64,7 @@ public: bool visit(Continue const& _node) override; bool visit(Break const& _node) override; bool visit(Return const& _node) override; - bool visit(VariableDefinition const& _node) override; + bool visit(VariableDeclarationStatement const& _node) override; bool visit(ExpressionStatement const& _node) override; bool visit(Expression const& _node) override; bool visit(Assignment const& _node) override; @@ -98,7 +98,7 @@ public: void endVisit(Continue const&) override; void endVisit(Break const&) override; void endVisit(Return const&) override; - void endVisit(VariableDefinition const&) override; + void endVisit(VariableDeclarationStatement const&) override; void endVisit(ExpressionStatement const&) override; void endVisit(Expression const&) override; void endVisit(Assignment const&) override; diff --git a/ASTPrinter.cpp b/ASTPrinter.cpp index d380b0029..209bb73e6 100644 --- a/ASTPrinter.cpp +++ b/ASTPrinter.cpp @@ -225,9 +225,9 @@ bool ASTPrinter::visit(Return const& _node) return goDeeper(); } -bool ASTPrinter::visit(VariableDefinition const& _node) +bool ASTPrinter::visit(VariableDeclarationStatement const& _node) { - writeLine("VariableDefinition"); + writeLine("VariableDeclarationStatement"); printSourcePart(_node); return goDeeper(); } @@ -469,7 +469,7 @@ void ASTPrinter::endVisit(Return const&) m_indentation--; } -void ASTPrinter::endVisit(VariableDefinition const&) +void ASTPrinter::endVisit(VariableDeclarationStatement const&) { m_indentation--; } diff --git a/ASTPrinter.h b/ASTPrinter.h index d9072aacc..7a0ef5a65 100644 --- a/ASTPrinter.h +++ b/ASTPrinter.h @@ -68,7 +68,7 @@ public: bool visit(Continue const& _node) override; bool visit(Break const& _node) override; bool visit(Return const& _node) override; - bool visit(VariableDefinition const& _node) override; + bool visit(VariableDeclarationStatement const& _node) override; bool visit(ExpressionStatement const& _node) override; bool visit(Expression const& _node) override; bool visit(Assignment const& _node) override; @@ -109,7 +109,7 @@ public: void endVisit(Continue const&) override; void endVisit(Break const&) override; void endVisit(Return const&) override; - void endVisit(VariableDefinition const&) override; + void endVisit(VariableDeclarationStatement const&) override; void endVisit(ExpressionStatement const&) override; void endVisit(Expression const&) override; void endVisit(Assignment const&) override; diff --git a/ASTVisitor.h b/ASTVisitor.h index a7fa6b1cf..2ecfbe4b1 100644 --- a/ASTVisitor.h +++ b/ASTVisitor.h @@ -69,7 +69,7 @@ public: virtual bool visit(Continue&) { return true; } virtual bool visit(Break&) { return true; } virtual bool visit(Return&) { return true; } - virtual bool visit(VariableDefinition&) { return true; } + virtual bool visit(VariableDeclarationStatement&) { return true; } virtual bool visit(ExpressionStatement&) { return true; } virtual bool visit(Expression&) { return true; } virtual bool visit(Assignment&) { return true; } @@ -112,7 +112,7 @@ public: virtual void endVisit(Continue&) { } virtual void endVisit(Break&) { } virtual void endVisit(Return&) { } - virtual void endVisit(VariableDefinition&) { } + virtual void endVisit(VariableDeclarationStatement&) { } virtual void endVisit(ExpressionStatement&) { } virtual void endVisit(Expression&) { } virtual void endVisit(Assignment&) { } @@ -159,7 +159,7 @@ public: virtual bool visit(Continue const&) { return true; } virtual bool visit(Break const&) { return true; } virtual bool visit(Return const&) { return true; } - virtual bool visit(VariableDefinition const&) { return true; } + virtual bool visit(VariableDeclarationStatement const&) { return true; } virtual bool visit(ExpressionStatement const&) { return true; } virtual bool visit(Expression const&) { return true; } virtual bool visit(Assignment const&) { return true; } @@ -202,7 +202,7 @@ public: virtual void endVisit(Continue const&) { } virtual void endVisit(Break const&) { } virtual void endVisit(Return const&) { } - virtual void endVisit(VariableDefinition const&) { } + virtual void endVisit(VariableDeclarationStatement const&) { } virtual void endVisit(ExpressionStatement const&) { } virtual void endVisit(Expression const&) { } virtual void endVisit(Assignment const&) { } diff --git a/AST_accept.h b/AST_accept.h index b71e103df..5bd6993db 100644 --- a/AST_accept.h +++ b/AST_accept.h @@ -196,16 +196,24 @@ void FunctionDefinition::accept(ASTConstVisitor& _visitor) const void VariableDeclaration::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) + { if (m_typeName) m_typeName->accept(_visitor); + if (m_value) + m_value->accept(_visitor); + } _visitor.endVisit(*this); } void VariableDeclaration::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) + { if (m_typeName) m_typeName->accept(_visitor); + if (m_value) + m_value->accept(_visitor); + } _visitor.endVisit(*this); } @@ -475,25 +483,17 @@ void ExpressionStatement::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } -void VariableDefinition::accept(ASTVisitor& _visitor) +void VariableDeclarationStatement::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) - { m_variable->accept(_visitor); - if (m_value) - m_value->accept(_visitor); - } _visitor.endVisit(*this); } -void VariableDefinition::accept(ASTConstVisitor& _visitor) const +void VariableDeclarationStatement::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) - { m_variable->accept(_visitor); - if (m_value) - m_value->accept(_visitor); - } _visitor.endVisit(*this); } diff --git a/Compiler.cpp b/Compiler.cpp index 14acc0113..23014da6c 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -73,7 +73,7 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp for (ASTPointer const& base: contract->getBaseContracts()) { ContractDefinition const* baseContract = dynamic_cast( - base->getName()->getReferencedDeclaration()); + base->getName()->getReferencedDeclaration()); solAssert(baseContract, ""); if (baseArguments.count(baseContract) == 0) baseArguments[baseContract] = &base->getArguments(); @@ -85,12 +85,14 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp { ContractDefinition const* base = bases[bases.size() - i]; solAssert(base, ""); + initializeStateVariables(*base); FunctionDefinition const* baseConstructor = base->getConstructor(); if (!baseConstructor) continue; solAssert(baseArguments[base], ""); appendBaseConstructorCall(*baseConstructor, *baseArguments[base]); } + initializeStateVariables(_contract); if (_contract.getConstructor()) appendConstructorCall(*_contract.getConstructor()); @@ -247,6 +249,13 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract) m_context.addStateVariable(*variable); } +void Compiler::initializeStateVariables(ContractDefinition const& _contract) +{ + for (ASTPointer const& variable: _contract.getStateVariables()) + if (variable->getValue()) + ExpressionCompiler::appendStateVariableInitialization(m_context, *variable); +} + bool Compiler::visit(VariableDeclaration const& _variableDeclaration) { solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration."); @@ -429,7 +438,7 @@ bool Compiler::visit(Return const& _return) return false; } -bool Compiler::visit(VariableDefinition const& _variableDefinition) +bool Compiler::visit(VariableDeclarationStatement const& _variableDefinition) { if (Expression const* expression = _variableDefinition.getExpression()) { diff --git a/Compiler.h b/Compiler.h index 1aeaee88f..0838512ee 100644 --- a/Compiler.h +++ b/Compiler.h @@ -59,6 +59,7 @@ private: void appendReturnValuePacker(TypePointers const& _typeParameters); void registerStateVariables(ContractDefinition const& _contract); + void initializeStateVariables(ContractDefinition const& _contract); virtual bool visit(VariableDeclaration const& _variableDeclaration) override; virtual bool visit(FunctionDefinition const& _function) override; @@ -68,7 +69,7 @@ private: virtual bool visit(Continue const& _continue) override; virtual bool visit(Break const& _break) override; virtual bool visit(Return const& _return) override; - virtual bool visit(VariableDefinition const& _variableDefinition) override; + virtual bool visit(VariableDeclarationStatement const& _variableDefinition) override; virtual bool visit(ExpressionStatement const& _expressionStatement) override; virtual bool visit(PlaceholderStatement const&) override; diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index a8bc53e0f..461dfef14 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -56,6 +56,23 @@ void ExpressionCompiler::appendStateVariableAccessor(CompilerContext& _context, compiler.appendStateVariableAccessor(_varDecl); } +void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize) +{ + compileExpression(_context, *(_varDecl.getValue()), _optimize); + if (_varDecl.getValue()->getType()) + appendTypeConversion(_context, *(_varDecl.getValue())->getType(), *(_varDecl.getValue())->getType()); + + ExpressionCompiler compiler(_context, _optimize); + compiler.appendStateVariableInitialization(_varDecl); +} + +void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) +{ + LValue var = LValue(m_context); + var.fromDeclaration(_varDecl, _varDecl.getValue()->getLocation()); + var.storeValue(*_varDecl.getType(), _varDecl.getLocation()); +} + bool ExpressionCompiler::visit(Assignment const& _assignment) { _assignment.getRightHandSide().accept(*this); @@ -77,7 +94,6 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) } m_currentLValue.storeValue(*_assignment.getRightHandSide().getType(), _assignment.getLocation()); m_currentLValue.reset(); - return false; } @@ -572,7 +588,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag(); else if (dynamic_cast(declaration)) { - m_currentLValue.fromIdentifier(_identifier, *declaration); + m_currentLValue.fromDeclaration(*declaration, _identifier.getLocation()); m_currentLValue.retrieveValueIfLValueNotRequested(_identifier); } else if (dynamic_cast(declaration)) @@ -1002,12 +1018,12 @@ ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType m_size = unsigned(m_dataType->getSizeOnStack()); } -void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration) +void ExpressionCompiler::LValue::fromDeclaration(Declaration const& _declaration, Location const& _location) { if (m_context->isLocalVariable(&_declaration)) { m_type = LValueType::Stack; - m_dataType = _identifier.getType(); + m_dataType = _declaration.getType(); m_size = m_dataType->getSizeOnStack(); m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration); } @@ -1015,12 +1031,13 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D { *m_context << m_context->getStorageLocationOfVariable(_declaration); m_type = LValueType::Storage; - m_dataType = _identifier.getType(); + m_dataType = _declaration.getType(); solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); - m_size = unsigned(m_dataType->getStorageSize()); } + m_size = unsigned(m_dataType->getStorageSize()); + } else - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation()) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) << errinfo_comment("Identifier type not supported or identifier not found.")); } @@ -1117,7 +1134,7 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co } else { - solAssert(_sourceType.getCategory() == m_dataType->getCategory(), ""); + solAssert(_sourceType.getCategory() == m_dataType->getCategory(), "Wrong type conversation for assignment."); if (m_dataType->getCategory() == Type::Category::ByteArray) { CompilerUtils(*m_context).copyByteArrayToStorage( diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index 471d81865..889c58b19 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -59,6 +59,9 @@ public: /// Appends code for a State Variable accessor function static void appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false); + /// Appends code for a State Variable Initialization function + static void appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false); + private: explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false): m_optimize(_optimize), m_context(_compilerContext), m_currentLValue(m_context) {} @@ -111,6 +114,9 @@ private: /// Appends code for a State Variable accessor function void appendStateVariableAccessor(VariableDeclaration const& _varDecl); + /// Appends code for a State Variable initialization + void appendStateVariableInitialization(VariableDeclaration const& _varDecl); + /** * Helper class to store and retrieve lvalues to and from various locations. * All types except STACK store a reference in a slot on the stack, STACK just @@ -126,8 +132,9 @@ private: std::shared_ptr const& _dataType, unsigned _baseStackOffset = 0); /// Set type according to the declaration and retrieve the reference. - /// @a _expression is the current expression - void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration); + /// @a _location is the current location + void fromDeclaration(Declaration const& _declaration, Location const& _location); + void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; } bool isValid() const { return m_type != LValueType::None; } diff --git a/NameAndTypeResolver.cpp b/NameAndTypeResolver.cpp index e19b0bf9e..15e1ac6f5 100644 --- a/NameAndTypeResolver.cpp +++ b/NameAndTypeResolver.cpp @@ -267,12 +267,12 @@ void DeclarationRegistrationHelper::endVisit(ModifierDefinition&) closeCurrentScope(); } -void DeclarationRegistrationHelper::endVisit(VariableDefinition& _variableDefinition) +void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _variableDeclarationStatement) { // Register the local variables with the function // This does not fit here perfectly, but it saves us another AST visit. - solAssert(m_currentFunction, "Variable definition without function."); - m_currentFunction->addLocalVariable(_variableDefinition.getDeclaration()); + solAssert(m_currentFunction, "Variable declaration without function."); + m_currentFunction->addLocalVariable(_variableDeclarationStatement.getDeclaration()); } bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) diff --git a/NameAndTypeResolver.h b/NameAndTypeResolver.h index d9ac98ce5..63b8ab637 100644 --- a/NameAndTypeResolver.h +++ b/NameAndTypeResolver.h @@ -105,7 +105,7 @@ private: void endVisit(FunctionDefinition& _function) override; bool visit(ModifierDefinition& _modifier) override; void endVisit(ModifierDefinition& _modifier) override; - void endVisit(VariableDefinition& _variableDefinition) override; + void endVisit(VariableDeclarationStatement& _variableDeclarationStatement) override; bool visit(VariableDeclaration& _declaration) override; bool visit(EventDefinition& _event) override; void endVisit(EventDefinition& _event) override; diff --git a/Parser.cpp b/Parser.cpp index 72334c6cc..9940fb8d9 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -148,6 +148,7 @@ ASTPointer Parser::parseContractDefinition() { VarDeclParserOptions options; options.isStateVariable = true; + options.allowInitialValue = true; stateVariables.push_back(parseVariableDeclaration(options)); expectToken(Token::Semicolon); } @@ -324,9 +325,19 @@ ASTPointer Parser::parseVariableDeclaration(VarDeclParserOp } else identifier = expectIdentifierToken(); - return nodeFactory.createNode(type, identifier, - visibility, _options.isStateVariable, - isIndexed); + ASTPointer value; + if (_options.allowInitialValue) + { + if (m_scanner->getCurrentToken() == Token::Assign) + { + m_scanner->next(); + value = parseExpression(); + nodeFactory.setEndPositionFromNode(value); + } + } + return nodeFactory.createNode(type, identifier, value, + visibility, _options.isStateVariable, + isIndexed); } ASTPointer Parser::parseModifierDefinition() @@ -519,7 +530,7 @@ ASTPointer Parser::parseStatement() } // fall-through default: - statement = parseVarDefOrExprStmt(); + statement = parseVarDeclOrExprStmt(); } expectToken(Token::Semicolon); return statement; @@ -568,7 +579,7 @@ ASTPointer Parser::parseForStatement() // LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RParen? if (m_scanner->getCurrentToken() != Token::Semicolon) - initExpression = parseVarDefOrExprStmt(); + initExpression = parseVarDeclOrExprStmt(); expectToken(Token::Semicolon); if (m_scanner->getCurrentToken() != Token::Semicolon) @@ -587,30 +598,22 @@ ASTPointer Parser::parseForStatement() body); } -ASTPointer Parser::parseVarDefOrExprStmt() +ASTPointer Parser::parseVarDeclOrExprStmt() { - if (peekVariableDefinition()) - return parseVariableDefinition(); + if (peekVariableDeclarationStatement()) + return parseVariableDeclarationStatement(); else return parseExpressionStatement(); } -ASTPointer Parser::parseVariableDefinition() +ASTPointer Parser::parseVariableDeclarationStatement() { ASTNodeFactory nodeFactory(*this); VarDeclParserOptions options; options.allowVar = true; + options.allowInitialValue = true; ASTPointer variable = parseVariableDeclaration(options); - ASTPointer value; - if (m_scanner->getCurrentToken() == Token::Assign) - { - m_scanner->next(); - value = parseExpression(); - nodeFactory.setEndPositionFromNode(value); - } - else - nodeFactory.setEndPositionFromNode(variable); - return nodeFactory.createNode(variable, value); + return nodeFactory.createNode(variable); } ASTPointer Parser::parseExpressionStatement() @@ -822,11 +825,11 @@ pair>, vector>> Parser::pars } -bool Parser::peekVariableDefinition() +bool Parser::peekVariableDeclarationStatement() { - // distinguish between variable definition (and potentially assignment) and expression statement + // distinguish between variable declaration (and potentially assignment) and expression statement // (which include assignments to other expressions and pre-declared variables) - // We have a variable definition if we get a keyword that specifies a type name, or + // We have a variable declaration if we get a keyword that specifies a type name, or // in the case of a user-defined type, we have two identifiers following each other. return (m_scanner->getCurrentToken() == Token::Mapping || m_scanner->getCurrentToken() == Token::Var || diff --git a/Parser.h b/Parser.h index 1bb4ea977..4034aec85 100644 --- a/Parser.h +++ b/Parser.h @@ -51,6 +51,7 @@ private: bool isStateVariable = false; bool allowIndexed = false; bool allowEmptyName = false; + bool allowInitialValue = false; }; ///@{ @@ -76,8 +77,8 @@ private: ASTPointer parseIfStatement(); ASTPointer parseWhileStatement(); ASTPointer parseForStatement(); - ASTPointer parseVarDefOrExprStmt(); - ASTPointer parseVariableDefinition(); + ASTPointer parseVarDeclOrExprStmt(); + ASTPointer parseVariableDeclarationStatement(); ASTPointer parseExpressionStatement(); ASTPointer parseExpression(); ASTPointer parseBinaryExpression(int _minPrecedence = 4); @@ -91,8 +92,8 @@ private: ///@{ ///@name Helper functions - /// Peeks ahead in the scanner to determine if a variable definition is going to follow - bool peekVariableDefinition(); + /// Peeks ahead in the scanner to determine if a variable declaration statement is going to follow + bool peekVariableDeclarationStatement(); /// If current token value is not _value, throw exception otherwise advance token. void expectToken(Token::Value _value); diff --git a/Types.cpp b/Types.cpp index a9c480176..55dedd921 100644 --- a/Types.cpp +++ b/Types.cpp @@ -653,7 +653,7 @@ MemberList const& StructType::getMembers() const // We need to lazy-initialize it because of recursive references. if (!m_members) { - vector> members; + MemberList::MemberMap members; for (ASTPointer const& variable: m_struct.getMembers()) members.push_back(make_pair(variable->getName(), variable->getType())); m_members.reset(new MemberList(members));