From 3fd9358c3e33e90261a4aec36a0d38e408e85496 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 9 Oct 2014 12:28:37 +0200 Subject: [PATCH] Corrected indentation. --- libsolidity/AST.cpp | 22 +- libsolidity/AST.h | 228 +++++----- libsolidity/BaseTypes.h | 10 +- libsolidity/Parser.cpp | 382 +++++++++-------- libsolidity/Parser.h | 73 ++-- libsolidity/Scanner.cpp | 894 ++++++++++++++++++++-------------------- libsolidity/Scanner.h | 354 ++++++++-------- libsolidity/Token.cpp | 8 +- libsolidity/Token.h | 594 +++++++++++++------------- 9 files changed, 1292 insertions(+), 1273 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index ba50b7c6f..76e1ff444 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** * @author Christian diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 86c5022d8..dad257f23 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** * @author Christian @@ -50,47 +50,47 @@ class Expression; class ASTNode { public: - explicit ASTNode(Location const& _location) - : m_location(_location) - {} + explicit ASTNode(Location const& _location) + : m_location(_location) + {} - Location getLocation() const { return m_location; } + Location getLocation() const { return m_location; } private: - Location m_location; + Location m_location; }; class ContractDefinition : public ASTNode { public: - ContractDefinition(Location const& _location, - std::string const& _name, - vecptr const& _definedStructs, - vecptr const& _stateVariables, - vecptr const& _definedFunctions) - : ASTNode(_location), m_name(_name), - m_definedStructs(_definedStructs), - m_stateVariables(_stateVariables), - m_definedFunctions(_definedFunctions) - {} + ContractDefinition(Location const& _location, + std::string const& _name, + vecptr const& _definedStructs, + vecptr const& _stateVariables, + vecptr const& _definedFunctions) + : ASTNode(_location), m_name(_name), + m_definedStructs(_definedStructs), + m_stateVariables(_stateVariables), + m_definedFunctions(_definedFunctions) + {} private: - std::string m_name; - vecptr m_definedStructs; - vecptr m_stateVariables; - vecptr m_definedFunctions; + std::string m_name; + vecptr m_definedStructs; + vecptr m_stateVariables; + vecptr m_definedFunctions; }; class StructDefinition : public ASTNode { public: - StructDefinition(Location const& _location, - std::string const& _name, - vecptr const& _members) - : ASTNode(_location), m_name(_name), m_members(_members) - {} + StructDefinition(Location const& _location, + std::string const& _name, + vecptr const& _members) + : ASTNode(_location), m_name(_name), m_members(_members) + {} private: - std::string m_name; - vecptr m_members; + std::string m_name; + vecptr m_members; }; /// Used as function parameter list and return list @@ -99,45 +99,45 @@ private: class ParameterList : public ASTNode { public: - ParameterList(Location const& _location, vecptr const& _parameters) - : ASTNode(_location), m_parameters(_parameters) - {} + ParameterList(Location const& _location, vecptr const& _parameters) + : ASTNode(_location), m_parameters(_parameters) + {} private: - vecptr m_parameters; + vecptr m_parameters; }; class FunctionDefinition : public ASTNode { public: - FunctionDefinition(Location const& _location, std::string const& _name, bool _isPublic, - ptr const& _parameters, - bool _isDeclaredConst, - ptr const& _returnParameters, - ptr const& _body) - : ASTNode(_location), m_name(_name), m_isPublic(_isPublic), m_parameters(_parameters), - m_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters), - m_body(_body) - {} + FunctionDefinition(Location const& _location, std::string const& _name, bool _isPublic, + ptr const& _parameters, + bool _isDeclaredConst, + ptr const& _returnParameters, + ptr const& _body) + : ASTNode(_location), m_name(_name), m_isPublic(_isPublic), m_parameters(_parameters), + m_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters), + m_body(_body) + {} private: - std::string m_name; - bool m_isPublic; - ptr m_parameters; - bool m_isDeclaredConst; - ptr m_returnParameters; - ptr m_body; + std::string m_name; + bool m_isPublic; + ptr m_parameters; + bool m_isDeclaredConst; + ptr m_returnParameters; + ptr m_body; }; class VariableDeclaration : public ASTNode { public: - VariableDeclaration(Location const& _location, - ptr const& _type, - std::string const& _name) - : ASTNode(_location), m_type(_type), m_name(_name) - {} + VariableDeclaration(Location const& _location, + ptr const& _type, + std::string const& _name) + : ASTNode(_location), m_type(_type), m_name(_name) + {} private: - ptr m_type; ///< can be empty ("var") - std::string m_name; + ptr m_type; ///< can be empty ("var") + std::string m_name; }; /// types @@ -146,42 +146,42 @@ private: class TypeName : public ASTNode { public: - explicit TypeName(Location const& _location) - : ASTNode(_location) - {} + explicit TypeName(Location const& _location) + : ASTNode(_location) + {} }; /// any pre-defined type that is not a mapping class ElementaryTypeName : public TypeName { public: - explicit ElementaryTypeName(Location const& _location, Token::Value _type) - : TypeName(_location), m_type(_type) - {} + explicit ElementaryTypeName(Location const& _location, Token::Value _type) + : TypeName(_location), m_type(_type) + {} private: - Token::Value m_type; + Token::Value m_type; }; class UserDefinedTypeName : public TypeName { public: - UserDefinedTypeName(Location const& _location, std::string const& _name) - : TypeName(_location), m_name(_name) - {} + UserDefinedTypeName(Location const& _location, std::string const& _name) + : TypeName(_location), m_name(_name) + {} private: - std::string m_name; + std::string m_name; }; class Mapping : public TypeName { public: - Mapping(Location const& _location, ptr const& _keyType, - ptr const& _valueType) - : TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) - {} + Mapping(Location const& _location, ptr const& _keyType, + ptr const& _valueType) + : TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) + {} private: - ptr m_keyType; - ptr m_valueType; + ptr m_keyType; + ptr m_valueType; }; /// @} @@ -192,28 +192,28 @@ private: class Statement : public ASTNode { public: - explicit Statement(Location const& _location) - : ASTNode(_location) - {} + explicit Statement(Location const& _location) + : ASTNode(_location) + {} }; class Block : public Statement { public: - explicit Block(Location const& _location) - : Statement(_location) - {} + explicit Block(Location const& _location, vecptr const& _statements) + : Statement(_location), m_statements(_statements) + {} private: - vecptr m_statements; + vecptr m_statements; }; class IfStatement : public Statement { private: - ptr m_condition; - ptr m_trueBody; - ptr m_falseBody; + ptr m_condition; + ptr m_trueBody; + ptr m_falseBody; }; class BreakableStatement : public Statement @@ -224,8 +224,8 @@ class BreakableStatement : public Statement class WhileStatement : public BreakableStatement { private: - ptr m_condition; - ptr m_body; + ptr m_condition; + ptr m_body; }; class Continue : public Statement @@ -241,15 +241,15 @@ class Break : public Statement class Return : public Statement { private: - ptr m_expression; + ptr m_expression; }; class VariableAssignment : public Statement { private: - ptr m_variable; - Token::Value m_assigmentOperator; - ptr m_rightHandSide; ///< can be missing + ptr m_variable; + Token::Value m_assigmentOperator; + ptr m_rightHandSide; ///< can be missing }; class Expression : public Statement @@ -265,47 +265,47 @@ private: class Assignment : public Expression { private: - ptr m_leftHandSide; - Token::Value m_assigmentOperator; - ptr m_rightHandSide; + ptr m_leftHandSide; + Token::Value m_assigmentOperator; + ptr m_rightHandSide; }; class UnaryOperation : public Expression { private: - Token::Value m_operator; - ptr m_subExpression; - bool isPrefix; + Token::Value m_operator; + ptr m_subExpression; + bool isPrefix; }; class BinaryOperation : public Expression { private: - ptr m_left; - ptr m_right; - Token::Value m_operator; + ptr m_left; + ptr m_right; + Token::Value m_operator; }; /// Can be ordinary function call, type cast or struct construction. class FunctionCall : public Expression { private: - // if m_functionName is the name of a type, store the token directly - std::string m_functionName; // "in place" calls of return values are not possible for now - vecptr m_arguments; + // if m_functionName is the name of a type, store the token directly + std::string m_functionName; // "in place" calls of return values are not possible for now + vecptr m_arguments; }; class MemberAccess : public Expression { private: - ptr m_expression; - std::string m_memberName; + ptr m_expression; + std::string m_memberName; }; class IndexAccess : public Expression { - ptr m_base; - ptr m_index; + ptr m_base; + ptr m_index; }; class PrimaryExpression : public Expression @@ -315,13 +315,13 @@ class PrimaryExpression : public Expression class Identifier : public PrimaryExpression { private: - std::string m_name; + std::string m_name; }; class Literal : public PrimaryExpression { private: - std::string m_value; + std::string m_value; }; /// @} diff --git a/libsolidity/BaseTypes.h b/libsolidity/BaseTypes.h index 2e92b07e8..a037f6553 100644 --- a/libsolidity/BaseTypes.h +++ b/libsolidity/BaseTypes.h @@ -7,13 +7,13 @@ namespace solidity { /// Representation of an interval of source positions. /// The interval includes start and excludes end. struct Location { - Location(int _start, int _end) : start(_start), end(_end) { } - Location() : start(-1), end(-1) { } + Location(int _start, int _end) : start(_start), end(_end) { } + Location() : start(-1), end(-1) { } - bool IsValid() const { return start >= 0 && end >= start; } + bool IsValid() const { return start >= 0 && end >= start; } - int start; - int end; + int start; + int end; }; } } diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 2df1b5762..2886b2c18 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** * @author Christian @@ -30,9 +30,9 @@ namespace solidity { ptr Parser::parse(std::shared_ptr const& _scanner) { - m_scanner = _scanner; + m_scanner = _scanner; - return parseContractDefinition(); + return parseContractDefinition(); } @@ -41,236 +41,254 @@ ptr Parser::parse(std::shared_ptr const& _scanner) class Parser::ASTNodeFactory { public: - ASTNodeFactory(const Parser& _parser) - : m_parser(_parser), m_location(_parser.getPosition(), -1) - {} - - void markEndPosition() { m_location.end = m_parser.getEndPosition(); } - - /// Set the end position to the one of the given node. - void setEndPositionFromNode(const ptr& _node) - { - m_location.end = _node->getLocation().end; - } - - /// @todo: check that this actually uses perfect forwarding - template - ptr createNode(Args&&... _args) - { - if (m_location.end < 0) markEndPosition(); - return std::make_shared(m_location, std::forward(_args)...); - } + ASTNodeFactory(const Parser& _parser) + : m_parser(_parser), m_location(_parser.getPosition(), -1) + {} + + void markEndPosition() { m_location.end = m_parser.getEndPosition(); } + + /// Set the end position to the one of the given node. + void setEndPositionFromNode(const ptr& _node) + { + m_location.end = _node->getLocation().end; + } + + /// @todo: check that this actually uses perfect forwarding + template + ptr createNode(Args&&... _args) + { + if (m_location.end < 0) markEndPosition(); + return std::make_shared(m_location, std::forward(_args)...); + } private: - const Parser& m_parser; - Location m_location; + const Parser& m_parser; + Location m_location; }; int Parser::getPosition() const { - return m_scanner->getCurrentLocation().start; + return m_scanner->getCurrentLocation().start; } int Parser::getEndPosition() const { - return m_scanner->getCurrentLocation().end; + return m_scanner->getCurrentLocation().end; } ptr Parser::parseContractDefinition() { - ASTNodeFactory nodeFactory(*this); - - expectToken(Token::CONTRACT); - std::string name = expectIdentifier(); - expectToken(Token::LBRACE); - - vecptr structs; - vecptr stateVariables; - vecptr functions; - bool visibilityIsPublic = true; - while (true) { - Token::Value currentToken = m_scanner->getCurrentToken(); - if (currentToken == Token::RBRACE) { - break; - } 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) { - functions.push_back(parseFunctionDefinition(visibilityIsPublic)); - } else if (currentToken == Token::STRUCT) { - structs.push_back(parseStructDefinition()); - } else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING || - Token::IsElementaryTypeName(currentToken)) { - stateVariables.push_back(parseVariableDeclaration()); - expectToken(Token::SEMICOLON); - } else { - throwExpectationError("Function, variable or struct declaration expected."); - } - } - nodeFactory.markEndPosition(); - - m_scanner->next(); - expectToken(Token::EOS); - - return nodeFactory.createNode(name, structs, stateVariables, functions); + ASTNodeFactory nodeFactory(*this); + + expectToken(Token::CONTRACT); + std::string name = expectIdentifier(); + expectToken(Token::LBRACE); + + vecptr structs; + vecptr stateVariables; + vecptr functions; + bool visibilityIsPublic = true; + while (true) { + Token::Value currentToken = m_scanner->getCurrentToken(); + if (currentToken == Token::RBRACE) { + break; + } 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) { + functions.push_back(parseFunctionDefinition(visibilityIsPublic)); + } else if (currentToken == Token::STRUCT) { + structs.push_back(parseStructDefinition()); + } else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING || + Token::IsElementaryTypeName(currentToken)) { + stateVariables.push_back(parseVariableDeclaration()); + expectToken(Token::SEMICOLON); + } else { + throwExpectationError("Function, variable or struct declaration expected."); + } + } + nodeFactory.markEndPosition(); + + m_scanner->next(); + expectToken(Token::EOS); + + return nodeFactory.createNode(name, structs, stateVariables, functions); } ptr Parser::parseFunctionDefinition(bool _isPublic) { - ASTNodeFactory nodeFactory(*this); - - expectToken(Token::FUNCTION); - std::string name(expectIdentifier()); - ptr parameters(parseParameterList()); - bool isDeclaredConst = false; - if (m_scanner->getCurrentToken() == Token::CONST) { - isDeclaredConst = true; - m_scanner->next(); - } - ptr returnParameters; - if (m_scanner->getCurrentToken() == Token::RETURNS) { - m_scanner->next(); - returnParameters = parseParameterList(); - } - ptr block = parseBlock(); - nodeFactory.setEndPositionFromNode(block); - return nodeFactory.createNode(name, _isPublic, parameters, - isDeclaredConst, returnParameters, block); + ASTNodeFactory nodeFactory(*this); + + expectToken(Token::FUNCTION); + std::string name(expectIdentifier()); + ptr parameters(parseParameterList()); + bool isDeclaredConst = false; + if (m_scanner->getCurrentToken() == Token::CONST) { + isDeclaredConst = true; + m_scanner->next(); + } + ptr returnParameters; + if (m_scanner->getCurrentToken() == Token::RETURNS) { + m_scanner->next(); + returnParameters = parseParameterList(); + } + ptr block = parseBlock(); + nodeFactory.setEndPositionFromNode(block); + return nodeFactory.createNode(name, _isPublic, parameters, + isDeclaredConst, returnParameters, block); } ptr Parser::parseStructDefinition() { - ASTNodeFactory nodeFactory(*this); - - expectToken(Token::STRUCT); - std::string name = expectIdentifier(); - vecptr members; - expectToken(Token::LBRACE); - while (m_scanner->getCurrentToken() != Token::RBRACE) { - members.push_back(parseVariableDeclaration()); - expectToken(Token::SEMICOLON); - } - nodeFactory.markEndPosition(); - expectToken(Token::RBRACE); - - return nodeFactory.createNode(name, members); + ASTNodeFactory nodeFactory(*this); + + expectToken(Token::STRUCT); + std::string name = expectIdentifier(); + vecptr members; + expectToken(Token::LBRACE); + while (m_scanner->getCurrentToken() != Token::RBRACE) { + members.push_back(parseVariableDeclaration()); + expectToken(Token::SEMICOLON); + } + nodeFactory.markEndPosition(); + expectToken(Token::RBRACE); + + return nodeFactory.createNode(name, members); } ptr Parser::parseVariableDeclaration() { - ASTNodeFactory nodeFactory(*this); + ASTNodeFactory nodeFactory(*this); - ptr type = parseTypeName(); - nodeFactory.markEndPosition(); - std::string name = expectIdentifier(); - return nodeFactory.createNode(type, name); + ptr type = parseTypeName(); + nodeFactory.markEndPosition(); + std::string name = expectIdentifier(); + return nodeFactory.createNode(type, name); } ptr Parser::parseTypeName() { - ptr type; - Token::Value token = m_scanner->getCurrentToken(); - if (Token::IsElementaryTypeName(token)) { - type = ASTNodeFactory(*this).createNode(token); - m_scanner->next(); - } else if (token == Token::VAR) { - type = ASTNodeFactory(*this).createNode(); - m_scanner->next(); - } else if (token == Token::MAPPING) { - type = parseMapping(); - } else if (token == Token::IDENTIFIER) { - type = ASTNodeFactory(*this).createNode(m_scanner->getCurrentLiteral()); - m_scanner->next(); - } else { - throwExpectationError("Expected type name"); - } - - return type; + ptr type; + Token::Value token = m_scanner->getCurrentToken(); + if (Token::IsElementaryTypeName(token)) { + type = ASTNodeFactory(*this).createNode(token); + m_scanner->next(); + } else if (token == Token::VAR) { + type = ASTNodeFactory(*this).createNode(); + m_scanner->next(); + } else if (token == Token::MAPPING) { + type = parseMapping(); + } else if (token == Token::IDENTIFIER) { + type = ASTNodeFactory(*this).createNode(m_scanner->getCurrentLiteral()); + m_scanner->next(); + } else { + throwExpectationError("Expected type name"); + } + + return type; } ptr Parser::parseMapping() { - ASTNodeFactory nodeFactory(*this); + ASTNodeFactory nodeFactory(*this); - expectToken(Token::MAPPING); - expectToken(Token::LPAREN); + expectToken(Token::MAPPING); + expectToken(Token::LPAREN); - if (!Token::IsElementaryTypeName(m_scanner->getCurrentToken())) - throwExpectationError("Expected elementary type name for mapping key type"); - ptr keyType; - keyType = ASTNodeFactory(*this).createNode(m_scanner->getCurrentToken()); - m_scanner->next(); + if (!Token::IsElementaryTypeName(m_scanner->getCurrentToken())) + throwExpectationError("Expected elementary type name for mapping key type"); + ptr keyType; + keyType = ASTNodeFactory(*this).createNode(m_scanner->getCurrentToken()); + m_scanner->next(); - expectToken(Token::ARROW); - ptr valueType = parseTypeName(); - nodeFactory.markEndPosition(); - expectToken(Token::RPAREN); + expectToken(Token::ARROW); + ptr valueType = parseTypeName(); + nodeFactory.markEndPosition(); + expectToken(Token::RPAREN); - return nodeFactory.createNode(keyType, valueType); + return nodeFactory.createNode(keyType, valueType); } ptr Parser::parseParameterList() { - ASTNodeFactory nodeFactory(*this); - - vecptr parameters; - expectToken(Token::LPAREN); - if (m_scanner->getCurrentToken() != Token::RPAREN) { - parameters.push_back(parseVariableDeclaration()); - while (m_scanner->getCurrentToken() != Token::RPAREN) { - expectToken(Token::COMMA); - parameters.push_back(parseVariableDeclaration()); - } - } - nodeFactory.markEndPosition(); - m_scanner->next(); - return nodeFactory.createNode(parameters); + ASTNodeFactory nodeFactory(*this); + + vecptr parameters; + expectToken(Token::LPAREN); + if (m_scanner->getCurrentToken() != Token::RPAREN) { + parameters.push_back(parseVariableDeclaration()); + while (m_scanner->getCurrentToken() != Token::RPAREN) { + expectToken(Token::COMMA); + parameters.push_back(parseVariableDeclaration()); + } + } + nodeFactory.markEndPosition(); + m_scanner->next(); + return nodeFactory.createNode(parameters); } ptr Parser::parseBlock() { - ASTNodeFactory nodeFactory(*this); - expectToken(Token::LBRACE); - while (m_scanner->getCurrentToken() != Token::RBRACE) { - m_scanner->next(); - // @todo - } - nodeFactory.markEndPosition(); - expectToken(Token::RBRACE); - return nodeFactory.createNode(); + + ASTNodeFactory nodeFactory(*this); + expectToken(Token::LBRACE); + vecptr statements; + while (m_scanner->getCurrentToken() != Token::RBRACE) { + m_scanner->next(); + statements.push_back(parseStatement()); + } + nodeFactory.markEndPosition(); + expectToken(Token::RBRACE); + return nodeFactory.createNode(statements); +} + +ptr Parser::parseStatement() +{ + + 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 + case Token::CONTINUE: // all following + return + } } void Parser::expectToken(Token::Value _value) { - if (m_scanner->getCurrentToken() != _value) - throwExpectationError(std::string("Expected token ") + std::string(Token::Name(_value))); - m_scanner->next(); + if (m_scanner->getCurrentToken() != _value) + throwExpectationError(std::string("Expected token ") + std::string(Token::Name(_value))); + m_scanner->next(); } std::string Parser::expectIdentifier() { - if (m_scanner->getCurrentToken() != Token::IDENTIFIER) - throwExpectationError("Expected identifier"); + if (m_scanner->getCurrentToken() != Token::IDENTIFIER) + throwExpectationError("Expected identifier"); - std::string literal = m_scanner->getCurrentLiteral(); - m_scanner->next(); - return literal; + std::string literal = m_scanner->getCurrentLiteral(); + m_scanner->next(); + return literal; } void Parser::throwExpectationError(const std::string& _description) { - int line, column; - std::tie(line, column) = m_scanner->translatePositionToLineColumn(getPosition()); - cwarn << "Solidity parser error: " << _description - << "at line " << (line + 1) - << ", column " << (column + 1); - cwarn << m_scanner->getLineAtPosition(getPosition()); - cwarn << std::string(column, ' ') << "^"; - - /// @todo make a proper exception hierarchy - throw std::exception(); + int line, column; + std::tie(line, column) = m_scanner->translatePositionToLineColumn(getPosition()); + cwarn << "Solidity parser error: " << _description + << "at line " << (line + 1) + << ", column " << (column + 1); + cwarn << m_scanner->getLineAtPosition(getPosition()); + cwarn << std::string(column, ' ') << "^"; + + /// @todo make a proper exception hierarchy + throw std::exception(); } diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 96f1d6883..65409a296 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** * @author Christian @@ -32,37 +32,38 @@ class Scanner; class Parser { public: - ptr parse(std::shared_ptr const& _scanner); + ptr parse(std::shared_ptr const& _scanner); private: - class ASTNodeFactory; + class ASTNodeFactory; - /// Start position of the current token - int getPosition() const; - /// End position of the current token - int getEndPosition() const; + /// Start position of the current token + int getPosition() const; + /// End position of the current token + int getEndPosition() const; - /// Parsing functions for the AST nodes - /// @{ - ptr parseContractDefinition(); - ptr parseFunctionDefinition(bool _isPublic); - ptr parseStructDefinition(); - ptr parseVariableDeclaration(); - ptr parseTypeName(); - ptr parseMapping(); - ptr parseParameterList(); - ptr parseBlock(); - /// @} + /// Parsing functions for the AST nodes + /// @{ + ptr parseContractDefinition(); + ptr parseFunctionDefinition(bool _isPublic); + ptr parseStructDefinition(); + ptr parseVariableDeclaration(); + ptr parseTypeName(); + ptr parseMapping(); + ptr parseParameterList(); + ptr parseBlock(); + ptr parseStatement(); + /// @} - /// Helper functions - /// @{ - /// If current token value is not _value, throw exception otherwise advance token. - void expectToken(Token::Value _value); - std::string expectIdentifier(); - void throwExpectationError(const std::string& _description); - /// @} + /// Helper functions + /// @{ + /// If current token value is not _value, throw exception otherwise advance token. + void expectToken(Token::Value _value); + std::string expectIdentifier(); + void throwExpectationError(const std::string& _description); + /// @} - std::shared_ptr m_scanner; + std::shared_ptr m_scanner; }; } } diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 836e0d092..334da8e7f 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -49,66 +49,66 @@ 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); - } - - 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; - } + 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; + } } Scanner::Scanner(const CharStream& _source) { - reset(_source); + reset(_source); } void Scanner::reset(const CharStream& _source) { - m_source = _source; + m_source = _source; - m_char = m_source.get(); - skipWhitespace(); - scanToken(); - next(); + m_char = m_source.get(); + skipWhitespace(); + scanToken(); + next(); } 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++) { - int d = HexValue(m_char); - if (d < 0) { - rollback(i); - return false; - } - x = x * 16 + d; - advance(); - } - - scanned_number = x; - return true; + BOOST_ASSERT(expected_length <= 4); // prevent overflow + + char x = 0; + for (int i = 0; i < expected_length; i++) { + int d = HexValue(m_char); + if (d < 0) { + rollback(i); + return false; + } + x = x * 16 + d; + advance(); + } + + scanned_number = x; + return true; } @@ -117,29 +117,29 @@ BOOST_STATIC_ASSERT(Token::NUM_TOKENS <= 0x100); Token::Value Scanner::next() { - m_current_token = m_next_token; - m_hasLineTerminatorBeforeNext = false; - m_hasMultilineCommentBeforeNext = false; - scanToken(); - return m_current_token.token; + m_current_token = m_next_token; + m_hasLineTerminatorBeforeNext = false; + m_hasMultilineCommentBeforeNext = false; + scanToken(); + return m_current_token.token; } bool Scanner::skipWhitespace() { - const int start_position = getSourcePos(); - - 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; + const int start_position = getSourcePos(); + + 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; } @@ -156,28 +156,28 @@ Token::Value Scanner::skipSingleLineComment() Token::Value Scanner::skipMultiLineComment() { - BOOST_ASSERT(m_char == '*'); - advance(); - - while (!isSourcePastEndOfInput()) { - char ch = m_char; - advance(); - 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; - } - // 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 == '/') { - m_char = ' '; - return Token::WHITESPACE; - } - } - - // Unterminated multi-line comment. - return Token::ILLEGAL; + BOOST_ASSERT(m_char == '*'); + advance(); + + while (!isSourcePastEndOfInput()) { + char ch = m_char; + advance(); + 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; + } + // 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 == '/') { + m_char = ' '; + return Token::WHITESPACE; + } + } + + // Unterminated multi-line comment. + return Token::ILLEGAL; } void Scanner::scanToken() @@ -185,224 +185,224 @@ 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; - } - 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. + // 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; + } + + // Continue scanning for tokens as long as we're just skipping + // whitespace. } while (token == Token::WHITESPACE); m_next_token.location.end = getSourcePos(); @@ -411,67 +411,67 @@ void Scanner::scanToken() bool Scanner::scanEscape() { - char c = m_char; - advance(); - - // Skip escaped newlines. - if (IsLineTerminator(c)) - return true; - - 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' : { - if (!scanHexNumber(c, 4)) return false; - break; - } - 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. - addLiteralChar(c); - return true; + char c = m_char; + advance(); + + // Skip escaped newlines. + if (IsLineTerminator(c)) + return true; + + 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' : { + if (!scanHexNumber(c, 4)) return false; + break; + } + 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. + addLiteralChar(c); + return true; } Token::Value Scanner::scanString() { - const char quote = m_char; - advance(); // consume quote - - LiteralScope literal(this); - 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 (m_char != quote) return Token::ILLEGAL; - literal.Complete(); - - advance(); // consume quote - return Token::STRING_LITERAL; + const char quote = m_char; + advance(); // consume quote + + LiteralScope literal(this); + 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 (m_char != quote) return Token::ILLEGAL; + literal.Complete(); + + advance(); // consume quote + return Token::STRING_LITERAL; } void Scanner::scanDecimalDigits() { - while (IsDecimalDigit(m_char)) - addLiteralCharAndAdvance(); + while (IsDecimalDigit(m_char)) + addLiteralCharAndAdvance(); } @@ -483,53 +483,53 @@ Token::Value Scanner::scanNumber(bool _periodSeen) 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 + // 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; - } - while (IsHexDigit(m_char)) { - addLiteralCharAndAdvance(); - } - } - } - - // Parse decimal digits and allow trailing fractional part. - if (kind == DECIMAL) { - scanDecimalDigits(); // optional - if (m_char == '.') { - addLiteralCharAndAdvance(); - scanDecimalDigits(); // optional - } - } + // 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; + } + while (IsHexDigit(m_char)) { + addLiteralCharAndAdvance(); + } + } + } + + // Parse decimal digits and allow trailing fractional part. + if (kind == DECIMAL) { + scanDecimalDigits(); // optional + if (m_char == '.') { + addLiteralCharAndAdvance(); + scanDecimalDigits(); // optional + } + } } // 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(); + 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 @@ -537,7 +537,7 @@ Token::Value Scanner::scanNumber(bool _periodSeen) // 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; + return Token::ILLEGAL; literal.Complete(); @@ -637,76 +637,76 @@ static Token::Value KeywordOrIdentifierToken(const std::string& input) const int kMinLength = 2; const int kMaxLength = 10; if (input.size() < kMinLength || input.size() > kMaxLength) { - return Token::IDENTIFIER; + return Token::IDENTIFIER; } switch (input[0]) { - default: + 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; \ - } \ - } - KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD) + { \ + /* '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; } Token::Value Scanner::scanIdentifierOrKeyword() { - BOOST_ASSERT(IsIdentifierStart(m_char)); - LiteralScope literal(this); + BOOST_ASSERT(IsIdentifierStart(m_char)); + LiteralScope literal(this); - addLiteralCharAndAdvance(); + addLiteralCharAndAdvance(); - // Scan the rest of the identifier characters. - while (IsIdentifierPart(m_char)) - addLiteralCharAndAdvance(); + // Scan the rest of the identifier characters. + while (IsIdentifierPart(m_char)) + addLiteralCharAndAdvance(); - literal.Complete(); + literal.Complete(); - return KeywordOrIdentifierToken(m_next_token.literal); + return KeywordOrIdentifierToken(m_next_token.literal); } std::string CharStream::getLineAtPosition(int _position) const { - // if _position points to \n, it returns the line before the \n - using size_type = std::string::size_type; - size_type searchStart = std::min(m_source.size(), _position); - if (searchStart > 0) searchStart--; - size_type lineStart = m_source.rfind('\n', searchStart); - if (lineStart == std::string::npos) - lineStart = 0; - else - lineStart++; - return m_source.substr(lineStart, - std::min(m_source.find('\n', lineStart), - m_source.size()) - lineStart); + // if _position points to \n, it returns the line before the \n + using size_type = std::string::size_type; + size_type searchStart = std::min(m_source.size(), _position); + if (searchStart > 0) searchStart--; + size_type lineStart = m_source.rfind('\n', searchStart); + if (lineStart == std::string::npos) + lineStart = 0; + else + lineStart++; + return m_source.substr(lineStart, + std::min(m_source.find('\n', lineStart), + m_source.size()) - lineStart); } std::tuple CharStream::translatePositionToLineColumn(int _position) const { - using size_type = std::string::size_type; - size_type searchPosition = std::min(m_source.size(), _position); - int lineNumber = std::count(m_source.begin(), m_source.begin() + searchPosition, '\n'); - - size_type lineStart; - if (searchPosition == 0) { - lineStart = 0; - } else { - lineStart = m_source.rfind('\n', searchPosition - 1); - lineStart = lineStart == std::string::npos ? 0 : lineStart + 1; - } - - return std::tuple(lineNumber, searchPosition - lineStart); + using size_type = std::string::size_type; + size_type searchPosition = std::min(m_source.size(), _position); + int lineNumber = std::count(m_source.begin(), m_source.begin() + searchPosition, '\n'); + + size_type lineStart; + if (searchPosition == 0) { + lineStart = 0; + } else { + lineStart = m_source.rfind('\n', searchPosition - 1); + lineStart = lineStart == std::string::npos ? 0 : lineStart + 1; + } + + return std::tuple(lineNumber, searchPosition - lineStart); } diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 7b1408c0b..4bc841111 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -60,37 +60,37 @@ class ParserRecorder; class CharStream { public: - CharStream() - : 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() { - if (isPastEndOfInput()) return 0; - ++m_pos; - if (isPastEndOfInput()) return 0; - return get(); - } - char rollback(size_t _amount) { - BOOST_ASSERT(m_pos >= _amount); - m_pos -= _amount; - return get(); - } - - /// Functions that help pretty-printing parse errors - /// Do only use in error cases, they are quite expensive. - /// @{ - std::string getLineAtPosition(int _position) const; - std::tuple translatePositionToLineColumn(int _position) const; - /// @} + CharStream() + : 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() { + if (isPastEndOfInput()) return 0; + ++m_pos; + if (isPastEndOfInput()) return 0; + return get(); + } + char rollback(size_t _amount) { + BOOST_ASSERT(m_pos >= _amount); + m_pos -= _amount; + return get(); + } + + /// Functions that help pretty-printing parse errors + /// Do only use in error cases, they are quite expensive. + /// @{ + std::string getLineAtPosition(int _position) const; + std::tuple translatePositionToLineColumn(int _position) const; + /// @} private: - std::string m_source; - size_t m_pos; + std::string m_source; + size_t m_pos; }; // ---------------------------------------------------------------------------- @@ -98,155 +98,155 @@ private: class Scanner { public: - // Scoped helper for literal recording. Automatically drops the literal - // if aborting the scanning before it's complete. - class LiteralScope { - public: - explicit LiteralScope(Scanner* self) - : scanner_(self), complete_(false) { - scanner_->startNewLiteral(); - } - ~LiteralScope() { - if (!complete_) scanner_->dropLiteral(); - } - void Complete() { - complete_ = true; - } - - private: - Scanner* scanner_; - bool complete_; - }; - - explicit Scanner(const CharStream& _source); - - // Resets the scanner as if newly constructed with _input as input. - void reset(const CharStream& _source); - - // Returns the next token and advances input. - Token::Value next(); - // Returns the current token again. - Token::Value getCurrentToken() { return m_current_token.token; } - // Returns the location information for the current token - // (the token last returned by Next()). - Location getCurrentLocation() const { return m_current_token.location; } - const std::string& getCurrentLiteral() const { return m_current_token.literal; } - - // Similar functions for the upcoming token. - - // One token look-ahead (past the token returned by Next()). - Token::Value peek() const { return m_next_token.token; } - - Location peekLocation() const { return m_next_token.location; } - const std::string& peekLiteral() const { return m_next_token.literal; } - - /// 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::tuple translatePositionToLineColumn(int _position) const - { - return m_source.translatePositionToLineColumn(_position); - } - /// @} - - // Returns true if there was a line terminator before the peek'ed token, - // possibly inside a multi-line comment. - bool hasAnyLineTerminatorBeforeNext() const { - return m_hasLineTerminatorBeforeNext || - m_hasMultilineCommentBeforeNext; - } + // Scoped helper for literal recording. Automatically drops the literal + // if aborting the scanning before it's complete. + class LiteralScope { + public: + explicit LiteralScope(Scanner* self) + : scanner_(self), complete_(false) { + scanner_->startNewLiteral(); + } + ~LiteralScope() { + if (!complete_) scanner_->dropLiteral(); + } + void Complete() { + complete_ = true; + } + + private: + Scanner* scanner_; + bool complete_; + }; + + explicit Scanner(const CharStream& _source); + + // Resets the scanner as if newly constructed with _input as input. + void reset(const CharStream& _source); + + // Returns the next token and advances input. + Token::Value next(); + // Returns the current token again. + Token::Value getCurrentToken() { return m_current_token.token; } + // Returns the location information for the current token + // (the token last returned by Next()). + Location getCurrentLocation() const { return m_current_token.location; } + const std::string& getCurrentLiteral() const { return m_current_token.literal; } + + // Similar functions for the upcoming token. + + // One token look-ahead (past the token returned by Next()). + Token::Value peek() const { return m_next_token.token; } + + Location peekLocation() const { return m_next_token.location; } + const std::string& peekLiteral() const { return m_next_token.literal; } + + /// 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::tuple translatePositionToLineColumn(int _position) const + { + return m_source.translatePositionToLineColumn(_position); + } + /// @} + + // Returns true if there was a line terminator before the peek'ed token, + // possibly inside a multi-line comment. + bool hasAnyLineTerminatorBeforeNext() const { + return m_hasLineTerminatorBeforeNext || + m_hasMultilineCommentBeforeNext; + } private: - // Used for the current and look-ahead token. - struct TokenDesc { - Token::Value token; - Location location; - std::string literal; - }; - - // Literal buffer support - inline void startNewLiteral() { - m_next_token.literal.clear(); - } - - inline void addLiteralChar(char c) { - m_next_token.literal.push_back(c); - } - - inline void dropLiteral() { - m_next_token.literal.clear(); - } - - 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); - } - - inline Token::Value selectToken(Token::Value tok) { - advance(); - return tok; - } - - inline Token::Value selectToken(char next, Token::Value then, Token::Value else_) { - advance(); - if (m_char == next) { - advance(); - return then; - } else { - return else_; - } - } - - bool scanHexNumber(char& scanned_number, int expected_length); - - // Scans a single JavaScript token. - void scanToken(); - - bool skipWhitespace(); - Token::Value skipSingleLineComment(); - Token::Value skipMultiLineComment(); - - void scanDecimalDigits(); - Token::Value scanNumber(bool _periodSeen); - Token::Value scanIdentifierOrKeyword(); - - Token::Value scanString(); - - // Scans an escape-sequence which is part of a string and adds the - // decoded character to the current literal. Returns true if a pattern - // is scanned. - bool scanEscape(); - - // Return the current source position. - 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) - - CharStream m_source; - - // one character look-ahead, equals 0 at end of input - char m_char; - - // Whether there is a line terminator whitespace character after - // the current token, and before the next. Does not count newlines - // inside multiline comments. - bool m_hasLineTerminatorBeforeNext; - // Whether there is a multi-line comment that contains a - // line-terminator after the current token, and before the next. - bool m_hasMultilineCommentBeforeNext; + // Used for the current and look-ahead token. + struct TokenDesc { + Token::Value token; + Location location; + std::string literal; + }; + + // Literal buffer support + inline void startNewLiteral() { + m_next_token.literal.clear(); + } + + inline void addLiteralChar(char c) { + m_next_token.literal.push_back(c); + } + + inline void dropLiteral() { + m_next_token.literal.clear(); + } + + 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); + } + + inline Token::Value selectToken(Token::Value tok) { + advance(); + return tok; + } + + inline Token::Value selectToken(char next, Token::Value then, Token::Value else_) { + advance(); + if (m_char == next) { + advance(); + return then; + } else { + return else_; + } + } + + bool scanHexNumber(char& scanned_number, int expected_length); + + // Scans a single JavaScript token. + void scanToken(); + + bool skipWhitespace(); + Token::Value skipSingleLineComment(); + Token::Value skipMultiLineComment(); + + void scanDecimalDigits(); + Token::Value scanNumber(bool _periodSeen); + Token::Value scanIdentifierOrKeyword(); + + Token::Value scanString(); + + // Scans an escape-sequence which is part of a string and adds the + // decoded character to the current literal. Returns true if a pattern + // is scanned. + bool scanEscape(); + + // Return the current source position. + 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) + + CharStream m_source; + + // one character look-ahead, equals 0 at end of input + char m_char; + + // Whether there is a line terminator whitespace character after + // the current token, and before the next. Does not count newlines + // inside multiline comments. + bool m_hasLineTerminatorBeforeNext; + // Whether there is a multi-line comment that contains a + // line-terminator after the current token, and before the next. + bool m_hasMultilineCommentBeforeNext; }; } } diff --git a/libsolidity/Token.cpp b/libsolidity/Token.cpp index 6ae6456a9..0264f7e85 100644 --- a/libsolidity/Token.cpp +++ b/libsolidity/Token.cpp @@ -47,21 +47,21 @@ namespace solidity { #define T(name, string, precedence) #name, const char* const Token::m_name[NUM_TOKENS] = { - TOKEN_LIST(T, T) + TOKEN_LIST(T, T) }; #undef T #define T(name, string, precedence) string, const char* const Token::m_string[NUM_TOKENS] = { - TOKEN_LIST(T, T) + TOKEN_LIST(T, T) }; #undef T #define T(name, string, precedence) precedence, const int8_t Token::m_precedence[NUM_TOKENS] = { - TOKEN_LIST(T, T) + TOKEN_LIST(T, T) }; #undef T @@ -69,7 +69,7 @@ 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[] = { - TOKEN_LIST(KT, KK) + TOKEN_LIST(KT, KK) }; #undef KT #undef KK diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 4476b3837..2ff5067bc 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -65,309 +65,309 @@ namespace solidity { #define IGNORE_TOKEN(name, string, precedence) -#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) \ - T(LBRACK, "[", 0) \ - T(RBRACK, "]", 0) \ - T(LBRACE, "{", 0) \ - T(RBRACE, "}", 0) \ - T(COLON, ":", 0) \ - T(SEMICOLON, ";", 0) \ - T(PERIOD, ".", 0) \ - T(CONDITIONAL, "?", 3) \ - 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 */ \ - /* same order! */ \ - T(INIT_VAR, "=init_var", 2) /* AST-use only. */ \ - T(INIT_LET, "=init_let", 2) /* AST-use only. */ \ - T(INIT_CONST, "=init_const", 2) /* AST-use only. */ \ - T(INIT_CONST_LEGACY, "=init_const_legacy", 2) /* AST-use only. */ \ - T(ASSIGN, "=", 2) \ - T(ASSIGN_BIT_OR, "|=", 2) \ - T(ASSIGN_BIT_XOR, "^=", 2) \ - T(ASSIGN_BIT_AND, "&=", 2) \ - T(ASSIGN_SHL, "<<=", 2) \ - T(ASSIGN_SAR, ">>=", 2) \ - T(ASSIGN_SHR, ">>>=", 2) \ - T(ASSIGN_ADD, "+=", 2) \ - T(ASSIGN_SUB, "-=", 2) \ - 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! */ \ - T(COMMA, ",", 1) \ - T(OR, "||", 4) \ - T(AND, "&&", 5) \ - T(BIT_OR, "|", 6) \ - T(BIT_XOR, "^", 7) \ - T(BIT_AND, "&", 8) \ - T(SHL, "<<", 11) \ - T(SAR, ">>", 11) \ - T(SHR, ">>>", 11) \ - T(ROR, "rotate right", 11) /* only used by Crankshaft */ \ - T(ADD, "+", 12) \ - T(SUB, "-", 12) \ - 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! */ \ - T(EQ, "==", 9) \ - T(NE, "!=", 9) \ - T(EQ_STRICT, "===", 9) \ - T(NE_STRICT, "!==", 9) \ - T(LT, "<", 10) \ - T(GT, ">", 10) \ - T(LTE, "<=", 10) \ - 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! */ \ - T(NOT, "!", 0) \ - T(BIT_NOT, "~", 0) \ - 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) \ - K(CATCH, "catch", 0) \ - K(CONTINUE, "continue", 0) \ - K(CONTRACT, "contract", 0) \ - K(DEBUGGER, "debugger", 0) \ - K(DEFAULT, "default", 0) \ - /* DELETE */ \ - K(DO, "do", 0) \ - K(ELSE, "else", 0) \ - K(FINALLY, "finally", 0) \ - K(FOR, "for", 0) \ - K(FUNCTION, "function", 0) \ - K(IF, "if", 0) \ - /* IN */ \ - /* INSTANCEOF */ \ - K(MAPPING, "mapping", 0) \ - K(NEW, "new", 0) \ - K(PUBLIC, "public", 0) \ - K(PRIVATE, "private", 0) \ - K(RETURN, "return", 0) \ - K(RETURNS, "returns", 0) \ - K(STRUCT, "struct", 0) \ - K(SWITCH, "switch", 0) \ - K(THIS, "this", 0) \ - K(THROW, "throw", 0) \ - K(TRY, "try", 0) \ - /* TYPEOF */ \ - K(VAR, "var", 0) \ - /* VOID */ \ - K(WHILE, "while", 0) \ - K(WITH, "with", 0) \ - \ - /* type keywords, keep them in this order, keep int as first keyword TODO more to be added */ \ - K(INT, "int", 0) \ - K(INT32, "int32", 0) \ - K(INT64, "int64", 0) \ - K(INT128, "int128", 0) \ - K(INT256, "int256", 0) \ - K(UINT, "uint", 0) \ - K(UINT32, "uint32", 0) \ - K(UINT64, "uint64", 0) \ - K(UINT128, "uint128", 0) \ - K(UINT256, "uint256", 0) \ - K(HASH, "hash", 0) \ - K(HASH32, "hash32", 0) \ - K(HASH64, "hash64", 0) \ - K(HASH128, "hash128", 0) \ - K(HASH256, "hash256", 0) \ - K(ADDRESS, "address", 0) \ - K(BOOL, "bool", 0) \ - K(STRING_TYPE, "string", 0) \ - K(TEXT, "text", 0) \ - 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) \ - K(CLASS, "class", 0) \ - K(CONST, "const", 0) \ - K(EXPORT, "export", 0) \ - K(EXTENDS, "extends", 0) \ - K(IMPORT, "import", 0) \ - K(LET, "let", 0) \ - K(STATIC, "static", 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) +#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) \ + T(LBRACK, "[", 0) \ + T(RBRACK, "]", 0) \ + T(LBRACE, "{", 0) \ + T(RBRACE, "}", 0) \ + T(COLON, ":", 0) \ + T(SEMICOLON, ";", 0) \ + T(PERIOD, ".", 0) \ + T(CONDITIONAL, "?", 3) \ + 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 */ \ + /* same order! */ \ + T(INIT_VAR, "=init_var", 2) /* AST-use only. */ \ + T(INIT_LET, "=init_let", 2) /* AST-use only. */ \ + T(INIT_CONST, "=init_const", 2) /* AST-use only. */ \ + T(INIT_CONST_LEGACY, "=init_const_legacy", 2) /* AST-use only. */ \ + T(ASSIGN, "=", 2) \ + T(ASSIGN_BIT_OR, "|=", 2) \ + T(ASSIGN_BIT_XOR, "^=", 2) \ + T(ASSIGN_BIT_AND, "&=", 2) \ + T(ASSIGN_SHL, "<<=", 2) \ + T(ASSIGN_SAR, ">>=", 2) \ + T(ASSIGN_SHR, ">>>=", 2) \ + T(ASSIGN_ADD, "+=", 2) \ + T(ASSIGN_SUB, "-=", 2) \ + 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! */ \ + T(COMMA, ",", 1) \ + T(OR, "||", 4) \ + T(AND, "&&", 5) \ + T(BIT_OR, "|", 6) \ + T(BIT_XOR, "^", 7) \ + T(BIT_AND, "&", 8) \ + T(SHL, "<<", 11) \ + T(SAR, ">>", 11) \ + T(SHR, ">>>", 11) \ + T(ROR, "rotate right", 11) /* only used by Crankshaft */ \ + T(ADD, "+", 12) \ + T(SUB, "-", 12) \ + 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! */ \ + T(EQ, "==", 9) \ + T(NE, "!=", 9) \ + T(EQ_STRICT, "===", 9) \ + T(NE_STRICT, "!==", 9) \ + T(LT, "<", 10) \ + T(GT, ">", 10) \ + T(LTE, "<=", 10) \ + 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! */ \ + T(NOT, "!", 0) \ + T(BIT_NOT, "~", 0) \ + 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) \ + K(CATCH, "catch", 0) \ + K(CONTINUE, "continue", 0) \ + K(CONTRACT, "contract", 0) \ + K(DEBUGGER, "debugger", 0) \ + K(DEFAULT, "default", 0) \ + /* DELETE */ \ + K(DO, "do", 0) \ + K(ELSE, "else", 0) \ + K(FINALLY, "finally", 0) \ + K(FOR, "for", 0) \ + K(FUNCTION, "function", 0) \ + K(IF, "if", 0) \ + /* IN */ \ + /* INSTANCEOF */ \ + K(MAPPING, "mapping", 0) \ + K(NEW, "new", 0) \ + K(PUBLIC, "public", 0) \ + K(PRIVATE, "private", 0) \ + K(RETURN, "return", 0) \ + K(RETURNS, "returns", 0) \ + K(STRUCT, "struct", 0) \ + K(SWITCH, "switch", 0) \ + K(THIS, "this", 0) \ + K(THROW, "throw", 0) \ + K(TRY, "try", 0) \ + /* TYPEOF */ \ + K(VAR, "var", 0) \ + /* VOID */ \ + K(WHILE, "while", 0) \ + K(WITH, "with", 0) \ + \ + /* type keywords, keep them in this order, keep int as first keyword TODO more to be added */ \ + K(INT, "int", 0) \ + K(INT32, "int32", 0) \ + K(INT64, "int64", 0) \ + K(INT128, "int128", 0) \ + K(INT256, "int256", 0) \ + K(UINT, "uint", 0) \ + K(UINT32, "uint32", 0) \ + K(UINT64, "uint64", 0) \ + K(UINT128, "uint128", 0) \ + K(UINT256, "uint256", 0) \ + K(HASH, "hash", 0) \ + K(HASH32, "hash32", 0) \ + K(HASH64, "hash64", 0) \ + K(HASH128, "hash128", 0) \ + K(HASH256, "hash256", 0) \ + K(ADDRESS, "address", 0) \ + K(BOOL, "bool", 0) \ + K(STRING_TYPE, "string", 0) \ + K(TEXT, "text", 0) \ + 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) \ + K(CLASS, "class", 0) \ + K(CONST, "const", 0) \ + K(EXPORT, "export", 0) \ + K(EXTENDS, "extends", 0) \ + K(IMPORT, "import", 0) \ + K(LET, "let", 0) \ + K(STATIC, "static", 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 { - public: - // All token values. +public: + // All token values. #define T(name, string, precedence) name, - enum Value { - TOKEN_LIST(T, T) - NUM_TOKENS - }; + enum Value { + TOKEN_LIST(T, T) + NUM_TOKENS + }; #undef T - // Returns a string corresponding to the C++ token name - // (e.g. "LT" for the token LT). - static const char* Name(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 <= ROR; - } - - 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 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; - 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; - default: - BOOST_ASSERT(false); // should not get here - return op; - } - } - - 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) { - 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) { - BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned. - return m_precedence[tok]; - } - - private: - static const char* const m_name[NUM_TOKENS]; - static const char* const m_string[NUM_TOKENS]; - static const int8_t m_precedence[NUM_TOKENS]; - static const char m_tokenType[NUM_TOKENS]; + // Returns a string corresponding to the C++ token name + // (e.g. "LT" for the token LT). + static const char* Name(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 <= ROR; + } + + 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 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; + 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; + default: + BOOST_ASSERT(false); // should not get here + return op; + } + } + + 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) { + 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) { + BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned. + return m_precedence[tok]; + } + +private: + static const char* const m_name[NUM_TOKENS]; + static const char* const m_string[NUM_TOKENS]; + static const int8_t m_precedence[NUM_TOKENS]; + static const char m_tokenType[NUM_TOKENS]; }; } }