diff options
-rw-r--r-- | AST.cpp | 143 | ||||
-rw-r--r-- | AST.h | 37 | ||||
-rw-r--r-- | ASTForward.h | 31 | ||||
-rw-r--r-- | ASTPrinter.cpp | 46 | ||||
-rw-r--r-- | ASTPrinter.h | 34 | ||||
-rw-r--r-- | ASTVisitor.h | 34 | ||||
-rw-r--r-- | BaseTypes.h | 34 | ||||
-rw-r--r-- | Exceptions.h | 31 | ||||
-rw-r--r-- | NameAndTypeResolver.cpp | 44 | ||||
-rw-r--r-- | NameAndTypeResolver.h | 31 | ||||
-rw-r--r-- | Parser.cpp | 288 | ||||
-rw-r--r-- | Parser.h | 31 | ||||
-rw-r--r-- | Scanner.cpp | 911 | ||||
-rw-r--r-- | Scanner.h | 98 | ||||
-rw-r--r-- | Scope.cpp | 33 | ||||
-rw-r--r-- | Scope.h | 31 | ||||
-rw-r--r-- | Token.cpp | 21 | ||||
-rw-r--r-- | Token.h | 194 | ||||
-rw-r--r-- | Types.cpp | 64 | ||||
-rw-r--r-- | Types.h | 58 |
20 files changed, 1145 insertions, 1049 deletions
@@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -26,12 +26,15 @@ #include <libsolidity/ASTVisitor.h> #include <libsolidity/Exceptions.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ void ContractDefinition::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { listAccept(m_definedStructs, _visitor); listAccept(m_stateVariables, _visitor); listAccept(m_definedFunctions, _visitor); @@ -41,7 +44,8 @@ void ContractDefinition::accept(ASTVisitor& _visitor) void StructDefinition::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { listAccept(m_members, _visitor); } _visitor.endVisit(*this); @@ -49,7 +53,8 @@ void StructDefinition::accept(ASTVisitor& _visitor) void ParameterList::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { listAccept(m_parameters, _visitor); } _visitor.endVisit(*this); @@ -57,7 +62,8 @@ void ParameterList::accept(ASTVisitor& _visitor) void FunctionDefinition::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { m_parameters->accept(_visitor); if (m_returnParameters) m_returnParameters->accept(_visitor); @@ -68,7 +74,8 @@ void FunctionDefinition::accept(ASTVisitor& _visitor) void VariableDeclaration::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { if (m_typeName) m_typeName->accept(_visitor); } @@ -95,7 +102,8 @@ void UserDefinedTypeName::accept(ASTVisitor& _visitor) void Mapping::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { m_keyType->accept(_visitor); m_valueType->accept(_visitor); } @@ -110,7 +118,8 @@ void Statement::accept(ASTVisitor& _visitor) void Block::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { listAccept(m_statements, _visitor); } _visitor.endVisit(*this); @@ -118,7 +127,8 @@ void Block::accept(ASTVisitor& _visitor) void IfStatement::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { m_condition->accept(_visitor); m_trueBody->accept(_visitor); if (m_falseBody) @@ -135,7 +145,8 @@ void BreakableStatement::accept(ASTVisitor& _visitor) void WhileStatement::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { m_condition->accept(_visitor); m_body->accept(_visitor); } @@ -156,7 +167,8 @@ void Break::accept(ASTVisitor& _visitor) void Return::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { if (m_expression) m_expression->accept(_visitor); } @@ -165,7 +177,8 @@ void Return::accept(ASTVisitor& _visitor) void VariableDefinition::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { m_variable->accept(_visitor); if (m_value) m_value->accept(_visitor); @@ -175,7 +188,8 @@ void VariableDefinition::accept(ASTVisitor& _visitor) void Assignment::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { m_leftHandSide->accept(_visitor); m_rightHandSide->accept(_visitor); } @@ -184,7 +198,8 @@ void Assignment::accept(ASTVisitor& _visitor) void UnaryOperation::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { m_subExpression->accept(_visitor); } _visitor.endVisit(*this); @@ -192,7 +207,8 @@ void UnaryOperation::accept(ASTVisitor& _visitor) void BinaryOperation::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { m_left->accept(_visitor); m_right->accept(_visitor); } @@ -201,7 +217,8 @@ void BinaryOperation::accept(ASTVisitor& _visitor) void FunctionCall::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { m_expression->accept(_visitor); listAccept(m_arguments, _visitor); } @@ -210,7 +227,8 @@ void FunctionCall::accept(ASTVisitor& _visitor) void MemberAccess::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { m_expression->accept(_visitor); } _visitor.endVisit(*this); @@ -218,7 +236,8 @@ void MemberAccess::accept(ASTVisitor& _visitor) void IndexAccess::accept(ASTVisitor& _visitor) { - if (_visitor.visit(*this)) { + if (_visitor.visit(*this)) + { m_base->accept(_visitor); m_index->accept(_visitor); } @@ -253,7 +272,7 @@ void Statement::expectType(Expression& _expression, const Type& _expectedType) ptr<Type> Block::checkTypeRequirements() { - for (ptr<Statement> const& statement : m_statements) + for (ptr<Statement> const & statement : m_statements) statement->checkTypeRequirements(); return ptr<Type>(); } @@ -292,7 +311,6 @@ ptr<Type> Return::checkTypeRequirements() "declaration.")); // this could later be changed such that the paramaters type is an anonymous struct type, // but for now, we only allow one return parameter - expectType(*m_expression, *m_returnParameters->getParameters().front()->getType()); return ptr<Type>(); } @@ -303,10 +321,14 @@ ptr<Type> VariableDefinition::checkTypeRequirements() // setsthe 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->getType()) { + if (m_value) + { + if (m_variable->getType()) + { expectType(*m_value, *m_variable->getType()); - } else { + } + else + { // no type declared and no previous assignment, infer the type m_variable->setType(m_value->checkTypeRequirements()); } @@ -320,7 +342,8 @@ ptr<Type> Assignment::checkTypeRequirements() // add a feature to the type system to check that expectType(*m_rightHandSide, *m_leftHandSide->checkTypeRequirements()); m_type = m_leftHandSide->getType(); - if (m_assigmentOperator != Token::ASSIGN) { + if (m_assigmentOperator != Token::ASSIGN) + { // complex assignment if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator))) BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Operator not compatible with type.")); @@ -341,18 +364,19 @@ ptr<Type> BinaryOperation::checkTypeRequirements() { m_right->checkTypeRequirements(); m_left->checkTypeRequirements(); - if (m_right->getType()->isImplicitlyConvertibleTo(*m_left->getType())) m_commonType = m_left->getType(); else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) m_commonType = m_right->getType(); else BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("No common type found in binary operation.")); - - if (Token::IsCompareOp(m_operator)) { + if (Token::isCompareOp(m_operator)) + { m_type = std::make_shared<BoolType>(); - } else { - BOOST_ASSERT(Token::IsBinaryOp(m_operator)); + } + else + { + BOOST_ASSERT(Token::isBinaryOp(m_operator)); m_type = m_commonType; if (!m_commonType->acceptsBinaryOperator(m_operator)) BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Operator not compatible with type.")); @@ -363,12 +387,12 @@ ptr<Type> BinaryOperation::checkTypeRequirements() ptr<Type> FunctionCall::checkTypeRequirements() { m_expression->checkTypeRequirements(); - for (ptr<Expression> const& argument : m_arguments) + for (ptr<Expression> const & argument : m_arguments) argument->checkTypeRequirements(); - ptr<Type> expressionType = m_expression->getType(); Type::Category const category = expressionType->getCategory(); - if (category == Type::Category::TYPE) { + if (category == Type::Category::TYPE) + { TypeType* type = dynamic_cast<TypeType*>(expressionType.get()); BOOST_ASSERT(type != nullptr); //@todo for structs, we have to check the number of arguments to be equal to the @@ -378,9 +402,11 @@ ptr<Type> FunctionCall::checkTypeRequirements() "explicit type conersion.")); if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType())) BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Explicit type conversion not " - "allowed.")); + "allowed.")); m_type = type->getActualType(); - } else if (category == Type::Category::FUNCTION) { + } + else if (category == Type::Category::FUNCTION) + { //@todo would be nice to create a struct type from the arguments // and then ask if that is implicitly convertible to the struct represented by the // function parameters @@ -390,20 +416,22 @@ ptr<Type> FunctionCall::checkTypeRequirements() vecptr<VariableDeclaration> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Wrong argument count for " - "function call.")); - for (size_t i = 0; i < m_arguments.size(); ++i) { + "function call.")); + for (size_t i = 0; i < m_arguments.size(); ++i) + { if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType())) BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Invalid type for argument in " "function call.")); } - // @todo actually the return type should be an anonymous struct, // but we change it to the type of the first return value until we have structs if (fun.getReturnParameterList()->getParameters().empty()) m_type = std::make_shared<VoidType>(); else m_type = fun.getReturnParameterList()->getParameters().front()->getType(); - } else { + } + else + { BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Type does not support invocation.")); } return m_type; @@ -435,7 +463,8 @@ ptr<Type> Identifier::checkTypeRequirements() // var y = x; // the type of x is not yet determined. VariableDeclaration* variable = dynamic_cast<VariableDeclaration*>(m_referencedDeclaration); - if (variable != nullptr) { + if (variable != nullptr) + { if (variable->getType().get() == nullptr) BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Variable referenced before type " "could be determined.")); @@ -444,13 +473,15 @@ ptr<Type> Identifier::checkTypeRequirements() } //@todo can we unify these with TypeName::toType()? StructDefinition* structDef = dynamic_cast<StructDefinition*>(m_referencedDeclaration); - if (structDef != nullptr) { + if (structDef != nullptr) + { // note that we do not have a struct type here m_type = std::make_shared<TypeType>(std::make_shared<StructType>(*structDef)); return m_type; } FunctionDefinition* functionDef = dynamic_cast<FunctionDefinition*>(m_referencedDeclaration); - if (functionDef != nullptr) { + if (functionDef != nullptr) + { // a function reference is not a TypeType, because calling a TypeType converts to the type. // Calling a function (e.g. function(12), otherContract.function(34)) does not do a type // conversion. @@ -458,7 +489,8 @@ ptr<Type> Identifier::checkTypeRequirements() return m_type; } ContractDefinition* contractDef = dynamic_cast<ContractDefinition*>(m_referencedDeclaration); - if (contractDef != nullptr) { + if (contractDef != nullptr) + { m_type = std::make_shared<TypeType>(std::make_shared<ContractType>(*contractDef)); return m_type; } @@ -478,4 +510,5 @@ ptr<Type> Literal::checkTypeRequirements() return m_type; } -} } +} +} @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -33,8 +33,10 @@ #include <libsolidity/Token.h> #include <libsolidity/Types.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ class ASTVisitor; @@ -49,8 +51,10 @@ public: virtual void accept(ASTVisitor& _visitor) = 0; template <class T> - static void listAccept(vecptr<T>& _list, ASTVisitor& _visitor) { - for (ptr<T>& element : _list) element->accept(_visitor); + static void listAccept(vecptr<T>& _list, ASTVisitor& _visitor) + { + for (ptr<T>& element : _list) + element->accept(_visitor); } Location const& getLocation() const { return m_location; } @@ -521,4 +525,5 @@ private: /// @} -} } +} +} diff --git a/ASTForward.h b/ASTForward.h index 4963776b..0397cadd 100644 --- a/ASTForward.h +++ b/ASTForward.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -28,8 +28,10 @@ // Forward-declare all AST node types -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ class ASTNode; class Declaration; @@ -74,4 +76,5 @@ using vecptr = std::vector<ptr<T>>; using ASTString = std::string; -} } +} +} diff --git a/ASTPrinter.cpp b/ASTPrinter.cpp index bbaa2e0a..7c48dacb 100644 --- a/ASTPrinter.cpp +++ b/ASTPrinter.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -23,8 +23,10 @@ #include <libsolidity/ASTPrinter.h> #include <libsolidity/AST.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ ASTPrinter::ASTPrinter(ptr<ASTNode> _ast, const std::string& _source) : m_indentation(0), m_source(_source), m_ast(_ast) @@ -85,7 +87,7 @@ bool ASTPrinter::visit(TypeName& _node) bool ASTPrinter::visit(ElementaryTypeName& _node) { - writeLine(std::string("ElementaryTypeName ") + Token::String(_node.getType())); + writeLine(std::string("ElementaryTypeName ") + Token::toString(_node.getType())); printSourcePart(_node); return goDeeper(); } @@ -176,7 +178,7 @@ bool ASTPrinter::visit(Expression& _node) bool ASTPrinter::visit(Assignment& _node) { - writeLine(std::string("Assignment using operator ") + Token::String(_node.getAssignmentOperator())); + writeLine(std::string("Assignment using operator ") + Token::toString(_node.getAssignmentOperator())); printSourcePart(_node); return goDeeper(); } @@ -184,14 +186,14 @@ bool ASTPrinter::visit(Assignment& _node) bool ASTPrinter::visit(UnaryOperation& _node) { writeLine(std::string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") + - ") " + Token::String(_node.getOperator())); + ") " + Token::toString(_node.getOperator())); printSourcePart(_node); return goDeeper(); } bool ASTPrinter::visit(BinaryOperation& _node) { - writeLine(std::string("BinaryOperation using operator ") + Token::String(_node.getOperator())); + writeLine(std::string("BinaryOperation using operator ") + Token::toString(_node.getOperator())); printSourcePart(_node); return goDeeper(); } @@ -233,14 +235,14 @@ bool ASTPrinter::visit(Identifier& _node) bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) { - writeLine(std::string("ElementaryTypeNameExpression ") + Token::String(_node.getTypeToken())); + writeLine(std::string("ElementaryTypeNameExpression ") + Token::toString(_node.getTypeToken())); printSourcePart(_node); return goDeeper(); } bool ASTPrinter::visit(Literal& _node) { - const char* tokenString = Token::String(_node.getToken()); + const char* tokenString = Token::toString(_node.getToken()); if (tokenString == nullptr) tokenString = "----"; writeLine(std::string("Literal, token: ") + tokenString + " value: " + _node.getValue()); @@ -402,7 +404,8 @@ void ASTPrinter::endVisit(Literal&) void ASTPrinter::printSourcePart(ASTNode const& _node) { - if (!m_source.empty()) { + if (!m_source.empty()) + { Location const& location(_node.getLocation()); *m_ostream << getIndentation() << " Source: |" << m_source.substr(location.start, location.end - location.start) << "|\n"; @@ -419,4 +422,5 @@ void ASTPrinter::writeLine(const std::string& _line) *m_ostream << getIndentation() << _line << '\n'; } -} } +} +} diff --git a/ASTPrinter.h b/ASTPrinter.h index 6a864f38..52f34991 100644 --- a/ASTPrinter.h +++ b/ASTPrinter.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -25,8 +25,10 @@ #include <ostream> #include <libsolidity/ASTVisitor.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ class ASTPrinter : public ASTVisitor { @@ -67,7 +69,7 @@ public: bool visit(ElementaryTypeNameExpression& _node) override; bool visit(Literal& _node) override; - void endVisit(ASTNode & _node) override; + void endVisit(ASTNode& _node) override; void endVisit(ContractDefinition&) override; void endVisit(StructDefinition&) override; void endVisit(ParameterList&) override; @@ -103,10 +105,12 @@ private: std::string getIndentation() const; void writeLine(std::string const& _line); bool goDeeper() { m_indentation++; return true; } + int m_indentation; std::string m_source; ptr<ASTNode> m_ast; std::ostream* m_ostream; }; -} } +} +} diff --git a/ASTVisitor.h b/ASTVisitor.h index c28d2330..72f28768 100644 --- a/ASTVisitor.h +++ b/ASTVisitor.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -25,10 +25,13 @@ #include <libsolidity/ASTForward.h> #include <string> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ -class ASTVisitor { +class ASTVisitor +{ public: /// These functions are called after a call to ASTNode::accept, /// first visit, then (if visit returns true) recursively for all @@ -97,4 +100,5 @@ public: virtual void endVisit(Literal&) { } }; -} } +} +} diff --git a/BaseTypes.h b/BaseTypes.h index 6d57b74b..c8926b6a 100644 --- a/BaseTypes.h +++ b/BaseTypes.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -23,12 +23,15 @@ #pragma once -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ /// Representation of an interval of source positions. /// The interval includes start and excludes end. -struct Location { +struct Location +{ Location(int _start, int _end) : start(_start), end(_end) { } Location() : start(-1), end(-1) { } @@ -38,4 +41,5 @@ struct Location { int end; }; -} } +} +} diff --git a/Exceptions.h b/Exceptions.h index 5e0b1522..c14e0d79 100644 --- a/Exceptions.h +++ b/Exceptions.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -24,11 +24,14 @@ #include <libdevcore/Exceptions.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ struct ParserError : virtual Exception {}; struct TypeError : virtual Exception {}; struct DeclarationError : virtual Exception {}; -} } +} +} diff --git a/NameAndTypeResolver.cpp b/NameAndTypeResolver.cpp index 7208d7ac..ada987b0 100644 --- a/NameAndTypeResolver.cpp +++ b/NameAndTypeResolver.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -26,8 +26,10 @@ #include <libsolidity/Exceptions.h> #include <boost/assert.hpp> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ NameAndTypeResolver::NameAndTypeResolver() @@ -38,15 +40,12 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) { reset(); DeclarationRegistrationHelper registrar(m_scopes, _contract); - m_currentScope = &m_scopes[&_contract]; - //@todo structs - - for (ptr<VariableDeclaration> const& variable : _contract.getStateVariables()) + for (ptr<VariableDeclaration> const & variable : _contract.getStateVariables()) ReferencesResolver resolver(*variable, *this, nullptr); - - for (ptr<FunctionDefinition> const& function : _contract.getDefinedFunctions()) { + for (ptr<FunctionDefinition> const & function : _contract.getDefinedFunctions()) + { m_currentScope = &m_scopes[function.get()]; ReferencesResolver referencesResolver(*function, *this, function->getReturnParameterList().get()); @@ -54,7 +53,8 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) // First, all function parameter types need to be resolved before we can check // the types, since it is possible to call functions that are only defined later // in the source. - for (ptr<FunctionDefinition> const& function : _contract.getDefinedFunctions()) { + for (ptr<FunctionDefinition> const & function : _contract.getDefinedFunctions()) + { m_currentScope = &m_scopes[function.get()]; function->getBody().checkTypeRequirements(); } @@ -141,7 +141,6 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio BOOST_ASSERT(m_currentScope != nullptr); if (!m_currentScope->registerDeclaration(_declaration)) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Identifier already declared.")); - if (_opensScope) enterNewSubScope(_declaration); } @@ -198,4 +197,5 @@ bool ReferencesResolver::visit(Identifier& _identifier) } -} } +} +} diff --git a/NameAndTypeResolver.h b/NameAndTypeResolver.h index f5a3c84e..346c9e64 100644 --- a/NameAndTypeResolver.h +++ b/NameAndTypeResolver.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -29,8 +29,10 @@ #include <libsolidity/Scope.h> #include <libsolidity/ASTVisitor.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ class NameAndTypeResolver : private boost::noncopyable @@ -92,4 +94,5 @@ private: ParameterList* m_returnParameters; }; -} } +} +} @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -26,13 +26,14 @@ #include <libsolidity/Scanner.h> #include <libsolidity/Exceptions.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ ptr<ContractDefinition> Parser::parse(std::shared_ptr<Scanner> const& _scanner) { m_scanner = _scanner; - return parseContractDefinition(); } @@ -46,9 +47,15 @@ public: : m_parser(_parser), m_location(_parser.getPosition(), -1) {} - void markEndPosition() { m_location.end = m_parser.getEndPosition(); } + void markEndPosition() + { + m_location.end = m_parser.getEndPosition(); + } - void setLocationEmpty() { m_location.end = m_location.start; } + void setLocationEmpty() + { + m_location.end = m_location.start; + } /// Set the end position to the one of the given node. void setEndPositionFromNode(const ptr<ASTNode>& _node) @@ -58,7 +65,7 @@ public: /// @todo: check that this actually uses perfect forwarding template <class NodeType, typename... Args> - ptr<NodeType> createNode(Args&&... _args) + ptr<NodeType> createNode(Args&& ... _args) { if (m_location.end < 0) markEndPosition(); @@ -84,62 +91,73 @@ int Parser::getEndPosition() const ptr<ContractDefinition> Parser::parseContractDefinition() { ASTNodeFactory nodeFactory(*this); - expectToken(Token::CONTRACT); ptr<ASTString> name = expectIdentifierToken(); expectToken(Token::LBRACE); - vecptr<StructDefinition> structs; vecptr<VariableDeclaration> stateVariables; vecptr<FunctionDefinition> functions; bool visibilityIsPublic = true; - while (true) { + while (true) + { Token::Value currentToken = m_scanner->getCurrentToken(); - if (currentToken == Token::RBRACE) { + if (currentToken == Token::RBRACE) + { break; - } else if (currentToken == Token::PUBLIC || currentToken == Token::PRIVATE) { + } + else if (currentToken == Token::PUBLIC || currentToken == Token::PRIVATE) + { visibilityIsPublic = (m_scanner->getCurrentToken() == Token::PUBLIC); m_scanner->next(); expectToken(Token::COLON); - } else if (currentToken == Token::FUNCTION) { + } + else if (currentToken == Token::FUNCTION) + { functions.push_back(parseFunctionDefinition(visibilityIsPublic)); - } else if (currentToken == Token::STRUCT) { + } + else if (currentToken == Token::STRUCT) + { structs.push_back(parseStructDefinition()); - } else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING || - Token::IsElementaryTypeName(currentToken)) { + } + else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING || + Token::isElementaryTypeName(currentToken)) + { bool const allowVar = false; stateVariables.push_back(parseVariableDeclaration(allowVar)); expectToken(Token::SEMICOLON); - } else { + } + else + { throwExpectationError("Function, variable or struct declaration expected."); } } nodeFactory.markEndPosition(); - expectToken(Token::RBRACE); expectToken(Token::EOS); - return nodeFactory.createNode<ContractDefinition>(name, structs, stateVariables, functions); } ptr<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic) { ASTNodeFactory nodeFactory(*this); - expectToken(Token::FUNCTION); ptr<ASTString> name(expectIdentifierToken()); ptr<ParameterList> parameters(parseParameterList()); bool isDeclaredConst = false; - if (m_scanner->getCurrentToken() == Token::CONST) { + if (m_scanner->getCurrentToken() == Token::CONST) + { isDeclaredConst = true; m_scanner->next(); } ptr<ParameterList> returnParameters; - if (m_scanner->getCurrentToken() == Token::RETURNS) { + if (m_scanner->getCurrentToken() == Token::RETURNS) + { const bool permitEmptyParameterList = false; m_scanner->next(); returnParameters = parseParameterList(permitEmptyParameterList); - } else { + } + else + { // create an empty parameter list at a zero-length location ASTNodeFactory nodeFactory(*this); nodeFactory.setLocationEmpty(); @@ -148,32 +166,30 @@ ptr<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic) ptr<Block> block = parseBlock(); nodeFactory.setEndPositionFromNode(block); return nodeFactory.createNode<FunctionDefinition>(name, _isPublic, parameters, - isDeclaredConst, returnParameters, block); + isDeclaredConst, returnParameters, block); } ptr<StructDefinition> Parser::parseStructDefinition() { ASTNodeFactory nodeFactory(*this); - expectToken(Token::STRUCT); ptr<ASTString> name = expectIdentifierToken(); vecptr<VariableDeclaration> members; expectToken(Token::LBRACE); - while (m_scanner->getCurrentToken() != Token::RBRACE) { + while (m_scanner->getCurrentToken() != Token::RBRACE) + { bool const allowVar = false; members.push_back(parseVariableDeclaration(allowVar)); expectToken(Token::SEMICOLON); } nodeFactory.markEndPosition(); expectToken(Token::RBRACE); - return nodeFactory.createNode<StructDefinition>(name, members); } ptr<VariableDeclaration> Parser::parseVariableDeclaration(bool _allowVar) { ASTNodeFactory nodeFactory(*this); - ptr<TypeName> type = parseTypeName(_allowVar); nodeFactory.markEndPosition(); return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken()); @@ -183,58 +199,63 @@ ptr<TypeName> Parser::parseTypeName(bool _allowVar) { ptr<TypeName> type; Token::Value token = m_scanner->getCurrentToken(); - if (Token::IsElementaryTypeName(token)) { + if (Token::isElementaryTypeName(token)) + { type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(token); m_scanner->next(); - } else if (token == Token::VAR) { + } + else if (token == Token::VAR) + { if (!_allowVar) throwExpectationError("Expected explicit type name."); m_scanner->next(); - } else if (token == Token::MAPPING) { + } + else if (token == Token::MAPPING) + { type = parseMapping(); - } else if (token == Token::IDENTIFIER) { + } + else if (token == Token::IDENTIFIER) + { ASTNodeFactory nodeFactory(*this); nodeFactory.markEndPosition(); type = nodeFactory.createNode<UserDefinedTypeName>(expectIdentifierToken()); - } else { + } + else + { throwExpectationError("Expected type name"); } - return type; } ptr<Mapping> Parser::parseMapping() { ASTNodeFactory nodeFactory(*this); - expectToken(Token::MAPPING); expectToken(Token::LPAREN); - - if (!Token::IsElementaryTypeName(m_scanner->getCurrentToken())) + if (!Token::isElementaryTypeName(m_scanner->getCurrentToken())) throwExpectationError("Expected elementary type name for mapping key type"); ptr<ElementaryTypeName> keyType; keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(m_scanner->getCurrentToken()); m_scanner->next(); - expectToken(Token::ARROW); bool const allowVar = false; ptr<TypeName> valueType = parseTypeName(allowVar); nodeFactory.markEndPosition(); expectToken(Token::RPAREN); - return nodeFactory.createNode<Mapping>(keyType, valueType); } ptr<ParameterList> Parser::parseParameterList(bool _allowEmpty) { ASTNodeFactory nodeFactory(*this); - vecptr<VariableDeclaration> parameters; expectToken(Token::LPAREN); - if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RPAREN) { + if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RPAREN) + { bool const allowVar = false; parameters.push_back(parseVariableDeclaration(allowVar)); - while (m_scanner->getCurrentToken() != Token::RPAREN) { + while (m_scanner->getCurrentToken() != Token::RPAREN) + { expectToken(Token::COMMA); parameters.push_back(parseVariableDeclaration(allowVar)); } @@ -249,7 +270,8 @@ ptr<Block> Parser::parseBlock() ASTNodeFactory nodeFactory(*this); expectToken(Token::LBRACE); vecptr<Statement> statements; - while (m_scanner->getCurrentToken() != Token::RBRACE) { + while (m_scanner->getCurrentToken() != Token::RBRACE) + { statements.push_back(parseStatement()); } nodeFactory.markEndPosition(); @@ -260,16 +282,15 @@ ptr<Block> Parser::parseBlock() ptr<Statement> Parser::parseStatement() { ptr<Statement> statement; - - switch (m_scanner->getCurrentToken()) { + switch (m_scanner->getCurrentToken()) + { case Token::IF: return parseIfStatement(); case Token::WHILE: return parseWhileStatement(); case Token::LBRACE: return parseBlock(); - - // starting from here, all statements must be terminated by a semicolon + // starting from here, all statements must be terminated by a semicolon case Token::CONTINUE: statement = ASTNodeFactory(*this).createNode<Continue>(); break; @@ -277,28 +298,32 @@ ptr<Statement> Parser::parseStatement() statement = ASTNodeFactory(*this).createNode<Break>(); break; case Token::RETURN: + { + ASTNodeFactory nodeFactory(*this); + ptr<Expression> expression; + if (m_scanner->next() != Token::SEMICOLON) { - ASTNodeFactory nodeFactory(*this); - ptr<Expression> expression; - if (m_scanner->next() != Token::SEMICOLON) { - expression = parseExpression(); - nodeFactory.setEndPositionFromNode(expression); - } - statement = nodeFactory.createNode<Return>(expression); + expression = parseExpression(); + nodeFactory.setEndPositionFromNode(expression); } - break; + statement = nodeFactory.createNode<Return>(expression); + } + break; default: // distinguish between variable definition (and potentially assignment) and expressions // (which include assignments to other expressions and pre-declared variables) // We have a variable definition if we ge a keyword that specifies a type name, or // in the case of a user-defined type, we have two identifiers following each other. if (m_scanner->getCurrentToken() == Token::MAPPING || - m_scanner->getCurrentToken() == Token::VAR || - Token::IsElementaryTypeName(m_scanner->getCurrentToken()) || - (m_scanner->getCurrentToken() == Token::IDENTIFIER && - m_scanner->peek() == Token::IDENTIFIER)) { + m_scanner->getCurrentToken() == Token::VAR || + Token::isElementaryTypeName(m_scanner->getCurrentToken()) || + (m_scanner->getCurrentToken() == Token::IDENTIFIER && + m_scanner->peek() == Token::IDENTIFIER)) + { statement = parseVariableDefinition(); - } else { + } + else + { // "ordinary" expression statement = parseExpression(); } @@ -316,11 +341,14 @@ ptr<IfStatement> Parser::parseIfStatement() expectToken(Token::RPAREN); ptr<Statement> trueBody = parseStatement(); ptr<Statement> falseBody; - if (m_scanner->getCurrentToken() == Token::ELSE) { + if (m_scanner->getCurrentToken() == Token::ELSE) + { m_scanner->next(); falseBody = parseStatement(); nodeFactory.setEndPositionFromNode(falseBody); - } else { + } + else + { nodeFactory.setEndPositionFromNode(trueBody); } return nodeFactory.createNode<IfStatement>(condition, trueBody, falseBody); @@ -344,11 +372,14 @@ ptr<VariableDefinition> Parser::parseVariableDefinition() bool const allowVar = true; ptr<VariableDeclaration> variable = parseVariableDeclaration(allowVar); ptr<Expression> value; - if (m_scanner->getCurrentToken() == Token::ASSIGN) { + if (m_scanner->getCurrentToken() == Token::ASSIGN) + { m_scanner->next(); value = parseExpression(); nodeFactory.setEndPositionFromNode(value); - } else { + } + else + { nodeFactory.setEndPositionFromNode(variable); } return nodeFactory.createNode<VariableDefinition>(variable, value); @@ -358,9 +389,8 @@ ptr<Expression> Parser::parseExpression() { ASTNodeFactory nodeFactory(*this); ptr<Expression> expression = parseBinaryExpression(); - if (!Token::IsAssignmentOp(m_scanner->getCurrentToken())) + if (!Token::isAssignmentOp(m_scanner->getCurrentToken())) return expression; - Token::Value assignmentOperator = expectAssignmentOperator(); ptr<Expression> rightHandSide = parseExpression(); nodeFactory.setEndPositionFromNode(rightHandSide); @@ -371,9 +401,11 @@ ptr<Expression> Parser::parseBinaryExpression(int _minPrecedence) { ASTNodeFactory nodeFactory(*this); ptr<Expression> expression = parseUnaryExpression(); - int precedence = Token::Precedence(m_scanner->getCurrentToken()); - for (; precedence >= _minPrecedence; --precedence) { - while (Token::Precedence(m_scanner->getCurrentToken()) == precedence) { + int precedence = Token::precedence(m_scanner->getCurrentToken()); + for (; precedence >= _minPrecedence; --precedence) + { + while (Token::precedence(m_scanner->getCurrentToken()) == precedence) + { Token::Value op = m_scanner->getCurrentToken(); m_scanner->next(); ptr<Expression> right = parseBinaryExpression(precedence + 1); @@ -388,17 +420,20 @@ ptr<Expression> Parser::parseUnaryExpression() { ASTNodeFactory nodeFactory(*this); Token::Value token = m_scanner->getCurrentToken(); - if (Token::IsUnaryOp(token) || Token::IsCountOp(token)) { + if (Token::isUnaryOp(token) || Token::isCountOp(token)) + { // prefix expression m_scanner->next(); ptr<Expression> subExpression = parseUnaryExpression(); nodeFactory.setEndPositionFromNode(subExpression); return nodeFactory.createNode<UnaryOperation>(token, subExpression, true); - } else { + } + else + { // potential postfix expression ptr<Expression> subExpression = parseLeftHandSideExpression(); token = m_scanner->getCurrentToken(); - if (!Token::IsCountOp(token)) + if (!Token::isCountOp(token)) return subExpression; nodeFactory.markEndPosition(); m_scanner->next(); @@ -410,34 +445,35 @@ ptr<Expression> Parser::parseLeftHandSideExpression() { ASTNodeFactory nodeFactory(*this); ptr<Expression> expression = parsePrimaryExpression(); - - while (true) { - switch (m_scanner->getCurrentToken()) { + while (true) + { + switch (m_scanner->getCurrentToken()) + { case Token::LBRACK: - { - m_scanner->next(); - ptr<Expression> index = parseExpression(); - nodeFactory.markEndPosition(); - expectToken(Token::RBRACK); - expression = nodeFactory.createNode<IndexAccess>(expression, index); - } - break; + { + m_scanner->next(); + ptr<Expression> index = parseExpression(); + nodeFactory.markEndPosition(); + expectToken(Token::RBRACK); + expression = nodeFactory.createNode<IndexAccess>(expression, index); + } + break; case Token::PERIOD: - { - m_scanner->next(); - nodeFactory.markEndPosition(); - expression = nodeFactory.createNode<MemberAccess>(expression, expectIdentifierToken()); - } - break; + { + m_scanner->next(); + nodeFactory.markEndPosition(); + expression = nodeFactory.createNode<MemberAccess>(expression, expectIdentifierToken()); + } + break; case Token::LPAREN: - { - m_scanner->next(); - vecptr<Expression> arguments = parseFunctionCallArguments(); - nodeFactory.markEndPosition(); - expectToken(Token::RPAREN); - expression = nodeFactory.createNode<FunctionCall>(expression, arguments); - } - break; + { + m_scanner->next(); + vecptr<Expression> arguments = parseFunctionCallArguments(); + nodeFactory.markEndPosition(); + expectToken(Token::RPAREN); + expression = nodeFactory.createNode<FunctionCall>(expression, arguments); + } + break; default: return expression; } @@ -449,8 +485,8 @@ ptr<Expression> Parser::parsePrimaryExpression() ASTNodeFactory nodeFactory(*this); Token::Value token = m_scanner->getCurrentToken(); ptr<Expression> expression; - - switch (token) { + switch (token) + { case Token::TRUE_LITERAL: case Token::FALSE_LITERAL: expression = nodeFactory.createNode<Literal>(token, ptr<ASTString>()); @@ -466,18 +502,21 @@ ptr<Expression> Parser::parsePrimaryExpression() expression = nodeFactory.createNode<Identifier>(getLiteralAndAdvance()); break; case Token::LPAREN: - { - m_scanner->next(); - ptr<Expression> expression = parseExpression(); - expectToken(Token::RPAREN); - return expression; - } + { + m_scanner->next(); + ptr<Expression> expression = parseExpression(); + expectToken(Token::RPAREN); + return expression; + } default: - if (Token::IsElementaryTypeName(token)) { + if (Token::isElementaryTypeName(token)) + { // used for casts expression = nodeFactory.createNode<ElementaryTypeNameExpression>(token); m_scanner->next(); - } else { + } + else + { throwExpectationError("Expected primary expression."); return ptr<Expression>(); // this is not reached } @@ -488,9 +527,11 @@ ptr<Expression> Parser::parsePrimaryExpression() vecptr<Expression> Parser::parseFunctionCallArguments() { vecptr<Expression> arguments; - if (m_scanner->getCurrentToken() != Token::RPAREN) { + if (m_scanner->getCurrentToken() != Token::RPAREN) + { arguments.push_back(parseExpression()); - while (m_scanner->getCurrentToken() != Token::RPAREN) { + while (m_scanner->getCurrentToken() != Token::RPAREN) + { expectToken(Token::COMMA); arguments.push_back(parseExpression()); } @@ -501,14 +542,14 @@ vecptr<Expression> Parser::parseFunctionCallArguments() void Parser::expectToken(Token::Value _value) { if (m_scanner->getCurrentToken() != _value) - throwExpectationError(std::string("Expected token ") + std::string(Token::Name(_value))); + throwExpectationError(std::string("Expected token ") + std::string(Token::getName(_value))); m_scanner->next(); } Token::Value Parser::expectAssignmentOperator() { Token::Value op = m_scanner->getCurrentToken(); - if (!Token::IsAssignmentOp(op)) + if (!Token::isAssignmentOp(op)) throwExpectationError(std::string("Expected assignment operator")); m_scanner->next(); return op; @@ -518,7 +559,6 @@ ptr<ASTString> Parser::expectIdentifierToken() { if (m_scanner->getCurrentToken() != Token::IDENTIFIER) throwExpectationError("Expected identifier"); - return getLiteralAndAdvance(); } @@ -540,9 +580,9 @@ void Parser::throwExpectationError(const std::string& _description) << ", column " << (column + 1) << "\n" << m_scanner->getLineAtPosition(getPosition()) << "\n" << std::string(column, ' ') << "^"; - BOOST_THROW_EXCEPTION(ParserError() << errinfo_comment(buf.str())); } -} } +} +} @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -24,8 +24,10 @@ #include "libsolidity/AST.h" -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ class Scanner; @@ -77,4 +79,5 @@ private: std::shared_ptr<Scanner> m_scanner; }; -} } +} +} diff --git a/Scanner.cpp b/Scanner.cpp index 334da8e7..c2875c9c 100644 --- a/Scanner.cpp +++ b/Scanner.cpp @@ -45,35 +45,47 @@ #include <libsolidity/Scanner.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ -namespace { - bool IsDecimalDigit(char c) { - return '0' <= c && c <= '9'; - } - bool IsHexDigit(char c) { - return IsDecimalDigit(c) - || ('a' <= c && c <= 'f') - || ('A' <= c && c <= 'F'); - } - bool IsLineTerminator(char c) { return c == '\n'; } - bool IsWhiteSpace(char c) { - return c == ' ' || c == '\n' || c == '\t'; - } - bool IsIdentifierStart(char c) { - return c == '_' || c == '$' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); - } - bool IsIdentifierPart(char c) { - return IsIdentifierStart(c) || IsDecimalDigit(c); - } +namespace +{ +bool IsDecimalDigit(char c) +{ + return '0' <= c && c <= '9'; +} +bool IsHexDigit(char c) +{ + return IsDecimalDigit(c) + || ('a' <= c && c <= 'f') + || ('A' <= c && c <= 'F'); +} +bool IsLineTerminator(char c) +{ + return c == '\n'; +} +bool IsWhiteSpace(char c) +{ + return c == ' ' || c == '\n' || c == '\t'; +} +bool IsIdentifierStart(char c) +{ + return c == '_' || c == '$' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); +} +bool IsIdentifierPart(char c) +{ + return IsIdentifierStart(c) || IsDecimalDigit(c); +} - int HexValue(char c) { - if (c >= '0' && c <= '9') return c - '0'; - else if (c >= 'a' && c <= 'f') return c - 'a' + 10; - else if (c >= 'A' && c <= 'F') return c - 'A' + 10; - else return -1; - } +int HexValue(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + else if (c >= 'a' && c <= 'f') return c - 'a' + 10; + else if (c >= 'A' && c <= 'F') return c - 'A' + 10; + else return -1; +} } Scanner::Scanner(const CharStream& _source) @@ -84,7 +96,6 @@ Scanner::Scanner(const CharStream& _source) void Scanner::reset(const CharStream& _source) { m_source = _source; - m_char = m_source.get(); skipWhitespace(); scanToken(); @@ -95,18 +106,18 @@ void Scanner::reset(const CharStream& _source) bool Scanner::scanHexNumber(char& scanned_number, int expected_length) { BOOST_ASSERT(expected_length <= 4); // prevent overflow - char x = 0; - for (int i = 0; i < expected_length; i++) { + for (int i = 0; i < expected_length; i++) + { int d = HexValue(m_char); - if (d < 0) { + if (d < 0) + { rollback(i); return false; } x = x * 16 + d; advance(); } - scanned_number = x; return true; } @@ -128,16 +139,14 @@ Token::Value Scanner::next() bool Scanner::skipWhitespace() { const int start_position = getSourcePos(); - - while (true) { - if (IsLineTerminator(m_char)) { - m_hasLineTerminatorBeforeNext = true; - } else if (!IsWhiteSpace(m_char)) { - break; - } - advance(); + while (true) + { + if (IsLineTerminator(m_char)) + m_hasLineTerminatorBeforeNext = true; + else if (!IsWhiteSpace(m_char)) + break; + advance(); } - // Return whether or not we skipped any characters. return getSourcePos() != start_position; } @@ -145,24 +154,24 @@ bool Scanner::skipWhitespace() Token::Value Scanner::skipSingleLineComment() { - // The line terminator at the end of the line is not considered - // to be part of the single-line comment; it is recognized - // separately by the lexical grammar and becomes part of the - // stream of input elements for the syntactic grammar - while (advance() && !IsLineTerminator(m_char)) { }; - - return Token::WHITESPACE; + // The line terminator at the end of the line is not considered + // to be part of the single-line comment; it is recognized + // separately by the lexical grammar and becomes part of the + // stream of input elements for the syntactic grammar + while (advance() && !IsLineTerminator(m_char)) { }; + return Token::WHITESPACE; } Token::Value Scanner::skipMultiLineComment() { BOOST_ASSERT(m_char == '*'); advance(); - - while (!isSourcePastEndOfInput()) { + while (!isSourcePastEndOfInput()) + { char ch = m_char; advance(); - if (IsLineTerminator(ch)) { + if (IsLineTerminator(ch)) + { // Following ECMA-262, section 7.4, a comment containing // a newline will make the comment count as a line-terminator. m_hasMultilineCommentBeforeNext = true; @@ -170,274 +179,250 @@ Token::Value Scanner::skipMultiLineComment() // If we have reached the end of the multi-line comment, we // consume the '/' and insert a whitespace. This way all // multi-line comments are treated as whitespace. - if (ch == '*' && m_char == '/') { + if (ch == '*' && m_char == '/') + { m_char = ' '; return Token::WHITESPACE; } } - // Unterminated multi-line comment. return Token::ILLEGAL; } void Scanner::scanToken() { - m_next_token.literal.clear(); - Token::Value token; - do { - // Remember the position of the next token - m_next_token.location.start = getSourcePos(); - - switch (m_char) { - case '\n': - m_hasLineTerminatorBeforeNext = true; // fall-through - case ' ': - case '\t': - token = selectToken(Token::WHITESPACE); - break; - - case '"': case '\'': - token = scanString(); - break; - - case '<': - // < <= << <<= - advance(); - if (m_char == '=') { - token = selectToken(Token::LTE); - } else if (m_char == '<') { - token = selectToken('=', Token::ASSIGN_SHL, Token::SHL); - } else { - token = Token::LT; - } - break; - - case '>': - // > >= >> >>= >>> >>>= - advance(); - if (m_char == '=') { - token = selectToken(Token::GTE); - } else if (m_char == '>') { - // >> >>= >>> >>>= - advance(); - if (m_char == '=') { - token = selectToken(Token::ASSIGN_SAR); - } else if (m_char == '>') { - token = selectToken('=', Token::ASSIGN_SHR, Token::SHR); - } else { - token = Token::SAR; - } - } else { - token = Token::GT; - } - break; - - case '=': - // = == => - advance(); - if (m_char == '=') { - token = selectToken(Token::EQ); - } else if (m_char == '>') { - token = selectToken(Token::ARROW); - } else { - token = Token::ASSIGN; - } - break; - - case '!': - // ! != !== - advance(); - if (m_char == '=') { - token = selectToken(Token::NE); - } else { - token = Token::NOT; - } - break; - - case '+': - // + ++ += - advance(); - if (m_char == '+') { - token = selectToken(Token::INC); - } else if (m_char == '=') { - token = selectToken(Token::ASSIGN_ADD); - } else { - token = Token::ADD; - } - break; - - case '-': - // - -- -= - advance(); - if (m_char == '-') { - advance(); - token = Token::DEC; - } else if (m_char == '=') { - token = selectToken(Token::ASSIGN_SUB); - } else { - token = Token::SUB; - } - break; - - case '*': - // * *= - token = selectToken('=', Token::ASSIGN_MUL, Token::MUL); - break; - - case '%': - // % %= - token = selectToken('=', Token::ASSIGN_MOD, Token::MOD); - break; - - case '/': - // / // /* /= - advance(); - if (m_char == '/') { - token = skipSingleLineComment(); - } else if (m_char == '*') { - token = skipMultiLineComment(); - } else if (m_char == '=') { - token = selectToken(Token::ASSIGN_DIV); - } else { - token = Token::DIV; - } - break; - - case '&': - // & && &= - advance(); - if (m_char == '&') { - token = selectToken(Token::AND); - } else if (m_char == '=') { - token = selectToken(Token::ASSIGN_BIT_AND); - } else { - token = Token::BIT_AND; - } - break; - - case '|': - // | || |= - advance(); - if (m_char == '|') { - token = selectToken(Token::OR); - } else if (m_char == '=') { - token = selectToken(Token::ASSIGN_BIT_OR); - } else { - token = Token::BIT_OR; + m_next_token.literal.clear(); + Token::Value token; + do + { + // Remember the position of the next token + m_next_token.location.start = getSourcePos(); + switch (m_char) + { + case '\n': + m_hasLineTerminatorBeforeNext = true; // fall-through + case ' ': + case '\t': + token = selectToken(Token::WHITESPACE); + break; + case '"': + case '\'': + token = scanString(); + break; + case '<': + // < <= << <<= + advance(); + if (m_char == '=') + token = selectToken(Token::LTE); + else if (m_char == '<') + token = selectToken('=', Token::ASSIGN_SHL, Token::SHL); + else + token = Token::LT; + break; + case '>': + // > >= >> >>= >>> >>>= + advance(); + if (m_char == '=') + token = selectToken(Token::GTE); + else if (m_char == '>') + { + // >> >>= >>> >>>= + advance(); + if (m_char == '=') + token = selectToken(Token::ASSIGN_SAR); + else if (m_char == '>') + token = selectToken('=', Token::ASSIGN_SHR, Token::SHR); + else + token = Token::SAR; + } + else + token = Token::GT; + break; + case '=': + // = == => + advance(); + if (m_char == '=') + token = selectToken(Token::EQ); + else if (m_char == '>') + token = selectToken(Token::ARROW); + else + token = Token::ASSIGN; + break; + case '!': + // ! != + advance(); + if (m_char == '=') + token = selectToken(Token::NE); + else + token = Token::NOT; + break; + case '+': + // + ++ += + advance(); + if (m_char == '+') + token = selectToken(Token::INC); + else if (m_char == '=') + token = selectToken(Token::ASSIGN_ADD); + else + token = Token::ADD; + break; + case '-': + // - -- -= + advance(); + if (m_char == '-') + { + advance(); + token = Token::DEC; + } + else if (m_char == '=') + token = selectToken(Token::ASSIGN_SUB); + else + token = Token::SUB; + break; + case '*': + // * *= + token = selectToken('=', Token::ASSIGN_MUL, Token::MUL); + break; + case '%': + // % %= + token = selectToken('=', Token::ASSIGN_MOD, Token::MOD); + break; + case '/': + // / // /* /= + advance(); + if (m_char == '/') + token = skipSingleLineComment(); + else if (m_char == '*') + token = skipMultiLineComment(); + else if (m_char == '=') + token = selectToken(Token::ASSIGN_DIV); + else + token = Token::DIV; + break; + case '&': + // & && &= + advance(); + if (m_char == '&') + token = selectToken(Token::AND); + else if (m_char == '=') + token = selectToken(Token::ASSIGN_BIT_AND); + else + token = Token::BIT_AND; + break; + case '|': + // | || |= + advance(); + if (m_char == '|') + token = selectToken(Token::OR); + else if (m_char == '=') + token = selectToken(Token::ASSIGN_BIT_OR); + else + token = Token::BIT_OR; + break; + case '^': + // ^ ^= + token = selectToken('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR); + break; + case '.': + // . Number + advance(); + if (IsDecimalDigit(m_char)) + token = scanNumber(true); + else + token = Token::PERIOD; + break; + case ':': + token = selectToken(Token::COLON); + break; + case ';': + token = selectToken(Token::SEMICOLON); + break; + case ',': + token = selectToken(Token::COMMA); + break; + case '(': + token = selectToken(Token::LPAREN); + break; + case ')': + token = selectToken(Token::RPAREN); + break; + case '[': + token = selectToken(Token::LBRACK); + break; + case ']': + token = selectToken(Token::RBRACK); + break; + case '{': + token = selectToken(Token::LBRACE); + break; + case '}': + token = selectToken(Token::RBRACE); + break; + case '?': + token = selectToken(Token::CONDITIONAL); + break; + case '~': + token = selectToken(Token::BIT_NOT); + break; + default: + if (IsIdentifierStart(m_char)) + token = scanIdentifierOrKeyword(); + else if (IsDecimalDigit(m_char)) + token = scanNumber(false); + else if (skipWhitespace()) + token = Token::WHITESPACE; + else if (isSourcePastEndOfInput()) + token = Token::EOS; + else + token = selectToken(Token::ILLEGAL); + break; } - break; - - case '^': - // ^ ^= - token = selectToken('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR); - break; - - case '.': - // . Number - advance(); - if (IsDecimalDigit(m_char)) { - token = scanNumber(true); - } else { - token = Token::PERIOD; - } - break; - - case ':': - token = selectToken(Token::COLON); - break; - - case ';': - token = selectToken(Token::SEMICOLON); - break; - - case ',': - token = selectToken(Token::COMMA); - break; - - case '(': - token = selectToken(Token::LPAREN); - break; - - case ')': - token = selectToken(Token::RPAREN); - break; - - case '[': - token = selectToken(Token::LBRACK); - break; - - case ']': - token = selectToken(Token::RBRACK); - break; - - case '{': - token = selectToken(Token::LBRACE); - break; - - case '}': - token = selectToken(Token::RBRACE); - break; - - case '?': - token = selectToken(Token::CONDITIONAL); - break; - - case '~': - token = selectToken(Token::BIT_NOT); - break; - - default: - if (IsIdentifierStart(m_char)) { - token = scanIdentifierOrKeyword(); - } else if (IsDecimalDigit(m_char)) { - token = scanNumber(false); - } else if (skipWhitespace()) { - token = Token::WHITESPACE; - } else if (isSourcePastEndOfInput()) { - token = Token::EOS; - } else { - token = selectToken(Token::ILLEGAL); - } - break; + // Continue scanning for tokens as long as we're just skipping + // whitespace. } - - // Continue scanning for tokens as long as we're just skipping - // whitespace. - } while (token == Token::WHITESPACE); - - m_next_token.location.end = getSourcePos(); - m_next_token.token = token; + while (token == Token::WHITESPACE); + m_next_token.location.end = getSourcePos(); + m_next_token.token = token; } bool Scanner::scanEscape() { char c = m_char; advance(); - // Skip escaped newlines. if (IsLineTerminator(c)) return true; - - switch (c) { + switch (c) + { case '\'': // fall through case '"' : // fall through - case '\\': break; - case 'b' : c = '\b'; break; - case 'f' : c = '\f'; break; - case 'n' : c = '\n'; break; - case 'r' : c = '\r'; break; - case 't' : c = '\t'; break; - case 'u' : { + case '\\': + break; + case 'b' : + c = '\b'; + break; + case 'f' : + c = '\f'; + break; + case 'n' : + c = '\n'; + break; + case 'r' : + c = '\r'; + break; + case 't' : + c = '\t'; + break; + case 'u' : if (!scanHexNumber(c, 4)) return false; break; - } - case 'v' : c = '\v'; break; - case 'x' : { + case 'v' : + c = '\v'; + break; + case 'x' : if (!scanHexNumber(c, 2)) return false; break; } - } - // According to ECMA-262, section 7.8.4, characters not covered by the // above cases should be illegal, but they are commonly handled as // non-escaped characters by JS VMs. @@ -449,20 +434,21 @@ Token::Value Scanner::scanString() { const char quote = m_char; advance(); // consume quote - LiteralScope literal(this); - while (m_char != quote && !isSourcePastEndOfInput() && !IsLineTerminator(m_char)) { + while (m_char != quote && !isSourcePastEndOfInput() && !IsLineTerminator(m_char)) + { char c = m_char; advance(); - if (c == '\\') { - if (isSourcePastEndOfInput() || !scanEscape()) return Token::ILLEGAL; - } else { - addLiteralChar(c); + if (c == '\\') + { + if (isSourcePastEndOfInput() || !scanEscape()) + return Token::ILLEGAL; } + else + addLiteralChar(c); } if (m_char != quote) return Token::ILLEGAL; literal.Complete(); - advance(); // consume quote return Token::STRING_LITERAL; } @@ -477,71 +463,66 @@ void Scanner::scanDecimalDigits() Token::Value Scanner::scanNumber(bool _periodSeen) { - BOOST_ASSERT(IsDecimalDigit(m_char)); // the first digit of the number or the fraction - - enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL; - - LiteralScope literal(this); - if (_periodSeen) { - // we have already seen a decimal point of the float - addLiteralChar('.'); - scanDecimalDigits(); // we know we have at least one digit - } else { - // if the first character is '0' we must check for octals and hex - if (m_char == '0') { - addLiteralCharAndAdvance(); - - // either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or - // an octal number. - if (m_char == 'x' || m_char == 'X') { - // hex number - kind = HEX; - addLiteralCharAndAdvance(); - if (!IsHexDigit(m_char)) { - // we must have at least one hex digit after 'x'/'X' - return Token::ILLEGAL; + BOOST_ASSERT(IsDecimalDigit(m_char)); // the first digit of the number or the fraction + enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL; + LiteralScope literal(this); + if (_periodSeen) + { + // we have already seen a decimal point of the float + addLiteralChar('.'); + scanDecimalDigits(); // we know we have at least one digit + } + else + { + // if the first character is '0' we must check for octals and hex + if (m_char == '0') + { + addLiteralCharAndAdvance(); + // either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or + // an octal number. + if (m_char == 'x' || m_char == 'X') + { + // hex number + kind = HEX; + addLiteralCharAndAdvance(); + if (!IsHexDigit(m_char)) + return Token::ILLEGAL; // we must have at least one hex digit after 'x'/'X' + while (IsHexDigit(m_char)) + addLiteralCharAndAdvance(); + } } - while (IsHexDigit(m_char)) { - addLiteralCharAndAdvance(); + // Parse decimal digits and allow trailing fractional part. + if (kind == DECIMAL) + { + scanDecimalDigits(); // optional + if (m_char == '.') + { + addLiteralCharAndAdvance(); + scanDecimalDigits(); // optional + } } - } } - - // Parse decimal digits and allow trailing fractional part. - if (kind == DECIMAL) { - scanDecimalDigits(); // optional - if (m_char == '.') { + // scan exponent, if any + if (m_char == 'e' || m_char == 'E') + { + BOOST_ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number + if (kind != DECIMAL) return Token::ILLEGAL; + // scan exponent addLiteralCharAndAdvance(); - scanDecimalDigits(); // optional - } + if (m_char == '+' || m_char == '-') + addLiteralCharAndAdvance(); + if (!IsDecimalDigit(m_char)) + return Token::ILLEGAL; // we must have at least one decimal digit after 'e'/'E' + scanDecimalDigits(); } - } - - // scan exponent, if any - if (m_char == 'e' || m_char == 'E') { - BOOST_ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number - if (kind != DECIMAL) return Token::ILLEGAL; - // scan exponent - addLiteralCharAndAdvance(); - if (m_char == '+' || m_char == '-') - addLiteralCharAndAdvance(); - if (!IsDecimalDigit(m_char)) { - // we must have at least one decimal digit after 'e'/'E' - return Token::ILLEGAL; - } - scanDecimalDigits(); - } - - // The source character immediately following a numeric literal must - // not be an identifier start or a decimal digit; see ECMA-262 - // section 7.8.3, page 17 (note that we read only one decimal digit - // if the value is 0). - if (IsDecimalDigit(m_char) || IsIdentifierStart(m_char)) - return Token::ILLEGAL; - - literal.Complete(); - - return Token::NUMBER; + // The source character immediately following a numeric literal must + // not be an identifier start or a decimal digit; see ECMA-262 + // section 7.8.3, page 17 (note that we read only one decimal digit + // if the value is 0). + if (IsDecimalDigit(m_char) || IsIdentifierStart(m_char)) + return Token::ILLEGAL; + literal.Complete(); + return Token::NUMBER; } @@ -549,130 +530,126 @@ Token::Value Scanner::scanNumber(bool _periodSeen) // 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("catch", Token::CATCH) \ - KEYWORD("const", Token::CONST) \ - KEYWORD("continue", Token::CONTINUE) \ - KEYWORD("contract", Token::CONTRACT) \ - KEYWORD_GROUP('d') \ - KEYWORD("debugger", Token::DEBUGGER) \ - KEYWORD("default", Token::DEFAULT) \ - KEYWORD("delete", Token::DELETE) \ - KEYWORD("do", Token::DO) \ - KEYWORD_GROUP('e') \ - KEYWORD("else", Token::ELSE) \ - KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \ - KEYWORD_GROUP('f') \ - KEYWORD("false", Token::FALSE_LITERAL) \ - KEYWORD("finally", Token::FINALLY) \ - KEYWORD("for", Token::FOR) \ - KEYWORD("function", Token::FUNCTION) \ - KEYWORD_GROUP('h') \ - KEYWORD("hash", Token::HASH) \ - KEYWORD("hash32", Token::HASH32) \ - KEYWORD("hash64", Token::HASH64) \ - KEYWORD("hash128", Token::HASH128) \ - KEYWORD("hash256", Token::HASH256) \ - KEYWORD_GROUP('i') \ - KEYWORD("if", Token::IF) \ - KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \ - KEYWORD("in", Token::IN) \ - KEYWORD("instanceof", Token::INSTANCEOF) \ - KEYWORD("int", Token::INT) \ - KEYWORD("int32", Token::INT32) \ - KEYWORD("int64", Token::INT64) \ - KEYWORD("int128", Token::INT128) \ - KEYWORD("int256", Token::INT256) \ - KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \ - 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("package", Token::FUTURE_STRICT_RESERVED_WORD) \ - KEYWORD("private", Token::PRIVATE) \ - KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \ - 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("this", Token::THIS) \ - KEYWORD("throw", Token::THROW) \ - KEYWORD("true", Token::TRUE_LITERAL) \ - KEYWORD("try", Token::TRY) \ - KEYWORD("typeof", Token::TYPEOF) \ - KEYWORD_GROUP('u') \ - KEYWORD("uint", Token::UINT) \ - KEYWORD("uint32", Token::UINT32) \ - KEYWORD("uint64", Token::UINT64) \ - KEYWORD("uint128", Token::UINT128) \ - KEYWORD("uint256", Token::UINT256) \ - KEYWORD("ureal", Token::UREAL) \ - KEYWORD_GROUP('v') \ - KEYWORD("var", Token::VAR) \ - KEYWORD("void", Token::VOID) \ - KEYWORD_GROUP('w') \ - KEYWORD("while", Token::WHILE) \ - KEYWORD("with", Token::WITH) + 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("catch", Token::CATCH) \ + KEYWORD("const", Token::CONST) \ + KEYWORD("continue", Token::CONTINUE) \ + KEYWORD("contract", Token::CONTRACT) \ + KEYWORD_GROUP('d') \ + KEYWORD("debugger", Token::DEBUGGER) \ + KEYWORD("default", Token::DEFAULT) \ + KEYWORD("delete", Token::DELETE) \ + KEYWORD("do", Token::DO) \ + KEYWORD_GROUP('e') \ + KEYWORD("else", Token::ELSE) \ + KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \ + KEYWORD_GROUP('f') \ + KEYWORD("false", Token::FALSE_LITERAL) \ + KEYWORD("finally", Token::FINALLY) \ + KEYWORD("for", Token::FOR) \ + KEYWORD("function", Token::FUNCTION) \ + KEYWORD_GROUP('h') \ + KEYWORD("hash", Token::HASH) \ + KEYWORD("hash32", Token::HASH32) \ + KEYWORD("hash64", Token::HASH64) \ + KEYWORD("hash128", Token::HASH128) \ + KEYWORD("hash256", Token::HASH256) \ + KEYWORD_GROUP('i') \ + KEYWORD("if", Token::IF) \ + KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD("in", Token::IN) \ + KEYWORD("instanceof", Token::INSTANCEOF) \ + KEYWORD("int", Token::INT) \ + KEYWORD("int32", Token::INT32) \ + KEYWORD("int64", Token::INT64) \ + KEYWORD("int128", Token::INT128) \ + KEYWORD("int256", Token::INT256) \ + KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \ + 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("package", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD("private", Token::PRIVATE) \ + KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \ + 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("this", Token::THIS) \ + KEYWORD("throw", Token::THROW) \ + KEYWORD("true", Token::TRUE_LITERAL) \ + KEYWORD("try", Token::TRY) \ + KEYWORD("typeof", Token::TYPEOF) \ + KEYWORD_GROUP('u') \ + KEYWORD("uint", Token::UINT) \ + KEYWORD("uint32", Token::UINT32) \ + KEYWORD("uint64", Token::UINT64) \ + KEYWORD("uint128", Token::UINT128) \ + KEYWORD("uint256", Token::UINT256) \ + KEYWORD("ureal", Token::UREAL) \ + KEYWORD_GROUP('v') \ + KEYWORD("var", Token::VAR) \ + KEYWORD("void", Token::VOID) \ + KEYWORD_GROUP('w') \ + KEYWORD("while", Token::WHILE) \ + KEYWORD("with", Token::WITH) static Token::Value KeywordOrIdentifierToken(const std::string& input) { - BOOST_ASSERT(!input.empty()); - const int kMinLength = 2; - const int kMaxLength = 10; - if (input.size() < kMinLength || input.size() > kMaxLength) { - return Token::IDENTIFIER; - } - switch (input[0]) { + BOOST_ASSERT(!input.empty()); + const int kMinLength = 2; + const int kMaxLength = 10; + if (input.size() < kMinLength || input.size() > kMaxLength) + return Token::IDENTIFIER; + switch (input[0]) + { default: #define KEYWORD_GROUP_CASE(ch) \ - break; \ - 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. */ \ - const int keyword_length = sizeof(keyword) - 1; \ - BOOST_STATIC_ASSERT(keyword_length >= kMinLength); \ - BOOST_STATIC_ASSERT(keyword_length <= kMaxLength); \ - if (input == keyword) { \ - return token; \ - } \ + /* 'keyword' is a char array, so sizeof(keyword) is */ \ + /* strlen(keyword) plus 1 for the NUL char. */ \ + const int keyword_length = sizeof(keyword) - 1; \ + BOOST_STATIC_ASSERT(keyword_length >= kMinLength); \ + BOOST_STATIC_ASSERT(keyword_length <= kMaxLength); \ + if (input == keyword) { \ + return token; \ + } \ } - KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD) - } - return Token::IDENTIFIER; + KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD) + } + return Token::IDENTIFIER; } Token::Value Scanner::scanIdentifierOrKeyword() { BOOST_ASSERT(IsIdentifierStart(m_char)); LiteralScope literal(this); - addLiteralCharAndAdvance(); - // Scan the rest of the identifier characters. while (IsIdentifierPart(m_char)) addLiteralCharAndAdvance(); - literal.Complete(); - return KeywordOrIdentifierToken(m_next_token.literal); } @@ -697,17 +674,17 @@ std::tuple<int, int> CharStream::translatePositionToLineColumn(int _position) co using size_type = std::string::size_type; size_type searchPosition = std::min<size_type>(m_source.size(), _position); int lineNumber = std::count(m_source.begin(), m_source.begin() + searchPosition, '\n'); - size_type lineStart; - if (searchPosition == 0) { + if (searchPosition == 0) lineStart = 0; - } else { + else + { lineStart = m_source.rfind('\n', searchPosition - 1); lineStart = lineStart == std::string::npos ? 0 : lineStart + 1; } - return std::tuple<int, int>(lineNumber, searchPosition - lineStart); } -} } +} +} @@ -50,33 +50,36 @@ #include <libsolidity/BaseTypes.h> #include <libsolidity/Token.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ class AstRawString; class AstValueFactory; class ParserRecorder; -class CharStream { +class CharStream +{ public: CharStream() : m_pos(0) {} - explicit CharStream(const std::string& _source) - : m_source(_source), m_pos(0) - {} + explicit CharStream(const std::string& _source) : m_source(_source), m_pos(0) {} int getPos() const { return m_pos; } bool isPastEndOfInput() const { return m_pos >= m_source.size(); } char get() const { return m_source[m_pos]; } - char advanceAndGet() { + char advanceAndGet() + { if (isPastEndOfInput()) return 0; ++m_pos; if (isPastEndOfInput()) return 0; return get(); } - char rollback(size_t _amount) { + char rollback(size_t _amount) + { BOOST_ASSERT(m_pos >= _amount); m_pos -= _amount; return get(); @@ -96,22 +99,17 @@ private: // ---------------------------------------------------------------------------- // JavaScript Scanner. -class Scanner { +class Scanner +{ public: // Scoped helper for literal recording. Automatically drops the literal // if aborting the scanning before it's complete. - class LiteralScope { + class LiteralScope + { public: - explicit LiteralScope(Scanner* self) - : scanner_(self), complete_(false) { - scanner_->startNewLiteral(); - } - ~LiteralScope() { - if (!complete_) scanner_->dropLiteral(); - } - void Complete() { - complete_ = true; - } + explicit LiteralScope(Scanner* self) : scanner_(self), complete_(false) { scanner_->startNewLiteral(); } + ~LiteralScope() { if (!complete_) scanner_->dropLiteral(); } + void Complete() { complete_ = true; } private: Scanner* scanner_; @@ -143,7 +141,10 @@ public: /// Functions that help pretty-printing parse errors. /// Do only use in error cases, they are quite expensive. /// @{ - std::string getLineAtPosition(int _position) const { return m_source.getLineAtPosition(_position); } + std::string getLineAtPosition(int _position) const + { + return m_source.getLineAtPosition(_position); + } std::tuple<int, int> translatePositionToLineColumn(int _position) const { return m_source.translatePositionToLineColumn(_position); @@ -152,56 +153,46 @@ public: // Returns true if there was a line terminator before the peek'ed token, // possibly inside a multi-line comment. - bool hasAnyLineTerminatorBeforeNext() const { + bool hasAnyLineTerminatorBeforeNext() const + { return m_hasLineTerminatorBeforeNext || - m_hasMultilineCommentBeforeNext; + m_hasMultilineCommentBeforeNext; } private: // Used for the current and look-ahead token. - struct TokenDesc { + struct TokenDesc + { Token::Value token; Location location; std::string literal; }; // Literal buffer support - inline void startNewLiteral() { - m_next_token.literal.clear(); - } + inline void startNewLiteral() { m_next_token.literal.clear(); } - inline void addLiteralChar(char c) { - m_next_token.literal.push_back(c); - } + inline void addLiteralChar(char c) { m_next_token.literal.push_back(c); } - inline void dropLiteral() { - m_next_token.literal.clear(); - } + inline void dropLiteral() { m_next_token.literal.clear(); } - inline void addLiteralCharAndAdvance() { - addLiteralChar(m_char); - advance(); - } + inline void addLiteralCharAndAdvance() { addLiteralChar(m_char); advance(); } // Low-level scanning support. bool advance() { m_char = m_source.advanceAndGet(); return !m_source.isPastEndOfInput(); } - void rollback(int amount) { - m_char = m_source.rollback(amount); - } + void rollback(int amount) { m_char = m_source.rollback(amount); } - inline Token::Value selectToken(Token::Value tok) { - advance(); - return tok; - } + inline Token::Value selectToken(Token::Value tok) { advance(); return tok; } - inline Token::Value selectToken(char next, Token::Value then, Token::Value else_) { + inline Token::Value selectToken(char next, Token::Value then, Token::Value else_) + { advance(); - if (m_char == next) { + if (m_char == next) + { advance(); return then; - } else { - return else_; } + else + return else_; } bool scanHexNumber(char& scanned_number, int expected_length); @@ -225,12 +216,8 @@ private: bool scanEscape(); // Return the current source position. - int getSourcePos() { - return m_source.getPos(); - } - bool isSourcePastEndOfInput() { - return m_source.isPastEndOfInput(); - } + int getSourcePos() { return m_source.getPos(); } + bool isSourcePastEndOfInput() { return m_source.isPastEndOfInput(); } TokenDesc m_current_token; // desc for current token (as returned by Next()) TokenDesc m_next_token; // desc for next token (one token look-ahead) @@ -249,4 +236,5 @@ private: bool m_hasMultilineCommentBeforeNext; }; -} } +} +} @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -23,8 +23,10 @@ #include <libsolidity/Scope.h> #include <libsolidity/AST.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ bool Scope::registerDeclaration(Declaration& _declaration) @@ -35,7 +37,7 @@ bool Scope::registerDeclaration(Declaration& _declaration) return true; } -Declaration*Scope::resolveName(ASTString const& _name, bool _recursive) const +Declaration* Scope::resolveName(ASTString const& _name, bool _recursive) const { auto result = m_declarations.find(_name); if (result != m_declarations.end()) @@ -45,4 +47,5 @@ Declaration*Scope::resolveName(ASTString const& _name, bool _recursive) const return nullptr; } -} } +} +} @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -28,8 +28,10 @@ #include <libsolidity/ASTForward.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ class Scope { @@ -46,4 +48,5 @@ private: std::map<ASTString, Declaration*> m_declarations; }; -} } +} +} @@ -42,25 +42,30 @@ #include <libsolidity/Token.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ #define T(name, string, precedence) #name, -const char* const Token::m_name[NUM_TOKENS] = { +const char* const Token::m_name[NUM_TOKENS] = +{ TOKEN_LIST(T, T) }; #undef T #define T(name, string, precedence) string, -const char* const Token::m_string[NUM_TOKENS] = { +const char* const Token::m_string[NUM_TOKENS] = +{ TOKEN_LIST(T, T) }; #undef T #define T(name, string, precedence) precedence, -const int8_t Token::m_precedence[NUM_TOKENS] = { +const int8_t Token::m_precedence[NUM_TOKENS] = +{ TOKEN_LIST(T, T) }; #undef T @@ -68,10 +73,12 @@ const int8_t Token::m_precedence[NUM_TOKENS] = { #define KT(a, b, c) 'T', #define KK(a, b, c) 'K', -const char Token::m_tokenType[] = { +const char Token::m_tokenType[] = +{ TOKEN_LIST(KT, KK) }; #undef KT #undef KK -} } +} +} @@ -47,8 +47,10 @@ #include <libdevcore/Common.h> #include <libdevcore/Log.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ // TOKEN_LIST takes a list of 3 macros M, all of which satisfy the // same signature M(name, string, precedence), where name is the @@ -68,7 +70,7 @@ namespace solidity { #define TOKEN_LIST(T, K) \ /* End of source indicator. */ \ T(EOS, "EOS", 0) \ - \ + \ /* Punctuators (ECMA-262, section 7.7, page 15). */ \ T(LPAREN, "(", 0) \ T(RPAREN, ")", 0) \ @@ -83,7 +85,7 @@ namespace solidity { T(INC, "++", 0) \ T(DEC, "--", 0) \ T(ARROW, "=>", 0) \ - \ + \ /* Assignment operators. */ \ /* IsAssignmentOp() and Assignment::is_compound() relies on */ \ /* this block of enum values being contiguous and sorted in the */ \ @@ -105,7 +107,7 @@ namespace solidity { T(ASSIGN_MUL, "*=", 2) \ T(ASSIGN_DIV, "/=", 2) \ T(ASSIGN_MOD, "%=", 2) \ - \ + \ /* Binary operators sorted by precedence. */ \ /* IsBinaryOp() relies on this block of enum values */ \ /* being contiguous and sorted in the same order! */ \ @@ -123,7 +125,7 @@ namespace solidity { T(MUL, "*", 13) \ T(DIV, "/", 13) \ T(MOD, "%", 13) \ - \ + \ /* Compare operators sorted by precedence. */ \ /* IsCompareOp() relies on this block of enum values */ \ /* being contiguous and sorted in the same order! */ \ @@ -137,7 +139,7 @@ namespace solidity { T(GTE, ">=", 10) \ K(INSTANCEOF, "instanceof", 10) \ K(IN, "in", 10) \ - \ + \ /* Unary operators. */ \ /* IsUnaryOp() relies on this block of enum values */ \ /* being contiguous and sorted in the same order! */ \ @@ -146,7 +148,7 @@ namespace solidity { K(DELETE, "delete", 0) \ K(TYPEOF, "typeof", 0) \ K(VOID, "void", 0) \ - \ + \ /* Keywords (ECMA-262, section 7.5.2, page 13). */ \ K(BREAK, "break", 0) \ K(CASE, "case", 0) \ @@ -180,7 +182,7 @@ namespace solidity { /* VOID */ \ K(WHILE, "while", 0) \ K(WITH, "with", 0) \ - \ + \ /* type keywords, keep them in this order, keep int as first keyword * the implementation in Types.cpp has to be synced to this here * TODO more to be added */ \ @@ -206,17 +208,17 @@ namespace solidity { K(REAL, "real", 0) \ K(UREAL, "ureal", 0) \ T(TYPES_END, NULL, 0) /* used as type enum end marker */ \ - \ + \ /* Literals (ECMA-262, section 7.8, page 16). */ \ K(NULL_LITERAL, "null", 0) \ K(TRUE_LITERAL, "true", 0) \ K(FALSE_LITERAL, "false", 0) \ T(NUMBER, NULL, 0) \ T(STRING_LITERAL, NULL, 0) \ - \ + \ /* Identifiers (not keywords or future reserved words). */ \ T(IDENTIFIER, NULL, 0) \ - \ + \ /* Future reserved words (ECMA-262, section 7.6.1.2). */ \ T(FUTURE_RESERVED_WORD, NULL, 0) \ T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \ @@ -227,21 +229,23 @@ namespace solidity { K(IMPORT, "import", 0) \ K(LET, "let", 0) \ K(STATIC, "static", 0) \ -/* K(YIELD, "yield", 0) */ \ + /* K(YIELD, "yield", 0) */ \ K(SUPER, "super", 0) \ - \ + \ /* Illegal token - not able to scan. */ \ T(ILLEGAL, "ILLEGAL", 0) \ - \ + \ /* Scanner-internal use only. */ \ T(WHITESPACE, NULL, 0) -class Token { +class Token +{ public: // All token values. #define T(name, string, precedence) name, - enum Value { + enum Value + { TOKEN_LIST(T, T) NUM_TOKENS }; @@ -249,123 +253,110 @@ public: // Returns a string corresponding to the C++ token name // (e.g. "LT" for the token LT). - static const char* Name(Value tok) { + static const char* getName(Value tok) + { BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned return m_name[tok]; } // 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 INIT_VAR <= 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 IsCompareOp(Value op) { - return EQ <= op && op <= IN; - } - - static bool IsOrderedRelationalCompareOp(Value op) { + 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 INIT_VAR <= 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 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 || op == EQ_STRICT; - } - - static bool IsInequalityOp(Value op) { - return op == NE || op == NE_STRICT; + static bool isEqualityOp(Value op) { return op == EQ || op == EQ_STRICT; } + static bool isInequalityOp(Value op) { return op == NE || op == NE_STRICT; } + static bool isArithmeticCompareOp(Value op) + { + return isOrderedRelationalCompareOp(op) || + isEqualityOp(op) || isInequalityOp(op); } - static bool IsArithmeticCompareOp(Value op) { - return IsOrderedRelationalCompareOp(op) || - IsEqualityOp(op) || IsInequalityOp(op); - } - - static Value NegateCompareOp(Value op) { - BOOST_ASSERT(IsArithmeticCompareOp(op)); - switch (op) { - case EQ: return NE; - case NE: return EQ; - case EQ_STRICT: return NE_STRICT; - case NE_STRICT: return EQ_STRICT; - case LT: return GTE; - case GT: return LTE; - case LTE: return GT; - case GTE: return LT; + static Value negateCompareOp(Value op) + { + BOOST_ASSERT(isArithmeticCompareOp(op)); + switch (op) + { + case EQ: + return NE; + case NE: + return EQ; + case EQ_STRICT: + return NE_STRICT; + case NE_STRICT: + return EQ_STRICT; + case LT: + return GTE; + case GT: + return LTE; + case LTE: + return GT; + case GTE: + return LT; default: BOOST_ASSERT(false); // should not get here return op; } } - static Value ReverseCompareOp(Value op) { - BOOST_ASSERT(IsArithmeticCompareOp(op)); - switch (op) { - case EQ: return EQ; - case NE: return NE; - case EQ_STRICT: return EQ_STRICT; - case NE_STRICT: return NE_STRICT; - case LT: return GT; - case GT: return LT; - case LTE: return GTE; - case GTE: return LTE; + static Value reverseCompareOp(Value op) + { + BOOST_ASSERT(isArithmeticCompareOp(op)); + switch (op) + { + case EQ: + return EQ; + case NE: + return NE; + case EQ_STRICT: + return EQ_STRICT; + case NE_STRICT: + return NE_STRICT; + case LT: + return GT; + case GT: + return LT; + case LTE: + return GTE; + case GTE: + return LTE; default: BOOST_ASSERT(false); // should not get here return op; } } - static Value AssignmentToBinaryOp(Value op) { - BOOST_ASSERT(IsAssignmentOp(op) && op != ASSIGN); + static Value AssignmentToBinaryOp(Value op) + { + BOOST_ASSERT(isAssignmentOp(op) && op != ASSIGN); return Token::Value(op + (BIT_OR - ASSIGN_BIT_OR)); } - static bool IsBitOp(Value op) { - return (BIT_OR <= op && op <= SHR) || op == BIT_NOT; - } - - static bool IsUnaryOp(Value op) { - return (NOT <= op && op <= VOID) || op == ADD || op == SUB; - } - - static bool IsCountOp(Value op) { - return op == INC || op == DEC; - } - - static bool IsShiftOp(Value op) { - return (SHL <= op) && (op <= SHR); - } + static bool isBitOp(Value op) { return (BIT_OR <= op && op <= SHR) || op == BIT_NOT; } + static bool isUnaryOp(Value op) { return (NOT <= op && op <= VOID) || op == ADD || op == SUB; } + static bool isCountOp(Value op) { return op == INC || op == DEC; } + static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } // Returns a string corresponding to the JS token string // (.e., "<" for the token LT) or NULL if the token doesn't // have a (unique) string (e.g. an IDENTIFIER). - static const char* String(Value tok) { + static const char* toString(Value tok) + { BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned. return m_string[tok]; } // Returns the precedence > 0 for binary and compare // operators; returns 0 otherwise. - static int Precedence(Value tok) { + static int precedence(Value tok) + { BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned. return m_precedence[tok]; } @@ -377,4 +368,5 @@ private: static const char m_tokenType[NUM_TOKENS]; }; -} } +} +} @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -23,12 +23,15 @@ #include <libsolidity/Types.h> #include <libsolidity/AST.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken) { - if (Token::INT <= _typeToken && _typeToken <= Token::HASH256) { + if (Token::INT <= _typeToken && _typeToken <= Token::HASH256) + { int offset = _typeToken - Token::INT; int bits = offset % 5; if (bits == 0) @@ -39,15 +42,14 @@ ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken) return std::make_shared<IntegerType>(bits, modifier == 0 ? IntegerType::Modifier::SIGNED : modifier == 1 ? IntegerType::Modifier::UNSIGNED : - IntegerType::Modifier::HASH); - } else if (_typeToken == Token::ADDRESS) { + IntegerType::Modifier::HASH); + } + else if (_typeToken == Token::ADDRESS) return std::make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS); - } else if (_typeToken == Token::BOOL) { + else if (_typeToken == Token::BOOL) return std::make_shared<BoolType>(); - } else { - BOOST_ASSERT(false); - // @todo add other tyes - } + else + BOOST_ASSERT(false); // @todo add other tyes } ptr<Type> Type::fromUserDefinedTypeName(const UserDefinedTypeName& _typeName) @@ -63,7 +65,8 @@ ptr<Type> Type::fromMapping(const Mapping&) ptr<Type> Type::forLiteral(const Literal& _literal) { - switch (_literal.getToken()) { + switch (_literal.getToken()) + { case Token::TRUE_LITERAL: case Token::FALSE_LITERAL: return std::make_shared<BoolType>(); @@ -114,13 +117,12 @@ bool IntegerType::isExplicitlyConvertibleTo(const Type& _convertTo) const bool IntegerType::acceptsBinaryOperator(Token::Value _operator) const { - if (isAddress()) { - return Token::IsCompareOp(_operator); - } else if (isHash()) { - return Token::IsCompareOp(_operator) || Token::IsBitOp(_operator); - } else { + if (isAddress()) + return Token::isCompareOp(_operator); + else if (isHash()) + return Token::isCompareOp(_operator) || Token::isBitOp(_operator); + else return true; - } } bool IntegerType::acceptsUnaryOperator(Token::Value _operator) const @@ -132,7 +134,8 @@ bool BoolType::isExplicitlyConvertibleTo(const Type& _convertTo) const { // conversion to integer is fine, but not to address // this is an example of explicit conversions being not transitive (though implicit should be) - if (_convertTo.getCategory() == Category::INTEGER) { + if (_convertTo.getCategory() == Category::INTEGER) + { IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo); if (!convertTo.isAddress()) return true; @@ -157,4 +160,5 @@ bool StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const } -} } +} +} @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -29,8 +29,10 @@ #include <libsolidity/Token.h> -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ // AST forward declarations class ContractDefinition; @@ -49,7 +51,8 @@ using ptr = std::shared_ptr<T>; class Type : private boost::noncopyable { public: - enum class Category { + enum class Category + { INTEGER, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE }; @@ -62,7 +65,10 @@ public: virtual Category getCategory() const = 0; virtual bool isImplicitlyConvertibleTo(const Type&) const { return false; } - virtual bool isExplicitlyConvertibleTo(const Type& _convertTo) const { return isImplicitlyConvertibleTo(_convertTo); } + virtual bool isExplicitlyConvertibleTo(const Type& _convertTo) const + { + return isImplicitlyConvertibleTo(_convertTo); + } virtual bool acceptsBinaryOperator(Token::Value) const { return false; } virtual bool acceptsUnaryOperator(Token::Value) const { return false; } }; @@ -70,7 +76,8 @@ public: class IntegerType : public Type { public: - enum class Modifier { + enum class Modifier + { UNSIGNED, SIGNED, HASH, ADDRESS }; virtual Category getCategory() const { return Category::INTEGER; } @@ -98,12 +105,18 @@ class BoolType : public Type public: virtual Category getCategory() const { return Category::BOOL; } virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override - { return _convertTo.getCategory() == Category::BOOL; } + { + return _convertTo.getCategory() == Category::BOOL; + } virtual bool isExplicitlyConvertibleTo(const Type& _convertTo) const override; virtual bool acceptsBinaryOperator(Token::Value _operator) const override - { return _operator == Token::AND || _operator == Token::OR; } + { + return _operator == Token::AND || _operator == Token::OR; + } virtual bool acceptsUnaryOperator(Token::Value _operator) const override - { return _operator == Token::NOT || _operator == Token::DELETE; } + { + return _operator == Token::NOT || _operator == Token::DELETE; + } }; class ContractType : public Type @@ -123,7 +136,9 @@ public: StructType(StructDefinition const& _struct) : m_struct(_struct) {} virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const; virtual bool acceptsUnaryOperator(Token::Value _operator) const override - { return _operator == Token::DELETE; } + { + return _operator == Token::DELETE; + } private: StructDefinition const& m_struct; }; @@ -168,4 +183,5 @@ private: }; -} } +} +} |