From b685735b3ac267fbcef97cf89b68adba65cf9ff0 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 1 Dec 2014 13:46:04 +0100 Subject: Cleanup of scanner. Removed redundancy of keyword definitions and removed some unused token predicates. --- Scanner.cpp | 197 ++++-------------------------------------------------------- Token.h | 14 ----- 2 files changed, 12 insertions(+), 199 deletions(-) diff --git a/Scanner.cpp b/Scanner.cpp index 4ffc2223..487d5c20 100644 --- a/Scanner.cpp +++ b/Scanner.cpp @@ -194,7 +194,6 @@ Token::Value Scanner::selectToken(char _next, Token::Value _then, Token::Value _ return _else; } - bool Scanner::skipWhitespace() { int const startPosition = getSourcePos(); @@ -204,7 +203,6 @@ bool Scanner::skipWhitespace() return getSourcePos() != startPosition; } - Token::Value Scanner::skipSingleLineComment() { // The line terminator at the end of the line is not considered @@ -215,7 +213,6 @@ Token::Value Scanner::skipSingleLineComment() return Token::WHITESPACE; } -/// For the moment this function simply consumes a single line triple slash doc comment Token::Value Scanner::scanDocumentationComment() { LiteralScope literal(this, LITERAL_TYPE_COMMENT); @@ -545,14 +542,12 @@ Token::Value Scanner::scanString() return Token::STRING_LITERAL; } - void Scanner::scanDecimalDigits() { while (isDecimalDigit(m_char)) addLiteralCharAndAdvance(); } - Token::Value Scanner::scanNumber(char _charSeen) { enum { DECIMAL, HEX, BINARY } kind = DECIMAL; @@ -623,186 +618,18 @@ Token::Value Scanner::scanNumber(char _charSeen) // ---------------------------------------------------------------------------- // Keyword Matcher -#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \ - KEYWORD_GROUP('a') \ - KEYWORD("address", Token::ADDRESS) \ - KEYWORD_GROUP('b') \ - KEYWORD("break", Token::BREAK) \ - KEYWORD("bool", Token::BOOL) \ - KEYWORD_GROUP('c') \ - KEYWORD("case", Token::CASE) \ - KEYWORD("const", Token::CONST) \ - KEYWORD("continue", Token::CONTINUE) \ - KEYWORD("contract", Token::CONTRACT) \ - KEYWORD_GROUP('d') \ - KEYWORD("default", Token::DEFAULT) \ - KEYWORD("delete", Token::DELETE) \ - KEYWORD("do", Token::DO) \ - KEYWORD_GROUP('e') \ - KEYWORD("else", Token::ELSE) \ - KEYWORD("extends", Token::EXTENDS) \ - KEYWORD_GROUP('f') \ - KEYWORD("false", Token::FALSE_LITERAL) \ - KEYWORD("for", Token::FOR) \ - KEYWORD("function", Token::FUNCTION) \ - KEYWORD_GROUP('h') \ - KEYWORD("hash", Token::HASH) \ - KEYWORD("hash8", Token::HASH8) \ - KEYWORD("hash16", Token::HASH16) \ - KEYWORD("hash24", Token::HASH24) \ - KEYWORD("hash32", Token::HASH32) \ - KEYWORD("hash40", Token::HASH40) \ - KEYWORD("hash48", Token::HASH48) \ - KEYWORD("hash56", Token::HASH56) \ - KEYWORD("hash64", Token::HASH64) \ - KEYWORD("hash72", Token::HASH72) \ - KEYWORD("hash80", Token::HASH80) \ - KEYWORD("hash88", Token::HASH88) \ - KEYWORD("hash96", Token::HASH96) \ - KEYWORD("hash104", Token::HASH104) \ - KEYWORD("hash112", Token::HASH112) \ - KEYWORD("hash120", Token::HASH120) \ - KEYWORD("hash128", Token::HASH128) \ - KEYWORD("hash136", Token::HASH136) \ - KEYWORD("hash144", Token::HASH144) \ - KEYWORD("hash152", Token::HASH152) \ - KEYWORD("hash160", Token::HASH160) \ - KEYWORD("hash168", Token::HASH168) \ - KEYWORD("hash178", Token::HASH176) \ - KEYWORD("hash184", Token::HASH184) \ - KEYWORD("hash192", Token::HASH192) \ - KEYWORD("hash200", Token::HASH200) \ - KEYWORD("hash208", Token::HASH208) \ - KEYWORD("hash216", Token::HASH216) \ - KEYWORD("hash224", Token::HASH224) \ - KEYWORD("hash232", Token::HASH232) \ - KEYWORD("hash240", Token::HASH240) \ - KEYWORD("hash248", Token::HASH248) \ - KEYWORD("hash256", Token::HASH256) \ - KEYWORD_GROUP('i') \ - KEYWORD("if", Token::IF) \ - KEYWORD("in", Token::IN) \ - KEYWORD("int", Token::INT) \ - KEYWORD("int8", Token::INT8) \ - KEYWORD("int16", Token::INT16) \ - KEYWORD("int24", Token::INT24) \ - KEYWORD("int32", Token::INT32) \ - KEYWORD("int40", Token::INT40) \ - KEYWORD("int48", Token::INT48) \ - KEYWORD("int56", Token::INT56) \ - KEYWORD("int64", Token::INT64) \ - KEYWORD("int72", Token::INT72) \ - KEYWORD("int80", Token::INT80) \ - KEYWORD("int88", Token::INT88) \ - KEYWORD("int96", Token::INT96) \ - KEYWORD("int104", Token::INT104) \ - KEYWORD("int112", Token::INT112) \ - KEYWORD("int120", Token::INT120) \ - KEYWORD("int128", Token::INT128) \ - KEYWORD("int136", Token::INT136) \ - KEYWORD("int144", Token::INT144) \ - KEYWORD("int152", Token::INT152) \ - KEYWORD("int160", Token::INT160) \ - KEYWORD("int168", Token::INT168) \ - KEYWORD("int178", Token::INT176) \ - KEYWORD("int184", Token::INT184) \ - KEYWORD("int192", Token::INT192) \ - KEYWORD("int200", Token::INT200) \ - KEYWORD("int208", Token::INT208) \ - KEYWORD("int216", Token::INT216) \ - KEYWORD("int224", Token::INT224) \ - KEYWORD("int232", Token::INT232) \ - KEYWORD("int240", Token::INT240) \ - KEYWORD("int248", Token::INT248) \ - KEYWORD("int256", Token::INT256) \ - KEYWORD_GROUP('l') \ - KEYWORD_GROUP('m') \ - KEYWORD("mapping", Token::MAPPING) \ - KEYWORD_GROUP('n') \ - KEYWORD("new", Token::NEW) \ - KEYWORD("null", Token::NULL_LITERAL) \ - KEYWORD_GROUP('p') \ - KEYWORD("private", Token::PRIVATE) \ - KEYWORD("public", Token::PUBLIC) \ - KEYWORD_GROUP('r') \ - KEYWORD("real", Token::REAL) \ - KEYWORD("return", Token::RETURN) \ - KEYWORD("returns", Token::RETURNS) \ - KEYWORD_GROUP('s') \ - KEYWORD("string", Token::STRING_TYPE) \ - KEYWORD("struct", Token::STRUCT) \ - KEYWORD("switch", Token::SWITCH) \ - KEYWORD_GROUP('t') \ - KEYWORD("text", Token::TEXT) \ - KEYWORD("true", Token::TRUE_LITERAL) \ - KEYWORD_GROUP('u') \ - KEYWORD("uint", Token::UINT) \ - KEYWORD("uint8", Token::UINT8) \ - KEYWORD("uint16", Token::UINT16) \ - KEYWORD("uint24", Token::UINT24) \ - KEYWORD("uint32", Token::UINT32) \ - KEYWORD("uint40", Token::UINT40) \ - KEYWORD("uint48", Token::UINT48) \ - KEYWORD("uint56", Token::UINT56) \ - KEYWORD("uint64", Token::UINT64) \ - KEYWORD("uint72", Token::UINT72) \ - KEYWORD("uint80", Token::UINT80) \ - KEYWORD("uint88", Token::UINT88) \ - KEYWORD("uint96", Token::UINT96) \ - KEYWORD("uint104", Token::UINT104) \ - KEYWORD("uint112", Token::UINT112) \ - KEYWORD("uint120", Token::UINT120) \ - KEYWORD("uint128", Token::UINT128) \ - KEYWORD("uint136", Token::UINT136) \ - KEYWORD("uint144", Token::UINT144) \ - KEYWORD("uint152", Token::UINT152) \ - KEYWORD("uint160", Token::UINT160) \ - KEYWORD("uint168", Token::UINT168) \ - KEYWORD("uint178", Token::UINT176) \ - KEYWORD("uint184", Token::UINT184) \ - KEYWORD("uint192", Token::UINT192) \ - KEYWORD("uint200", Token::UINT200) \ - KEYWORD("uint208", Token::UINT208) \ - KEYWORD("uint216", Token::UINT216) \ - KEYWORD("uint224", Token::UINT224) \ - KEYWORD("uint232", Token::UINT232) \ - KEYWORD("uint240", Token::UINT240) \ - KEYWORD("uint248", Token::UINT248) \ - KEYWORD("uint256", Token::UINT256) \ - KEYWORD("ureal", Token::UREAL) \ - KEYWORD_GROUP('v') \ - KEYWORD("var", Token::VAR) \ - KEYWORD_GROUP('w') \ - KEYWORD("while", Token::WHILE) \ - - -static Token::Value KeywordOrIdentifierToken(string const& _input) + +static Token::Value keywordOrIdentifierToken(string const& _input) { - if (asserts(!_input.empty())) - BOOST_THROW_EXCEPTION(InternalCompilerError()); - int const kMinLength = 2; - int const kMaxLength = 10; - if (_input.size() < kMinLength || _input.size() > kMaxLength) - return Token::IDENTIFIER; - switch (_input[0]) - { - default: -#define KEYWORD_GROUP_CASE(ch) \ - break; \ - case ch: -#define KEYWORD(keyword, token) \ - { \ - /* 'keyword' is a char array, so sizeof(keyword) is */ \ - /* strlen(keyword) plus 1 for the NUL char. */ \ - int const keywordLength = sizeof(keyword) - 1; \ - BOOST_STATIC_ASSERT(keywordLength >= kMinLength); \ - BOOST_STATIC_ASSERT(keywordLength <= kMaxLength); \ - if (_input == keyword) \ - return token; \ - } - KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD) - } - return Token::IDENTIFIER; +#define KEYWORD(name, string, precedence) {string, Token::name}, +#define TOKEN(name, string, precedence) + static const map keywords{ + TOKEN_LIST(TOKEN, KEYWORD) + }; +#undef KEYWORD +#undef TOKEN + auto it = keywords.find(_input); + return it == keywords.end() ? Token::IDENTIFIER : it->second; } Token::Value Scanner::scanIdentifierOrKeyword() @@ -815,7 +642,7 @@ Token::Value Scanner::scanIdentifierOrKeyword() while (isIdentifierPart(m_char)) addLiteralCharAndAdvance(); literal.complete(); - return KeywordOrIdentifierToken(m_nextToken.literal); + return keywordOrIdentifierToken(m_nextToken.literal); } char CharStream::advanceAndGet(size_t _chars) diff --git a/Token.h b/Token.h index 8974ca1a..f1a94af3 100644 --- a/Token.h +++ b/Token.h @@ -314,25 +314,11 @@ public: } // Predicates - static bool isKeyword(Value tok) { return m_tokenType[tok] == 'K'; } - static bool isIdentifier(Value tok) { return tok == IDENTIFIER; } static bool isElementaryTypeName(Value tok) { return INT <= tok && tok < TYPES_END; } static bool isAssignmentOp(Value tok) { return ASSIGN <= tok && tok <= ASSIGN_MOD; } static bool isBinaryOp(Value op) { return COMMA <= op && op <= MOD; } - static bool isTruncatingBinaryOp(Value op) { return BIT_OR <= op && op <= SHR; } static bool isArithmeticOp(Value op) { return ADD <= op && op <= MOD; } static bool isCompareOp(Value op) { return EQ <= op && op <= IN; } - static bool isOrderedRelationalCompareOp(Value op) - { - return op == LT || op == LTE || op == GT || op == GTE; - } - static bool isEqualityOp(Value op) { return op == EQ; } - static bool isInequalityOp(Value op) { return op == NE; } - static bool isArithmeticCompareOp(Value op) - { - return isOrderedRelationalCompareOp(op) || - isEqualityOp(op) || isInequalityOp(op); - } static Value AssignmentToBinaryOp(Value op) { -- cgit From 9e91596c8d5683e79314fcd53a18e0e3df7b3390 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 1 Dec 2014 15:22:45 +0100 Subject: Save the scope for every declaration. --- AST.h | 7 +++++- DeclarationContainer.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++ DeclarationContainer.h | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ NameAndTypeResolver.cpp | 19 ++++++++-------- NameAndTypeResolver.h | 14 ++++++------ Scope.cpp | 50 ------------------------------------------ Scope.h | 55 ---------------------------------------------- 7 files changed, 129 insertions(+), 123 deletions(-) create mode 100644 DeclarationContainer.cpp create mode 100644 DeclarationContainer.h delete mode 100644 Scope.cpp delete mode 100644 Scope.h diff --git a/AST.h b/AST.h index 81a12ad1..68b5c8b8 100644 --- a/AST.h +++ b/AST.h @@ -88,11 +88,16 @@ public: Declaration(Location const& _location, ASTPointer const& _name): ASTNode(_location), m_name(_name) {} - /// Returns the declared name. + /// @returns the declared name. ASTString const& getName() const { return *m_name; } + /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. + /// Available only after name and type resolution step. + Declaration* getScope() const { return m_scope; } + void setScope(Declaration* const& _scope) { m_scope = _scope; } private: ASTPointer m_name; + Declaration* m_scope; }; /** diff --git a/DeclarationContainer.cpp b/DeclarationContainer.cpp new file mode 100644 index 00000000..6ea9c28c --- /dev/null +++ b/DeclarationContainer.cpp @@ -0,0 +1,50 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @author Christian + * @date 2014 + * Scope - object that holds declaration of names. + */ + +#include +#include + +namespace dev +{ +namespace solidity +{ + +bool DeclarationContainer::registerDeclaration(Declaration& _declaration) +{ + if (m_declarations.find(_declaration.getName()) != m_declarations.end()) + return false; + m_declarations[_declaration.getName()] = &_declaration; + return true; +} + +Declaration* DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const +{ + auto result = m_declarations.find(_name); + if (result != m_declarations.end()) + return result->second; + if (_recursive && m_enclosingContainer) + return m_enclosingContainer->resolveName(_name, true); + return nullptr; +} + +} +} diff --git a/DeclarationContainer.h b/DeclarationContainer.h new file mode 100644 index 00000000..db681289 --- /dev/null +++ b/DeclarationContainer.h @@ -0,0 +1,57 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @author Christian + * @date 2014 + * Scope - object that holds declaration of names. + */ + +#pragma once + +#include +#include + +#include + +namespace dev +{ +namespace solidity +{ + +/** + * Container that stores mappings betwee names and declarations. It also contains a link to the + * enclosing scope. + */ +class DeclarationContainer +{ +public: + explicit DeclarationContainer(Declaration* _enclosingDeclaration = nullptr, DeclarationContainer* _enclosingContainer = nullptr): + m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {} + /// Registers the declaration in the scope unless its name is already declared. Returns true iff + /// it was not yet declared. + bool registerDeclaration(Declaration& _declaration); + Declaration* resolveName(ASTString const& _name, bool _recursive = false) const; + Declaration* getEnclosingDeclaration() const { return m_enclosingDeclaration; } + +private: + Declaration* m_enclosingDeclaration; + DeclarationContainer* m_enclosingContainer; + std::map m_declarations; +}; + +} +} diff --git a/NameAndTypeResolver.cpp b/NameAndTypeResolver.cpp index 225f2a78..d473348b 100644 --- a/NameAndTypeResolver.cpp +++ b/NameAndTypeResolver.cpp @@ -78,9 +78,9 @@ Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name return m_currentScope->resolveName(_name, _recursive); } -DeclarationRegistrationHelper::DeclarationRegistrationHelper(map& _scopes, +DeclarationRegistrationHelper::DeclarationRegistrationHelper(map& _scopes, ASTNode& _astRoot): - m_scopes(_scopes), m_currentScope(&m_scopes[nullptr]) + m_scopes(_scopes), m_currentScope(nullptr) { _astRoot.accept(*this); } @@ -135,31 +135,30 @@ bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) return true; } -void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node) +void DeclarationRegistrationHelper::enterNewSubScope(Declaration& _declaration) { - map::iterator iter; + map::iterator iter; bool newlyAdded; - tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope)); + tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, DeclarationContainer(m_currentScope, &m_scopes[m_currentScope])); if (asserts(newlyAdded)) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to add new scope.")); - m_currentScope = &iter->second; + m_currentScope = &_declaration; } void DeclarationRegistrationHelper::closeCurrentScope() { if (asserts(m_currentScope)) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Closed non-existing scope.")); - m_currentScope = m_currentScope->getEnclosingScope(); + m_currentScope = m_scopes[m_currentScope].getEnclosingDeclaration(); } void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) { - if (asserts(m_currentScope)) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration registered without scope.")); - if (!m_currentScope->registerDeclaration(_declaration)) + if (!m_scopes[m_currentScope].registerDeclaration(_declaration)) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) << errinfo_comment("Identifier already declared.")); //@todo the exception should also contain the location of the first declaration + _declaration.setScope(m_currentScope); if (_opensScope) enterNewSubScope(_declaration); } diff --git a/NameAndTypeResolver.h b/NameAndTypeResolver.h index 64f3c89d..797eca60 100644 --- a/NameAndTypeResolver.h +++ b/NameAndTypeResolver.h @@ -25,7 +25,7 @@ #include #include -#include +#include #include namespace dev @@ -61,9 +61,9 @@ private: /// Maps nodes declaring a scope to scopes, i.e. ContractDefinition and FunctionDeclaration, /// where nullptr denotes the global scope. Note that structs are not scope since they do /// not contain code. - std::map m_scopes; + std::map m_scopes; - Scope* m_currentScope; + DeclarationContainer* m_currentScope; }; /** @@ -73,7 +73,7 @@ private: class DeclarationRegistrationHelper: private ASTVisitor { public: - DeclarationRegistrationHelper(std::map& _scopes, ASTNode& _astRoot); + DeclarationRegistrationHelper(std::map& _scopes, ASTNode& _astRoot); private: bool visit(ContractDefinition& _contract); @@ -85,12 +85,12 @@ private: void endVisit(VariableDefinition& _variableDefinition); bool visit(VariableDeclaration& _declaration); - void enterNewSubScope(ASTNode& _node); + void enterNewSubScope(Declaration& _declaration); void closeCurrentScope(); void registerDeclaration(Declaration& _declaration, bool _opensScope); - std::map& m_scopes; - Scope* m_currentScope; + std::map& m_scopes; + Declaration* m_currentScope; FunctionDefinition* m_currentFunction; }; diff --git a/Scope.cpp b/Scope.cpp deleted file mode 100644 index 540c4120..00000000 --- a/Scope.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** - * @author Christian - * @date 2014 - * Scope - object that holds declaration of names. - */ - -#include -#include - -namespace dev -{ -namespace solidity -{ - -bool Scope::registerDeclaration(Declaration& _declaration) -{ - if (m_declarations.find(_declaration.getName()) != m_declarations.end()) - return false; - m_declarations[_declaration.getName()] = &_declaration; - return true; -} - -Declaration* Scope::resolveName(ASTString const& _name, bool _recursive) const -{ - auto result = m_declarations.find(_name); - if (result != m_declarations.end()) - return result->second; - if (_recursive && m_enclosingScope) - return m_enclosingScope->resolveName(_name, true); - return nullptr; -} - -} -} diff --git a/Scope.h b/Scope.h deleted file mode 100644 index 637c2d5c..00000000 --- a/Scope.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** - * @author Christian - * @date 2014 - * Scope - object that holds declaration of names. - */ - -#pragma once - -#include -#include - -#include - -namespace dev -{ -namespace solidity -{ - -/** - * Container that stores mappings betwee names and declarations. It also contains a link to the - * enclosing scope. - */ -class Scope -{ -public: - explicit Scope(Scope* _enclosingScope = nullptr): m_enclosingScope(_enclosingScope) {} - /// Registers the declaration in the scope unless its name is already declared. Returns true iff - /// it was not yet declared. - bool registerDeclaration(Declaration& _declaration); - Declaration* resolveName(ASTString const& _name, bool _recursive = false) const; - Scope* getEnclosingScope() const { return m_enclosingScope; } - -private: - Scope* m_enclosingScope; - std::map m_declarations; -}; - -} -} -- cgit From a2ad47441eeff3c8cac063670dc51e81e32c9005 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 1 Dec 2014 17:32:10 +0100 Subject: Disallow assignments to structs and mappings. --- AST.cpp | 12 ++++++++---- AST.h | 16 +++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/AST.cpp b/AST.cpp index 5c07ec80..4bd0b2c0 100644 --- a/AST.cpp +++ b/AST.cpp @@ -378,6 +378,9 @@ void Assignment::checkTypeRequirements() { m_leftHandSide->checkTypeRequirements(); m_leftHandSide->requireLValue(); + //@todo later, assignments to structs might be possible, but not to mappings + if (!m_leftHandSide->getType()->isValueType() && !m_leftHandSide->isLocalLValue()) + BOOST_THROW_EXCEPTION(createTypeError("Assignment to non-local non-value lvalue.")); m_rightHandSide->expectType(*m_leftHandSide->getType()); m_type = m_leftHandSide->getType(); if (m_assigmentOperator != Token::ASSIGN) @@ -403,7 +406,7 @@ void Expression::expectType(Type const& _expectedType) void Expression::requireLValue() { - if (!isLvalue()) + if (!isLValue()) BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue.")); m_lvalueRequested = true; } @@ -495,7 +498,8 @@ void MemberAccess::checkTypeRequirements() m_type = type.getMemberType(*m_memberName); if (!m_type) BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found in " + type.toString())); - m_isLvalue = (type.getCategory() == Type::Category::STRUCT && m_type->getCategory() != Type::Category::MAPPING); + //@todo later, this will not always be STORAGE + m_lvalue = type.getCategory() == Type::Category::STRUCT ? LValueType::STORAGE : LValueType::NONE; } void IndexAccess::checkTypeRequirements() @@ -507,7 +511,7 @@ void IndexAccess::checkTypeRequirements() MappingType const& type = dynamic_cast(*m_base->getType()); m_index->expectType(*type.getKeyType()); m_type = type.getValueType(); - m_isLvalue = m_type->getCategory() != Type::Category::MAPPING; + m_lvalue = LValueType::STORAGE; } void Identifier::checkTypeRequirements() @@ -521,7 +525,7 @@ void Identifier::checkTypeRequirements() if (!variable->getType()) BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined.")); m_type = variable->getType(); - m_isLvalue = true; + m_lvalue = variable->isLocalVariable() ? LValueType::LOCAL : LValueType::STORAGE; return; } //@todo can we unify these with TypeName::toType()? diff --git a/AST.h b/AST.h index 68b5c8b8..87bc3cd4 100644 --- a/AST.h +++ b/AST.h @@ -242,6 +242,8 @@ public: std::shared_ptr const& getType() const { return m_type; } void setType(std::shared_ptr const& _type) { m_type = _type; } + bool isLocalVariable() const { return !!dynamic_cast(getScope()); } + private: ASTPointer m_typeName; ///< can be empty ("var") @@ -526,12 +528,16 @@ private: */ class Expression: public ASTNode { +protected: + enum class LValueType { NONE, LOCAL, STORAGE }; + public: - Expression(Location const& _location): ASTNode(_location), m_isLvalue(false), m_lvalueRequested(false) {} + Expression(Location const& _location): ASTNode(_location), m_lvalue(LValueType::NONE), m_lvalueRequested(false) {} virtual void checkTypeRequirements() = 0; std::shared_ptr const& getType() const { return m_type; } - bool isLvalue() const { return m_isLvalue; } + bool isLValue() const { return m_lvalue != LValueType::NONE; } + bool isLocalLValue() const { return m_lvalue == LValueType::LOCAL; } /// Helper function, infer the type via @ref checkTypeRequirements and then check that it /// is implicitly convertible to @a _expectedType. If not, throw exception. @@ -546,9 +552,9 @@ public: protected: //! Inferred type of the expression, only filled after a call to checkTypeRequirements(). std::shared_ptr m_type; - //! Whether or not this expression is an lvalue, i.e. something that can be assigned to. - //! This is set during calls to @a checkTypeRequirements() - bool m_isLvalue; + //! If this expression is an lvalue (i.e. something that can be assigned to) and is stored + //! locally or in storage. This is set during calls to @a checkTypeRequirements() + LValueType m_lvalue; //! Whether the outer expression requested the address (true) or the value (false) of this expression. bool m_lvalueRequested; }; -- cgit From 24f3a4a2ea22d4b9a6098a86016f1c5edfbd714d Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 2 Dec 2014 17:53:25 +0100 Subject: Fix: Storage offset of first struct member should be zero. --- Types.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Types.cpp b/Types.cpp index b81fbbe3..7e07b116 100644 --- a/Types.cpp +++ b/Types.cpp @@ -295,9 +295,9 @@ u256 StructType::getStorageOffsetOfMember(string const& _name) const u256 offset; for (ASTPointer variable: m_struct.getMembers()) { - offset += variable->getType()->getStorageSize(); if (variable->getName() == _name) return offset; + offset += variable->getType()->getStorageSize(); } BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested.")); } -- cgit From 71ae1f8f00c5d384634496c58530adc8fb6be16e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 2 Dec 2014 20:18:01 +0100 Subject: Warnings fixes (well.. the UPnP was actually a crash fix.) --- Compiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Compiler.cpp b/Compiler.cpp index 988390d0..17ad4fd1 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -324,7 +324,7 @@ bool Compiler::visit(ExpressionStatement& _expressionStatement) { Expression& expression = _expressionStatement.getExpression(); ExpressionCompiler::compileExpression(m_context, expression); - Type::Category category = expression.getType()->getCategory(); +// Type::Category category = expression.getType()->getCategory(); for (unsigned i = 0; i < expression.getType()->getSizeOnStack(); ++i) m_context << eth::Instruction::POP; return false; -- cgit From 7b54d957d8535fb9c9a978246fe3afd90657fae2 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 3 Dec 2014 09:41:12 +0100 Subject: Comments for the TOKEN_LIST usage. --- Scanner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Scanner.cpp b/Scanner.cpp index 487d5c20..2f5f8d37 100644 --- a/Scanner.cpp +++ b/Scanner.cpp @@ -621,11 +621,11 @@ Token::Value Scanner::scanNumber(char _charSeen) static Token::Value keywordOrIdentifierToken(string const& _input) { + // The following macros are used inside TOKEN_LIST and cause non-keyword tokens to be ignored + // and keywords to be put inside the keywords variable. #define KEYWORD(name, string, precedence) {string, Token::name}, #define TOKEN(name, string, precedence) - static const map keywords{ - TOKEN_LIST(TOKEN, KEYWORD) - }; + static const map keywords({TOKEN_LIST(TOKEN, KEYWORD)}); #undef KEYWORD #undef TOKEN auto it = keywords.find(_input); -- cgit