Corrected indentation.

This commit is contained in:
Christian 2014-10-09 12:28:37 +02:00
parent 0a1ebe4f51
commit c3faa433ef
9 changed files with 1186 additions and 1167 deletions

22
AST.cpp
View File

@ -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 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful, cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @author Christian <c@ethdev.com> * @author Christian <c@ethdev.com>

228
AST.h
View File

@ -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 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful, cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @author Christian <c@ethdev.com> * @author Christian <c@ethdev.com>
@ -50,47 +50,47 @@ class Expression;
class ASTNode class ASTNode
{ {
public: public:
explicit ASTNode(Location const& _location) explicit ASTNode(Location const& _location)
: m_location(_location) : m_location(_location)
{} {}
Location getLocation() const { return m_location; } Location getLocation() const { return m_location; }
private: private:
Location m_location; Location m_location;
}; };
class ContractDefinition : public ASTNode class ContractDefinition : public ASTNode
{ {
public: public:
ContractDefinition(Location const& _location, ContractDefinition(Location const& _location,
std::string const& _name, std::string const& _name,
vecptr<StructDefinition> const& _definedStructs, vecptr<StructDefinition> const& _definedStructs,
vecptr<VariableDeclaration> const& _stateVariables, vecptr<VariableDeclaration> const& _stateVariables,
vecptr<FunctionDefinition> const& _definedFunctions) vecptr<FunctionDefinition> const& _definedFunctions)
: ASTNode(_location), m_name(_name), : ASTNode(_location), m_name(_name),
m_definedStructs(_definedStructs), m_definedStructs(_definedStructs),
m_stateVariables(_stateVariables), m_stateVariables(_stateVariables),
m_definedFunctions(_definedFunctions) m_definedFunctions(_definedFunctions)
{} {}
private: private:
std::string m_name; std::string m_name;
vecptr<StructDefinition> m_definedStructs; vecptr<StructDefinition> m_definedStructs;
vecptr<VariableDeclaration> m_stateVariables; vecptr<VariableDeclaration> m_stateVariables;
vecptr<FunctionDefinition> m_definedFunctions; vecptr<FunctionDefinition> m_definedFunctions;
}; };
class StructDefinition : public ASTNode class StructDefinition : public ASTNode
{ {
public: public:
StructDefinition(Location const& _location, StructDefinition(Location const& _location,
std::string const& _name, std::string const& _name,
vecptr<VariableDeclaration> const& _members) vecptr<VariableDeclaration> const& _members)
: ASTNode(_location), m_name(_name), m_members(_members) : ASTNode(_location), m_name(_name), m_members(_members)
{} {}
private: private:
std::string m_name; std::string m_name;
vecptr<VariableDeclaration> m_members; vecptr<VariableDeclaration> m_members;
}; };
/// Used as function parameter list and return list /// Used as function parameter list and return list
@ -99,45 +99,45 @@ private:
class ParameterList : public ASTNode class ParameterList : public ASTNode
{ {
public: public:
ParameterList(Location const& _location, vecptr<VariableDeclaration> const& _parameters) ParameterList(Location const& _location, vecptr<VariableDeclaration> const& _parameters)
: ASTNode(_location), m_parameters(_parameters) : ASTNode(_location), m_parameters(_parameters)
{} {}
private: private:
vecptr<VariableDeclaration> m_parameters; vecptr<VariableDeclaration> m_parameters;
}; };
class FunctionDefinition : public ASTNode class FunctionDefinition : public ASTNode
{ {
public: public:
FunctionDefinition(Location const& _location, std::string const& _name, bool _isPublic, FunctionDefinition(Location const& _location, std::string const& _name, bool _isPublic,
ptr<ParameterList> const& _parameters, ptr<ParameterList> const& _parameters,
bool _isDeclaredConst, bool _isDeclaredConst,
ptr<ParameterList> const& _returnParameters, ptr<ParameterList> const& _returnParameters,
ptr<Block> const& _body) ptr<Block> const& _body)
: ASTNode(_location), m_name(_name), m_isPublic(_isPublic), m_parameters(_parameters), : ASTNode(_location), m_name(_name), m_isPublic(_isPublic), m_parameters(_parameters),
m_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters), m_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters),
m_body(_body) m_body(_body)
{} {}
private: private:
std::string m_name; std::string m_name;
bool m_isPublic; bool m_isPublic;
ptr<ParameterList> m_parameters; ptr<ParameterList> m_parameters;
bool m_isDeclaredConst; bool m_isDeclaredConst;
ptr<ParameterList> m_returnParameters; ptr<ParameterList> m_returnParameters;
ptr<Block> m_body; ptr<Block> m_body;
}; };
class VariableDeclaration : public ASTNode class VariableDeclaration : public ASTNode
{ {
public: public:
VariableDeclaration(Location const& _location, VariableDeclaration(Location const& _location,
ptr<TypeName> const& _type, ptr<TypeName> const& _type,
std::string const& _name) std::string const& _name)
: ASTNode(_location), m_type(_type), m_name(_name) : ASTNode(_location), m_type(_type), m_name(_name)
{} {}
private: private:
ptr<TypeName> m_type; ///< can be empty ("var") ptr<TypeName> m_type; ///< can be empty ("var")
std::string m_name; std::string m_name;
}; };
/// types /// types
@ -146,42 +146,42 @@ private:
class TypeName : public ASTNode class TypeName : public ASTNode
{ {
public: public:
explicit TypeName(Location const& _location) explicit TypeName(Location const& _location)
: ASTNode(_location) : ASTNode(_location)
{} {}
}; };
/// any pre-defined type that is not a mapping /// any pre-defined type that is not a mapping
class ElementaryTypeName : public TypeName class ElementaryTypeName : public TypeName
{ {
public: public:
explicit ElementaryTypeName(Location const& _location, Token::Value _type) explicit ElementaryTypeName(Location const& _location, Token::Value _type)
: TypeName(_location), m_type(_type) : TypeName(_location), m_type(_type)
{} {}
private: private:
Token::Value m_type; Token::Value m_type;
}; };
class UserDefinedTypeName : public TypeName class UserDefinedTypeName : public TypeName
{ {
public: public:
UserDefinedTypeName(Location const& _location, std::string const& _name) UserDefinedTypeName(Location const& _location, std::string const& _name)
: TypeName(_location), m_name(_name) : TypeName(_location), m_name(_name)
{} {}
private: private:
std::string m_name; std::string m_name;
}; };
class Mapping : public TypeName class Mapping : public TypeName
{ {
public: public:
Mapping(Location const& _location, ptr<ElementaryTypeName> const& _keyType, Mapping(Location const& _location, ptr<ElementaryTypeName> const& _keyType,
ptr<TypeName> const& _valueType) ptr<TypeName> const& _valueType)
: TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) : TypeName(_location), m_keyType(_keyType), m_valueType(_valueType)
{} {}
private: private:
ptr<ElementaryTypeName> m_keyType; ptr<ElementaryTypeName> m_keyType;
ptr<TypeName> m_valueType; ptr<TypeName> m_valueType;
}; };
/// @} /// @}
@ -192,28 +192,28 @@ private:
class Statement : public ASTNode class Statement : public ASTNode
{ {
public: public:
explicit Statement(Location const& _location) explicit Statement(Location const& _location)
: ASTNode(_location) : ASTNode(_location)
{} {}
}; };
class Block : public Statement class Block : public Statement
{ {
public: public:
explicit Block(Location const& _location) explicit Block(Location const& _location, vecptr<Statement> const& _statements)
: Statement(_location) : Statement(_location), m_statements(_statements)
{} {}
private: private:
vecptr<Statement> m_statements; vecptr<Statement> m_statements;
}; };
class IfStatement : public Statement class IfStatement : public Statement
{ {
private: private:
ptr<Expression> m_condition; ptr<Expression> m_condition;
ptr<Statement> m_trueBody; ptr<Statement> m_trueBody;
ptr<Statement> m_falseBody; ptr<Statement> m_falseBody;
}; };
class BreakableStatement : public Statement class BreakableStatement : public Statement
@ -224,8 +224,8 @@ class BreakableStatement : public Statement
class WhileStatement : public BreakableStatement class WhileStatement : public BreakableStatement
{ {
private: private:
ptr<Expression> m_condition; ptr<Expression> m_condition;
ptr<Statement> m_body; ptr<Statement> m_body;
}; };
class Continue : public Statement class Continue : public Statement
@ -241,15 +241,15 @@ class Break : public Statement
class Return : public Statement class Return : public Statement
{ {
private: private:
ptr<Expression> m_expression; ptr<Expression> m_expression;
}; };
class VariableAssignment : public Statement class VariableAssignment : public Statement
{ {
private: private:
ptr<VariableDeclaration> m_variable; ptr<VariableDeclaration> m_variable;
Token::Value m_assigmentOperator; Token::Value m_assigmentOperator;
ptr<Expression> m_rightHandSide; ///< can be missing ptr<Expression> m_rightHandSide; ///< can be missing
}; };
class Expression : public Statement class Expression : public Statement
@ -265,47 +265,47 @@ private:
class Assignment : public Expression class Assignment : public Expression
{ {
private: private:
ptr<Expression> m_leftHandSide; ptr<Expression> m_leftHandSide;
Token::Value m_assigmentOperator; Token::Value m_assigmentOperator;
ptr<Expression> m_rightHandSide; ptr<Expression> m_rightHandSide;
}; };
class UnaryOperation : public Expression class UnaryOperation : public Expression
{ {
private: private:
Token::Value m_operator; Token::Value m_operator;
ptr<Expression> m_subExpression; ptr<Expression> m_subExpression;
bool isPrefix; bool isPrefix;
}; };
class BinaryOperation : public Expression class BinaryOperation : public Expression
{ {
private: private:
ptr<Expression> m_left; ptr<Expression> m_left;
ptr<Expression> m_right; ptr<Expression> m_right;
Token::Value m_operator; Token::Value m_operator;
}; };
/// Can be ordinary function call, type cast or struct construction. /// Can be ordinary function call, type cast or struct construction.
class FunctionCall : public Expression class FunctionCall : public Expression
{ {
private: private:
// if m_functionName is the name of a type, store the token directly // 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 std::string m_functionName; // "in place" calls of return values are not possible for now
vecptr<Expression> m_arguments; vecptr<Expression> m_arguments;
}; };
class MemberAccess : public Expression class MemberAccess : public Expression
{ {
private: private:
ptr<Expression> m_expression; ptr<Expression> m_expression;
std::string m_memberName; std::string m_memberName;
}; };
class IndexAccess : public Expression class IndexAccess : public Expression
{ {
ptr<Expression> m_base; ptr<Expression> m_base;
ptr<Expression> m_index; ptr<Expression> m_index;
}; };
class PrimaryExpression : public Expression class PrimaryExpression : public Expression
@ -315,13 +315,13 @@ class PrimaryExpression : public Expression
class Identifier : public PrimaryExpression class Identifier : public PrimaryExpression
{ {
private: private:
std::string m_name; std::string m_name;
}; };
class Literal : public PrimaryExpression class Literal : public PrimaryExpression
{ {
private: private:
std::string m_value; std::string m_value;
}; };
/// @} /// @}

View File

@ -7,13 +7,13 @@ namespace solidity {
/// Representation of an interval of source positions. /// Representation of an interval of source positions.
/// The interval includes start and excludes end. /// The interval includes start and excludes end.
struct Location { struct Location {
Location(int _start, int _end) : start(_start), end(_end) { } Location(int _start, int _end) : start(_start), end(_end) { }
Location() : start(-1), end(-1) { } Location() : start(-1), end(-1) { }
bool IsValid() const { return start >= 0 && end >= start; } bool IsValid() const { return start >= 0 && end >= start; }
int start; int start;
int end; int end;
}; };
} } } }

View File

@ -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 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful, cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @author Christian <c@ethdev.com> * @author Christian <c@ethdev.com>
@ -30,9 +30,9 @@ namespace solidity {
ptr<ASTNode> Parser::parse(std::shared_ptr<Scanner> const& _scanner) ptr<ASTNode> Parser::parse(std::shared_ptr<Scanner> const& _scanner)
{ {
m_scanner = _scanner; m_scanner = _scanner;
return parseContractDefinition(); return parseContractDefinition();
} }
@ -41,236 +41,254 @@ ptr<ASTNode> Parser::parse(std::shared_ptr<Scanner> const& _scanner)
class Parser::ASTNodeFactory class Parser::ASTNodeFactory
{ {
public: public:
ASTNodeFactory(const Parser& _parser) ASTNodeFactory(const Parser& _parser)
: m_parser(_parser), m_location(_parser.getPosition(), -1) : m_parser(_parser), m_location(_parser.getPosition(), -1)
{} {}
void markEndPosition() { m_location.end = m_parser.getEndPosition(); } void markEndPosition() { m_location.end = m_parser.getEndPosition(); }
/// Set the end position to the one of the given node. /// Set the end position to the one of the given node.
void setEndPositionFromNode(const ptr<ASTNode>& _node) void setEndPositionFromNode(const ptr<ASTNode>& _node)
{ {
m_location.end = _node->getLocation().end; m_location.end = _node->getLocation().end;
} }
/// @todo: check that this actually uses perfect forwarding /// @todo: check that this actually uses perfect forwarding
template <class NodeType, typename... Args> template <class NodeType, typename... Args>
ptr<NodeType> createNode(Args&&... _args) ptr<NodeType> createNode(Args&&... _args)
{ {
if (m_location.end < 0) markEndPosition(); if (m_location.end < 0) markEndPosition();
return std::make_shared<NodeType>(m_location, std::forward<Args>(_args)...); return std::make_shared<NodeType>(m_location, std::forward<Args>(_args)...);
} }
private: private:
const Parser& m_parser; const Parser& m_parser;
Location m_location; Location m_location;
}; };
int Parser::getPosition() const int Parser::getPosition() const
{ {
return m_scanner->getCurrentLocation().start; return m_scanner->getCurrentLocation().start;
} }
int Parser::getEndPosition() const int Parser::getEndPosition() const
{ {
return m_scanner->getCurrentLocation().end; return m_scanner->getCurrentLocation().end;
} }
ptr<ContractDefinition> Parser::parseContractDefinition() ptr<ContractDefinition> Parser::parseContractDefinition()
{ {
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
expectToken(Token::CONTRACT); expectToken(Token::CONTRACT);
std::string name = expectIdentifier(); std::string name = expectIdentifier();
expectToken(Token::LBRACE); expectToken(Token::LBRACE);
vecptr<StructDefinition> structs; vecptr<StructDefinition> structs;
vecptr<VariableDeclaration> stateVariables; vecptr<VariableDeclaration> stateVariables;
vecptr<FunctionDefinition> functions; vecptr<FunctionDefinition> functions;
bool visibilityIsPublic = true; bool visibilityIsPublic = true;
while (true) { while (true) {
Token::Value currentToken = m_scanner->getCurrentToken(); Token::Value currentToken = m_scanner->getCurrentToken();
if (currentToken == Token::RBRACE) { if (currentToken == Token::RBRACE) {
break; break;
} else if (currentToken == Token::PUBLIC || currentToken == Token::PRIVATE) { } else if (currentToken == Token::PUBLIC || currentToken == Token::PRIVATE) {
visibilityIsPublic = (m_scanner->getCurrentToken() == Token::PUBLIC); visibilityIsPublic = (m_scanner->getCurrentToken() == Token::PUBLIC);
m_scanner->next(); m_scanner->next();
expectToken(Token::COLON); expectToken(Token::COLON);
} else if (currentToken == Token::FUNCTION) { } else if (currentToken == Token::FUNCTION) {
functions.push_back(parseFunctionDefinition(visibilityIsPublic)); functions.push_back(parseFunctionDefinition(visibilityIsPublic));
} else if (currentToken == Token::STRUCT) { } else if (currentToken == Token::STRUCT) {
structs.push_back(parseStructDefinition()); structs.push_back(parseStructDefinition());
} else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING || } else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING ||
Token::IsElementaryTypeName(currentToken)) { Token::IsElementaryTypeName(currentToken)) {
stateVariables.push_back(parseVariableDeclaration()); stateVariables.push_back(parseVariableDeclaration());
expectToken(Token::SEMICOLON); expectToken(Token::SEMICOLON);
} else { } else {
throwExpectationError("Function, variable or struct declaration expected."); throwExpectationError("Function, variable or struct declaration expected.");
} }
} }
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
m_scanner->next(); m_scanner->next();
expectToken(Token::EOS); expectToken(Token::EOS);
return nodeFactory.createNode<ContractDefinition>(name, structs, stateVariables, functions); return nodeFactory.createNode<ContractDefinition>(name, structs, stateVariables, functions);
} }
ptr<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic) ptr<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)
{ {
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
expectToken(Token::FUNCTION); expectToken(Token::FUNCTION);
std::string name(expectIdentifier()); std::string name(expectIdentifier());
ptr<ParameterList> parameters(parseParameterList()); ptr<ParameterList> parameters(parseParameterList());
bool isDeclaredConst = false; bool isDeclaredConst = false;
if (m_scanner->getCurrentToken() == Token::CONST) { if (m_scanner->getCurrentToken() == Token::CONST) {
isDeclaredConst = true; isDeclaredConst = true;
m_scanner->next(); m_scanner->next();
} }
ptr<ParameterList> returnParameters; ptr<ParameterList> returnParameters;
if (m_scanner->getCurrentToken() == Token::RETURNS) { if (m_scanner->getCurrentToken() == Token::RETURNS) {
m_scanner->next(); m_scanner->next();
returnParameters = parseParameterList(); returnParameters = parseParameterList();
} }
ptr<Block> block = parseBlock(); ptr<Block> block = parseBlock();
nodeFactory.setEndPositionFromNode(block); nodeFactory.setEndPositionFromNode(block);
return nodeFactory.createNode<FunctionDefinition>(name, _isPublic, parameters, return nodeFactory.createNode<FunctionDefinition>(name, _isPublic, parameters,
isDeclaredConst, returnParameters, block); isDeclaredConst, returnParameters, block);
} }
ptr<StructDefinition> Parser::parseStructDefinition() ptr<StructDefinition> Parser::parseStructDefinition()
{ {
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
expectToken(Token::STRUCT); expectToken(Token::STRUCT);
std::string name = expectIdentifier(); std::string name = expectIdentifier();
vecptr<VariableDeclaration> members; vecptr<VariableDeclaration> members;
expectToken(Token::LBRACE); expectToken(Token::LBRACE);
while (m_scanner->getCurrentToken() != Token::RBRACE) { while (m_scanner->getCurrentToken() != Token::RBRACE) {
members.push_back(parseVariableDeclaration()); members.push_back(parseVariableDeclaration());
expectToken(Token::SEMICOLON); expectToken(Token::SEMICOLON);
} }
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
expectToken(Token::RBRACE); expectToken(Token::RBRACE);
return nodeFactory.createNode<StructDefinition>(name, members); return nodeFactory.createNode<StructDefinition>(name, members);
} }
ptr<VariableDeclaration> Parser::parseVariableDeclaration() ptr<VariableDeclaration> Parser::parseVariableDeclaration()
{ {
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
ptr<TypeName> type = parseTypeName(); ptr<TypeName> type = parseTypeName();
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
std::string name = expectIdentifier(); std::string name = expectIdentifier();
return nodeFactory.createNode<VariableDeclaration>(type, name); return nodeFactory.createNode<VariableDeclaration>(type, name);
} }
ptr<TypeName> Parser::parseTypeName() ptr<TypeName> Parser::parseTypeName()
{ {
ptr<TypeName> type; ptr<TypeName> type;
Token::Value token = m_scanner->getCurrentToken(); Token::Value token = m_scanner->getCurrentToken();
if (Token::IsElementaryTypeName(token)) { if (Token::IsElementaryTypeName(token)) {
type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(token); type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(token);
m_scanner->next(); m_scanner->next();
} else if (token == Token::VAR) { } else if (token == Token::VAR) {
type = ASTNodeFactory(*this).createNode<TypeName>(); type = ASTNodeFactory(*this).createNode<TypeName>();
m_scanner->next(); m_scanner->next();
} else if (token == Token::MAPPING) { } else if (token == Token::MAPPING) {
type = parseMapping(); type = parseMapping();
} else if (token == Token::IDENTIFIER) { } else if (token == Token::IDENTIFIER) {
type = ASTNodeFactory(*this).createNode<UserDefinedTypeName>(m_scanner->getCurrentLiteral()); type = ASTNodeFactory(*this).createNode<UserDefinedTypeName>(m_scanner->getCurrentLiteral());
m_scanner->next(); m_scanner->next();
} else { } else {
throwExpectationError("Expected type name"); throwExpectationError("Expected type name");
} }
return type; return type;
} }
ptr<Mapping> Parser::parseMapping() ptr<Mapping> Parser::parseMapping()
{ {
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
expectToken(Token::MAPPING); expectToken(Token::MAPPING);
expectToken(Token::LPAREN); expectToken(Token::LPAREN);
if (!Token::IsElementaryTypeName(m_scanner->getCurrentToken())) if (!Token::IsElementaryTypeName(m_scanner->getCurrentToken()))
throwExpectationError("Expected elementary type name for mapping key type"); throwExpectationError("Expected elementary type name for mapping key type");
ptr<ElementaryTypeName> keyType; ptr<ElementaryTypeName> keyType;
keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(m_scanner->getCurrentToken()); keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(m_scanner->getCurrentToken());
m_scanner->next(); m_scanner->next();
expectToken(Token::ARROW); expectToken(Token::ARROW);
ptr<TypeName> valueType = parseTypeName(); ptr<TypeName> valueType = parseTypeName();
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
expectToken(Token::RPAREN); expectToken(Token::RPAREN);
return nodeFactory.createNode<Mapping>(keyType, valueType); return nodeFactory.createNode<Mapping>(keyType, valueType);
} }
ptr<ParameterList> Parser::parseParameterList() ptr<ParameterList> Parser::parseParameterList()
{ {
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
vecptr<VariableDeclaration> parameters; vecptr<VariableDeclaration> parameters;
expectToken(Token::LPAREN); expectToken(Token::LPAREN);
if (m_scanner->getCurrentToken() != Token::RPAREN) { if (m_scanner->getCurrentToken() != Token::RPAREN) {
parameters.push_back(parseVariableDeclaration()); parameters.push_back(parseVariableDeclaration());
while (m_scanner->getCurrentToken() != Token::RPAREN) { while (m_scanner->getCurrentToken() != Token::RPAREN) {
expectToken(Token::COMMA); expectToken(Token::COMMA);
parameters.push_back(parseVariableDeclaration()); parameters.push_back(parseVariableDeclaration());
} }
} }
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
m_scanner->next(); m_scanner->next();
return nodeFactory.createNode<ParameterList>(parameters); return nodeFactory.createNode<ParameterList>(parameters);
} }
ptr<Block> Parser::parseBlock() ptr<Block> Parser::parseBlock()
{ {
ASTNodeFactory nodeFactory(*this);
expectToken(Token::LBRACE); ASTNodeFactory nodeFactory(*this);
while (m_scanner->getCurrentToken() != Token::RBRACE) { expectToken(Token::LBRACE);
m_scanner->next(); vecptr<Statement> statements;
// @todo while (m_scanner->getCurrentToken() != Token::RBRACE) {
} m_scanner->next();
nodeFactory.markEndPosition(); statements.push_back(parseStatement());
expectToken(Token::RBRACE); }
return nodeFactory.createNode<Block>(); nodeFactory.markEndPosition();
expectToken(Token::RBRACE);
return nodeFactory.createNode<Block>(statements);
}
ptr<Statement> 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) void Parser::expectToken(Token::Value _value)
{ {
if (m_scanner->getCurrentToken() != _value) if (m_scanner->getCurrentToken() != _value)
throwExpectationError(std::string("Expected token ") + std::string(Token::Name(_value))); throwExpectationError(std::string("Expected token ") + std::string(Token::Name(_value)));
m_scanner->next(); m_scanner->next();
} }
std::string Parser::expectIdentifier() std::string Parser::expectIdentifier()
{ {
if (m_scanner->getCurrentToken() != Token::IDENTIFIER) if (m_scanner->getCurrentToken() != Token::IDENTIFIER)
throwExpectationError("Expected identifier"); throwExpectationError("Expected identifier");
std::string literal = m_scanner->getCurrentLiteral(); std::string literal = m_scanner->getCurrentLiteral();
m_scanner->next(); m_scanner->next();
return literal; return literal;
} }
void Parser::throwExpectationError(const std::string& _description) void Parser::throwExpectationError(const std::string& _description)
{ {
int line, column; int line, column;
std::tie(line, column) = m_scanner->translatePositionToLineColumn(getPosition()); std::tie(line, column) = m_scanner->translatePositionToLineColumn(getPosition());
cwarn << "Solidity parser error: " << _description cwarn << "Solidity parser error: " << _description
<< "at line " << (line + 1) << "at line " << (line + 1)
<< ", column " << (column + 1); << ", column " << (column + 1);
cwarn << m_scanner->getLineAtPosition(getPosition()); cwarn << m_scanner->getLineAtPosition(getPosition());
cwarn << std::string(column, ' ') << "^"; cwarn << std::string(column, ' ') << "^";
/// @todo make a proper exception hierarchy /// @todo make a proper exception hierarchy
throw std::exception(); throw std::exception();
} }

View File

@ -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 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful, cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @author Christian <c@ethdev.com> * @author Christian <c@ethdev.com>
@ -32,37 +32,38 @@ class Scanner;
class Parser class Parser
{ {
public: public:
ptr<ASTNode> parse(std::shared_ptr<Scanner> const& _scanner); ptr<ASTNode> parse(std::shared_ptr<Scanner> const& _scanner);
private: private:
class ASTNodeFactory; class ASTNodeFactory;
/// Start position of the current token /// Start position of the current token
int getPosition() const; int getPosition() const;
/// End position of the current token /// End position of the current token
int getEndPosition() const; int getEndPosition() const;
/// Parsing functions for the AST nodes /// Parsing functions for the AST nodes
/// @{ /// @{
ptr<ContractDefinition> parseContractDefinition(); ptr<ContractDefinition> parseContractDefinition();
ptr<FunctionDefinition> parseFunctionDefinition(bool _isPublic); ptr<FunctionDefinition> parseFunctionDefinition(bool _isPublic);
ptr<StructDefinition> parseStructDefinition(); ptr<StructDefinition> parseStructDefinition();
ptr<VariableDeclaration> parseVariableDeclaration(); ptr<VariableDeclaration> parseVariableDeclaration();
ptr<TypeName> parseTypeName(); ptr<TypeName> parseTypeName();
ptr<Mapping> parseMapping(); ptr<Mapping> parseMapping();
ptr<ParameterList> parseParameterList(); ptr<ParameterList> parseParameterList();
ptr<Block> parseBlock(); ptr<Block> parseBlock();
/// @} ptr<Statement> parseStatement();
/// @}
/// Helper functions /// Helper functions
/// @{ /// @{
/// If current token value is not _value, throw exception otherwise advance token. /// If current token value is not _value, throw exception otherwise advance token.
void expectToken(Token::Value _value); void expectToken(Token::Value _value);
std::string expectIdentifier(); std::string expectIdentifier();
void throwExpectationError(const std::string& _description); void throwExpectationError(const std::string& _description);
/// @} /// @}
std::shared_ptr<Scanner> m_scanner; std::shared_ptr<Scanner> m_scanner;
}; };
} } } }

View File

@ -49,66 +49,66 @@ namespace dev {
namespace solidity { namespace solidity {
namespace { namespace {
bool IsDecimalDigit(char c) { bool IsDecimalDigit(char c) {
return '0' <= c && c <= '9'; return '0' <= c && c <= '9';
} }
bool IsHexDigit(char c) { bool IsHexDigit(char c) {
return IsDecimalDigit(c) return IsDecimalDigit(c)
|| ('a' <= c && c <= 'f') || ('a' <= c && c <= 'f')
|| ('A' <= c && c <= 'F'); || ('A' <= c && c <= 'F');
} }
bool IsLineTerminator(char c) { return c == '\n'; } bool IsLineTerminator(char c) { return c == '\n'; }
bool IsWhiteSpace(char c) { bool IsWhiteSpace(char c) {
return c == ' ' || c == '\n' || c == '\t'; return c == ' ' || c == '\n' || c == '\t';
} }
bool IsIdentifierStart(char c) { bool IsIdentifierStart(char c) {
return c == '_' || c == '$' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); return c == '_' || c == '$' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
} }
bool IsIdentifierPart(char c) { bool IsIdentifierPart(char c) {
return IsIdentifierStart(c) || IsDecimalDigit(c); return IsIdentifierStart(c) || IsDecimalDigit(c);
} }
int HexValue(char c) { int HexValue(char c) {
if (c >= '0' && c <= '9') return c - '0'; 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 if (c >= 'A' && c <= 'F') return c - 'A' + 10; else if (c >= 'A' && c <= 'F') return c - 'A' + 10;
else return -1; else return -1;
} }
} }
Scanner::Scanner(const CharStream& _source) Scanner::Scanner(const CharStream& _source)
{ {
reset(_source); reset(_source);
} }
void Scanner::reset(const CharStream& _source) void Scanner::reset(const CharStream& _source)
{ {
m_source = _source; m_source = _source;
m_char = m_source.get(); m_char = m_source.get();
skipWhitespace(); skipWhitespace();
scanToken(); scanToken();
next(); next();
} }
bool Scanner::scanHexNumber(char& scanned_number, int expected_length) bool Scanner::scanHexNumber(char& scanned_number, int expected_length)
{ {
BOOST_ASSERT(expected_length <= 4); // prevent overflow BOOST_ASSERT(expected_length <= 4); // prevent overflow
char x = 0; char x = 0;
for (int i = 0; i < expected_length; i++) { for (int i = 0; i < expected_length; i++) {
int d = HexValue(m_char); int d = HexValue(m_char);
if (d < 0) { if (d < 0) {
rollback(i); rollback(i);
return false; return false;
} }
x = x * 16 + d; x = x * 16 + d;
advance(); advance();
} }
scanned_number = x; scanned_number = x;
return true; return true;
} }
@ -117,29 +117,29 @@ BOOST_STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
Token::Value Scanner::next() Token::Value Scanner::next()
{ {
m_current_token = m_next_token; m_current_token = m_next_token;
m_hasLineTerminatorBeforeNext = false; m_hasLineTerminatorBeforeNext = false;
m_hasMultilineCommentBeforeNext = false; m_hasMultilineCommentBeforeNext = false;
scanToken(); scanToken();
return m_current_token.token; return m_current_token.token;
} }
bool Scanner::skipWhitespace() bool Scanner::skipWhitespace()
{ {
const int start_position = getSourcePos(); const int start_position = getSourcePos();
while (true) { while (true) {
if (IsLineTerminator(m_char)) { if (IsLineTerminator(m_char)) {
m_hasLineTerminatorBeforeNext = true; m_hasLineTerminatorBeforeNext = true;
} else if (!IsWhiteSpace(m_char)) { } else if (!IsWhiteSpace(m_char)) {
break; break;
} }
advance(); advance();
} }
// Return whether or not we skipped any characters. // Return whether or not we skipped any characters.
return getSourcePos() != start_position; return getSourcePos() != start_position;
} }
@ -156,28 +156,28 @@ Token::Value Scanner::skipSingleLineComment()
Token::Value Scanner::skipMultiLineComment() Token::Value Scanner::skipMultiLineComment()
{ {
BOOST_ASSERT(m_char == '*'); BOOST_ASSERT(m_char == '*');
advance(); advance();
while (!isSourcePastEndOfInput()) { while (!isSourcePastEndOfInput()) {
char ch = m_char; char ch = m_char;
advance(); advance();
if (IsLineTerminator(ch)) { if (IsLineTerminator(ch)) {
// Following ECMA-262, section 7.4, a comment containing // Following ECMA-262, section 7.4, a comment containing
// a newline will make the comment count as a line-terminator. // a newline will make the comment count as a line-terminator.
m_hasMultilineCommentBeforeNext = true; m_hasMultilineCommentBeforeNext = true;
} }
// If we have reached the end of the multi-line comment, we // If we have reached the end of the multi-line comment, we
// consume the '/' and insert a whitespace. This way all // consume the '/' and insert a whitespace. This way all
// multi-line comments are treated as whitespace. // multi-line comments are treated as whitespace.
if (ch == '*' && m_char == '/') { if (ch == '*' && m_char == '/') {
m_char = ' '; m_char = ' ';
return Token::WHITESPACE; return Token::WHITESPACE;
} }
} }
// Unterminated multi-line comment. // Unterminated multi-line comment.
return Token::ILLEGAL; return Token::ILLEGAL;
} }
void Scanner::scanToken() void Scanner::scanToken()
@ -185,224 +185,224 @@ void Scanner::scanToken()
m_next_token.literal.clear(); m_next_token.literal.clear();
Token::Value token; Token::Value token;
do { do {
// Remember the position of the next token // Remember the position of the next token
m_next_token.location.start = getSourcePos(); m_next_token.location.start = getSourcePos();
switch (m_char) { switch (m_char) {
case '\n': case '\n':
m_hasLineTerminatorBeforeNext = true; // fall-through m_hasLineTerminatorBeforeNext = true; // fall-through
case ' ': case ' ':
case '\t': case '\t':
token = selectToken(Token::WHITESPACE); token = selectToken(Token::WHITESPACE);
break; break;
case '"': case '\'': case '"': case '\'':
token = scanString(); token = scanString();
break; break;
case '<': case '<':
// < <= << <<= // < <= << <<=
advance(); advance();
if (m_char == '=') { if (m_char == '=') {
token = selectToken(Token::LTE); token = selectToken(Token::LTE);
} else if (m_char == '<') { } else if (m_char == '<') {
token = selectToken('=', Token::ASSIGN_SHL, Token::SHL); token = selectToken('=', Token::ASSIGN_SHL, Token::SHL);
} else { } else {
token = Token::LT; token = Token::LT;
} }
break; break;
case '>': case '>':
// > >= >> >>= >>> >>>= // > >= >> >>= >>> >>>=
advance(); advance();
if (m_char == '=') { if (m_char == '=') {
token = selectToken(Token::GTE); token = selectToken(Token::GTE);
} else if (m_char == '>') { } else if (m_char == '>') {
// >> >>= >>> >>>= // >> >>= >>> >>>=
advance(); advance();
if (m_char == '=') { if (m_char == '=') {
token = selectToken(Token::ASSIGN_SAR); token = selectToken(Token::ASSIGN_SAR);
} else if (m_char == '>') { } else if (m_char == '>') {
token = selectToken('=', Token::ASSIGN_SHR, Token::SHR); token = selectToken('=', Token::ASSIGN_SHR, Token::SHR);
} else { } else {
token = Token::SAR; token = Token::SAR;
} }
} else { } else {
token = Token::GT; token = Token::GT;
} }
break; break;
case '=': case '=':
// = == => // = == =>
advance(); advance();
if (m_char == '=') { if (m_char == '=') {
token = selectToken(Token::EQ); token = selectToken(Token::EQ);
} else if (m_char == '>') { } else if (m_char == '>') {
token = selectToken(Token::ARROW); token = selectToken(Token::ARROW);
} else { } else {
token = Token::ASSIGN; token = Token::ASSIGN;
} }
break; break;
case '!': case '!':
// ! != !== // ! != !==
advance(); advance();
if (m_char == '=') { if (m_char == '=') {
token = selectToken(Token::NE); token = selectToken(Token::NE);
} else { } else {
token = Token::NOT; token = Token::NOT;
} }
break; break;
case '+': case '+':
// + ++ += // + ++ +=
advance(); advance();
if (m_char == '+') { if (m_char == '+') {
token = selectToken(Token::INC); token = selectToken(Token::INC);
} else if (m_char == '=') { } else if (m_char == '=') {
token = selectToken(Token::ASSIGN_ADD); token = selectToken(Token::ASSIGN_ADD);
} else { } else {
token = Token::ADD; token = Token::ADD;
} }
break; break;
case '-': case '-':
// - -- -= // - -- -=
advance(); advance();
if (m_char == '-') { if (m_char == '-') {
advance(); advance();
token = Token::DEC; token = Token::DEC;
} else if (m_char == '=') { } else if (m_char == '=') {
token = selectToken(Token::ASSIGN_SUB); token = selectToken(Token::ASSIGN_SUB);
} else { } else {
token = Token::SUB; token = Token::SUB;
} }
break; break;
case '*': case '*':
// * *= // * *=
token = selectToken('=', Token::ASSIGN_MUL, Token::MUL); token = selectToken('=', Token::ASSIGN_MUL, Token::MUL);
break; break;
case '%': case '%':
// % %= // % %=
token = selectToken('=', Token::ASSIGN_MOD, Token::MOD); token = selectToken('=', Token::ASSIGN_MOD, Token::MOD);
break; break;
case '/': case '/':
// / // /* /= // / // /* /=
advance(); advance();
if (m_char == '/') { if (m_char == '/') {
token = skipSingleLineComment(); token = skipSingleLineComment();
} else if (m_char == '*') { } else if (m_char == '*') {
token = skipMultiLineComment(); token = skipMultiLineComment();
} else if (m_char == '=') { } else if (m_char == '=') {
token = selectToken(Token::ASSIGN_DIV); token = selectToken(Token::ASSIGN_DIV);
} else { } else {
token = Token::DIV; token = Token::DIV;
} }
break; break;
case '&': case '&':
// & && &= // & && &=
advance(); advance();
if (m_char == '&') { if (m_char == '&') {
token = selectToken(Token::AND); token = selectToken(Token::AND);
} else if (m_char == '=') { } else if (m_char == '=') {
token = selectToken(Token::ASSIGN_BIT_AND); token = selectToken(Token::ASSIGN_BIT_AND);
} else { } else {
token = Token::BIT_AND; token = Token::BIT_AND;
} }
break; break;
case '|': case '|':
// | || |= // | || |=
advance(); advance();
if (m_char == '|') { if (m_char == '|') {
token = selectToken(Token::OR); token = selectToken(Token::OR);
} else if (m_char == '=') { } else if (m_char == '=') {
token = selectToken(Token::ASSIGN_BIT_OR); token = selectToken(Token::ASSIGN_BIT_OR);
} else { } else {
token = Token::BIT_OR; token = Token::BIT_OR;
} }
break; break;
case '^': case '^':
// ^ ^= // ^ ^=
token = selectToken('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR); token = selectToken('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
break; break;
case '.': case '.':
// . Number // . Number
advance(); advance();
if (IsDecimalDigit(m_char)) { if (IsDecimalDigit(m_char)) {
token = scanNumber(true); token = scanNumber(true);
} else { } else {
token = Token::PERIOD; token = Token::PERIOD;
} }
break; break;
case ':': case ':':
token = selectToken(Token::COLON); token = selectToken(Token::COLON);
break; break;
case ';': case ';':
token = selectToken(Token::SEMICOLON); token = selectToken(Token::SEMICOLON);
break; break;
case ',': case ',':
token = selectToken(Token::COMMA); token = selectToken(Token::COMMA);
break; break;
case '(': case '(':
token = selectToken(Token::LPAREN); token = selectToken(Token::LPAREN);
break; break;
case ')': case ')':
token = selectToken(Token::RPAREN); token = selectToken(Token::RPAREN);
break; break;
case '[': case '[':
token = selectToken(Token::LBRACK); token = selectToken(Token::LBRACK);
break; break;
case ']': case ']':
token = selectToken(Token::RBRACK); token = selectToken(Token::RBRACK);
break; break;
case '{': case '{':
token = selectToken(Token::LBRACE); token = selectToken(Token::LBRACE);
break; break;
case '}': case '}':
token = selectToken(Token::RBRACE); token = selectToken(Token::RBRACE);
break; break;
case '?': case '?':
token = selectToken(Token::CONDITIONAL); token = selectToken(Token::CONDITIONAL);
break; break;
case '~': case '~':
token = selectToken(Token::BIT_NOT); token = selectToken(Token::BIT_NOT);
break; break;
default: default:
if (IsIdentifierStart(m_char)) { if (IsIdentifierStart(m_char)) {
token = scanIdentifierOrKeyword(); token = scanIdentifierOrKeyword();
} else if (IsDecimalDigit(m_char)) { } else if (IsDecimalDigit(m_char)) {
token = scanNumber(false); token = scanNumber(false);
} else if (skipWhitespace()) { } else if (skipWhitespace()) {
token = Token::WHITESPACE; token = Token::WHITESPACE;
} else if (isSourcePastEndOfInput()) { } else if (isSourcePastEndOfInput()) {
token = Token::EOS; token = Token::EOS;
} else { } else {
token = selectToken(Token::ILLEGAL); token = selectToken(Token::ILLEGAL);
} }
break; break;
} }
// Continue scanning for tokens as long as we're just skipping // Continue scanning for tokens as long as we're just skipping
// whitespace. // whitespace.
} while (token == Token::WHITESPACE); } while (token == Token::WHITESPACE);
m_next_token.location.end = getSourcePos(); m_next_token.location.end = getSourcePos();
@ -411,67 +411,67 @@ void Scanner::scanToken()
bool Scanner::scanEscape() bool Scanner::scanEscape()
{ {
char c = m_char; char c = m_char;
advance(); advance();
// Skip escaped newlines. // Skip escaped newlines.
if (IsLineTerminator(c)) if (IsLineTerminator(c))
return true; return true;
switch (c) { switch (c) {
case '\'': // fall through case '\'': // fall through
case '"' : // fall through case '"' : // fall through
case '\\': break; case '\\': break;
case 'b' : c = '\b'; break; case 'b' : c = '\b'; break;
case 'f' : c = '\f'; break; case 'f' : c = '\f'; break;
case 'n' : c = '\n'; break; case 'n' : c = '\n'; break;
case 'r' : c = '\r'; break; case 'r' : c = '\r'; break;
case 't' : c = '\t'; break; case 't' : c = '\t'; break;
case 'u' : { case 'u' : {
if (!scanHexNumber(c, 4)) return false; if (!scanHexNumber(c, 4)) return false;
break; break;
} }
case 'v' : c = '\v'; break; case 'v' : c = '\v'; break;
case 'x' : { case 'x' : {
if (!scanHexNumber(c, 2)) return false; if (!scanHexNumber(c, 2)) return false;
break; break;
} }
} }
// According to ECMA-262, section 7.8.4, characters not covered by the // According to ECMA-262, section 7.8.4, characters not covered by the
// above cases should be illegal, but they are commonly handled as // above cases should be illegal, but they are commonly handled as
// non-escaped characters by JS VMs. // non-escaped characters by JS VMs.
addLiteralChar(c); addLiteralChar(c);
return true; return true;
} }
Token::Value Scanner::scanString() Token::Value Scanner::scanString()
{ {
const char quote = m_char; const char quote = m_char;
advance(); // consume quote advance(); // consume quote
LiteralScope literal(this); LiteralScope literal(this);
while (m_char != quote && !isSourcePastEndOfInput() && !IsLineTerminator(m_char)) { while (m_char != quote && !isSourcePastEndOfInput() && !IsLineTerminator(m_char)) {
char c = m_char; char c = m_char;
advance(); advance();
if (c == '\\') { if (c == '\\') {
if (isSourcePastEndOfInput() || !scanEscape()) return Token::ILLEGAL; if (isSourcePastEndOfInput() || !scanEscape()) return Token::ILLEGAL;
} else { } else {
addLiteralChar(c); addLiteralChar(c);
} }
} }
if (m_char != quote) return Token::ILLEGAL; if (m_char != quote) return Token::ILLEGAL;
literal.Complete(); literal.Complete();
advance(); // consume quote advance(); // consume quote
return Token::STRING_LITERAL; return Token::STRING_LITERAL;
} }
void Scanner::scanDecimalDigits() void Scanner::scanDecimalDigits()
{ {
while (IsDecimalDigit(m_char)) while (IsDecimalDigit(m_char))
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
} }
@ -483,53 +483,53 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
LiteralScope literal(this); LiteralScope literal(this);
if (_periodSeen) { if (_periodSeen) {
// we have already seen a decimal point of the float // we have already seen a decimal point of the float
addLiteralChar('.'); addLiteralChar('.');
scanDecimalDigits(); // we know we have at least one digit scanDecimalDigits(); // we know we have at least one digit
} else { } else {
// if the first character is '0' we must check for octals and hex // if the first character is '0' we must check for octals and hex
if (m_char == '0') { if (m_char == '0') {
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
// either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or // either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or
// an octal number. // an octal number.
if (m_char == 'x' || m_char == 'X') { if (m_char == 'x' || m_char == 'X') {
// hex number // hex number
kind = HEX; kind = HEX;
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
if (!IsHexDigit(m_char)) { if (!IsHexDigit(m_char)) {
// we must have at least one hex digit after 'x'/'X' // we must have at least one hex digit after 'x'/'X'
return Token::ILLEGAL; return Token::ILLEGAL;
} }
while (IsHexDigit(m_char)) { while (IsHexDigit(m_char)) {
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
} }
} }
} }
// Parse decimal digits and allow trailing fractional part. // Parse decimal digits and allow trailing fractional part.
if (kind == DECIMAL) { if (kind == DECIMAL) {
scanDecimalDigits(); // optional scanDecimalDigits(); // optional
if (m_char == '.') { if (m_char == '.') {
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
scanDecimalDigits(); // optional scanDecimalDigits(); // optional
} }
} }
} }
// scan exponent, if any // scan exponent, if any
if (m_char == 'e' || m_char == 'E') { if (m_char == 'e' || m_char == 'E') {
BOOST_ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number BOOST_ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
if (kind != DECIMAL) return Token::ILLEGAL; if (kind != DECIMAL) return Token::ILLEGAL;
// scan exponent // scan exponent
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
if (m_char == '+' || m_char == '-') if (m_char == '+' || m_char == '-')
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
if (!IsDecimalDigit(m_char)) { if (!IsDecimalDigit(m_char)) {
// we must have at least one decimal digit after 'e'/'E' // we must have at least one decimal digit after 'e'/'E'
return Token::ILLEGAL; return Token::ILLEGAL;
} }
scanDecimalDigits(); scanDecimalDigits();
} }
// The source character immediately following a numeric literal must // 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 // section 7.8.3, page 17 (note that we read only one decimal digit
// if the value is 0). // if the value is 0).
if (IsDecimalDigit(m_char) || IsIdentifierStart(m_char)) if (IsDecimalDigit(m_char) || IsIdentifierStart(m_char))
return Token::ILLEGAL; return Token::ILLEGAL;
literal.Complete(); literal.Complete();
@ -637,76 +637,76 @@ static Token::Value KeywordOrIdentifierToken(const std::string& input)
const int kMinLength = 2; const int kMinLength = 2;
const int kMaxLength = 10; const int kMaxLength = 10;
if (input.size() < kMinLength || input.size() > kMaxLength) { if (input.size() < kMinLength || input.size() > kMaxLength) {
return Token::IDENTIFIER; return Token::IDENTIFIER;
} }
switch (input[0]) { switch (input[0]) {
default: default:
#define KEYWORD_GROUP_CASE(ch) \ #define KEYWORD_GROUP_CASE(ch) \
break; \ break; \
case ch: case ch:
#define KEYWORD(keyword, token) \ #define KEYWORD(keyword, token) \
{ \ { \
/* 'keyword' is a char array, so sizeof(keyword) is */ \ /* 'keyword' is a char array, so sizeof(keyword) is */ \
/* strlen(keyword) plus 1 for the NUL char. */ \ /* strlen(keyword) plus 1 for the NUL char. */ \
const int keyword_length = sizeof(keyword) - 1; \ const int keyword_length = sizeof(keyword) - 1; \
BOOST_STATIC_ASSERT(keyword_length >= kMinLength); \ BOOST_STATIC_ASSERT(keyword_length >= kMinLength); \
BOOST_STATIC_ASSERT(keyword_length <= kMaxLength); \ BOOST_STATIC_ASSERT(keyword_length <= kMaxLength); \
if (input == keyword) { \ if (input == keyword) { \
return token; \ return token; \
} \ } \
} }
KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD) KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
} }
return Token::IDENTIFIER; return Token::IDENTIFIER;
} }
Token::Value Scanner::scanIdentifierOrKeyword() Token::Value Scanner::scanIdentifierOrKeyword()
{ {
BOOST_ASSERT(IsIdentifierStart(m_char)); BOOST_ASSERT(IsIdentifierStart(m_char));
LiteralScope literal(this); LiteralScope literal(this);
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
// Scan the rest of the identifier characters. // Scan the rest of the identifier characters.
while (IsIdentifierPart(m_char)) while (IsIdentifierPart(m_char))
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
literal.Complete(); literal.Complete();
return KeywordOrIdentifierToken(m_next_token.literal); return KeywordOrIdentifierToken(m_next_token.literal);
} }
std::string CharStream::getLineAtPosition(int _position) const std::string CharStream::getLineAtPosition(int _position) const
{ {
// if _position points to \n, it returns the line before the \n // if _position points to \n, it returns the line before the \n
using size_type = std::string::size_type; using size_type = std::string::size_type;
size_type searchStart = std::min<size_type>(m_source.size(), _position); size_type searchStart = std::min<size_type>(m_source.size(), _position);
if (searchStart > 0) searchStart--; if (searchStart > 0) searchStart--;
size_type lineStart = m_source.rfind('\n', searchStart); size_type lineStart = m_source.rfind('\n', searchStart);
if (lineStart == std::string::npos) if (lineStart == std::string::npos)
lineStart = 0; lineStart = 0;
else else
lineStart++; lineStart++;
return m_source.substr(lineStart, return m_source.substr(lineStart,
std::min(m_source.find('\n', lineStart), std::min(m_source.find('\n', lineStart),
m_source.size()) - lineStart); m_source.size()) - lineStart);
} }
std::tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const std::tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const
{ {
using size_type = std::string::size_type; using size_type = std::string::size_type;
size_type searchPosition = std::min<size_type>(m_source.size(), _position); size_type searchPosition = std::min<size_type>(m_source.size(), _position);
int lineNumber = std::count(m_source.begin(), m_source.begin() + searchPosition, '\n'); int lineNumber = std::count(m_source.begin(), m_source.begin() + searchPosition, '\n');
size_type lineStart; size_type lineStart;
if (searchPosition == 0) { if (searchPosition == 0) {
lineStart = 0; lineStart = 0;
} else { } else {
lineStart = m_source.rfind('\n', searchPosition - 1); lineStart = m_source.rfind('\n', searchPosition - 1);
lineStart = lineStart == std::string::npos ? 0 : lineStart + 1; lineStart = lineStart == std::string::npos ? 0 : lineStart + 1;
} }
return std::tuple<int, int>(lineNumber, searchPosition - lineStart); return std::tuple<int, int>(lineNumber, searchPosition - lineStart);
} }

296
Scanner.h
View File

@ -60,37 +60,37 @@ class ParserRecorder;
class CharStream { class CharStream {
public: public:
CharStream() CharStream()
: m_pos(0) : m_pos(0)
{} {}
explicit CharStream(const std::string& _source) explicit CharStream(const std::string& _source)
: m_source(_source), m_pos(0) : m_source(_source), m_pos(0)
{} {}
int getPos() const { return m_pos; } int getPos() const { return m_pos; }
bool isPastEndOfInput() const { return m_pos >= m_source.size(); } bool isPastEndOfInput() const { return m_pos >= m_source.size(); }
char get() const { return m_source[m_pos]; } char get() const { return m_source[m_pos]; }
char advanceAndGet() { char advanceAndGet() {
if (isPastEndOfInput()) return 0; if (isPastEndOfInput()) return 0;
++m_pos; ++m_pos;
if (isPastEndOfInput()) return 0; if (isPastEndOfInput()) return 0;
return get(); return get();
} }
char rollback(size_t _amount) { char rollback(size_t _amount) {
BOOST_ASSERT(m_pos >= _amount); BOOST_ASSERT(m_pos >= _amount);
m_pos -= _amount; m_pos -= _amount;
return get(); return get();
} }
/// Functions that help pretty-printing parse errors /// Functions that help pretty-printing parse errors
/// Do only use in error cases, they are quite expensive. /// Do only use in error cases, they are quite expensive.
/// @{ /// @{
std::string getLineAtPosition(int _position) const; std::string getLineAtPosition(int _position) const;
std::tuple<int, int> translatePositionToLineColumn(int _position) const; std::tuple<int, int> translatePositionToLineColumn(int _position) const;
/// @} /// @}
private: private:
std::string m_source; std::string m_source;
size_t m_pos; size_t m_pos;
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -98,155 +98,155 @@ private:
class Scanner { class Scanner {
public: public:
// Scoped helper for literal recording. Automatically drops the literal // Scoped helper for literal recording. Automatically drops the literal
// if aborting the scanning before it's complete. // if aborting the scanning before it's complete.
class LiteralScope { class LiteralScope {
public: public:
explicit LiteralScope(Scanner* self) explicit LiteralScope(Scanner* self)
: scanner_(self), complete_(false) { : scanner_(self), complete_(false) {
scanner_->startNewLiteral(); scanner_->startNewLiteral();
} }
~LiteralScope() { ~LiteralScope() {
if (!complete_) scanner_->dropLiteral(); if (!complete_) scanner_->dropLiteral();
} }
void Complete() { void Complete() {
complete_ = true; complete_ = true;
} }
private: private:
Scanner* scanner_; Scanner* scanner_;
bool complete_; bool complete_;
}; };
explicit Scanner(const CharStream& _source); explicit Scanner(const CharStream& _source);
// Resets the scanner as if newly constructed with _input as input. // Resets the scanner as if newly constructed with _input as input.
void reset(const CharStream& _source); void reset(const CharStream& _source);
// Returns the next token and advances input. // Returns the next token and advances input.
Token::Value next(); Token::Value next();
// Returns the current token again. // Returns the current token again.
Token::Value getCurrentToken() { return m_current_token.token; } Token::Value getCurrentToken() { return m_current_token.token; }
// Returns the location information for the current token // Returns the location information for the current token
// (the token last returned by Next()). // (the token last returned by Next()).
Location getCurrentLocation() const { return m_current_token.location; } Location getCurrentLocation() const { return m_current_token.location; }
const std::string& getCurrentLiteral() const { return m_current_token.literal; } const std::string& getCurrentLiteral() const { return m_current_token.literal; }
// Similar functions for the upcoming token. // Similar functions for the upcoming token.
// One token look-ahead (past the token returned by Next()). // One token look-ahead (past the token returned by Next()).
Token::Value peek() const { return m_next_token.token; } Token::Value peek() const { return m_next_token.token; }
Location peekLocation() const { return m_next_token.location; } Location peekLocation() const { return m_next_token.location; }
const std::string& peekLiteral() const { return m_next_token.literal; } const std::string& peekLiteral() const { return m_next_token.literal; }
/// Functions that help pretty-printing parse errors. /// Functions that help pretty-printing parse errors.
/// Do only use in error cases, they are quite expensive. /// 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 std::tuple<int, int> translatePositionToLineColumn(int _position) const
{ {
return m_source.translatePositionToLineColumn(_position); return m_source.translatePositionToLineColumn(_position);
} }
/// @} /// @}
// Returns true if there was a line terminator before the peek'ed token, // Returns true if there was a line terminator before the peek'ed token,
// possibly inside a multi-line comment. // possibly inside a multi-line comment.
bool hasAnyLineTerminatorBeforeNext() const { bool hasAnyLineTerminatorBeforeNext() const {
return m_hasLineTerminatorBeforeNext || return m_hasLineTerminatorBeforeNext ||
m_hasMultilineCommentBeforeNext; m_hasMultilineCommentBeforeNext;
} }
private: private:
// Used for the current and look-ahead token. // Used for the current and look-ahead token.
struct TokenDesc { struct TokenDesc {
Token::Value token; Token::Value token;
Location location; Location location;
std::string literal; std::string literal;
}; };
// Literal buffer support // Literal buffer support
inline void startNewLiteral() { inline void startNewLiteral() {
m_next_token.literal.clear(); m_next_token.literal.clear();
} }
inline void addLiteralChar(char c) { inline void addLiteralChar(char c) {
m_next_token.literal.push_back(c); m_next_token.literal.push_back(c);
} }
inline void dropLiteral() { inline void dropLiteral() {
m_next_token.literal.clear(); m_next_token.literal.clear();
} }
inline void addLiteralCharAndAdvance() { inline void addLiteralCharAndAdvance() {
addLiteralChar(m_char); addLiteralChar(m_char);
advance(); advance();
} }
// Low-level scanning support. // Low-level scanning support.
bool advance() { m_char = m_source.advanceAndGet(); return !m_source.isPastEndOfInput(); } bool advance() { m_char = m_source.advanceAndGet(); return !m_source.isPastEndOfInput(); }
void rollback(int amount) { void rollback(int amount) {
m_char = m_source.rollback(amount); m_char = m_source.rollback(amount);
} }
inline Token::Value selectToken(Token::Value tok) { inline Token::Value selectToken(Token::Value tok) {
advance(); advance();
return tok; 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(); advance();
if (m_char == next) { if (m_char == next) {
advance(); advance();
return then; return then;
} else { } else {
return else_; return else_;
} }
} }
bool scanHexNumber(char& scanned_number, int expected_length); bool scanHexNumber(char& scanned_number, int expected_length);
// Scans a single JavaScript token. // Scans a single JavaScript token.
void scanToken(); void scanToken();
bool skipWhitespace(); bool skipWhitespace();
Token::Value skipSingleLineComment(); Token::Value skipSingleLineComment();
Token::Value skipMultiLineComment(); Token::Value skipMultiLineComment();
void scanDecimalDigits(); void scanDecimalDigits();
Token::Value scanNumber(bool _periodSeen); Token::Value scanNumber(bool _periodSeen);
Token::Value scanIdentifierOrKeyword(); Token::Value scanIdentifierOrKeyword();
Token::Value scanString(); Token::Value scanString();
// Scans an escape-sequence which is part of a string and adds the // Scans an escape-sequence which is part of a string and adds the
// decoded character to the current literal. Returns true if a pattern // decoded character to the current literal. Returns true if a pattern
// is scanned. // is scanned.
bool scanEscape(); bool scanEscape();
// Return the current source position. // Return the current source position.
int getSourcePos() { int getSourcePos() {
return m_source.getPos(); return m_source.getPos();
} }
bool isSourcePastEndOfInput() { bool isSourcePastEndOfInput() {
return m_source.isPastEndOfInput(); return m_source.isPastEndOfInput();
} }
TokenDesc m_current_token; // desc for current token (as returned by Next()) TokenDesc m_current_token; // desc for current token (as returned by Next())
TokenDesc m_next_token; // desc for next token (one token look-ahead) TokenDesc m_next_token; // desc for next token (one token look-ahead)
CharStream m_source; CharStream m_source;
// one character look-ahead, equals 0 at end of input // one character look-ahead, equals 0 at end of input
char m_char; char m_char;
// Whether there is a line terminator whitespace character after // Whether there is a line terminator whitespace character after
// the current token, and before the next. Does not count newlines // the current token, and before the next. Does not count newlines
// inside multiline comments. // inside multiline comments.
bool m_hasLineTerminatorBeforeNext; bool m_hasLineTerminatorBeforeNext;
// Whether there is a multi-line comment that contains a // Whether there is a multi-line comment that contains a
// line-terminator after the current token, and before the next. // line-terminator after the current token, and before the next.
bool m_hasMultilineCommentBeforeNext; bool m_hasMultilineCommentBeforeNext;
}; };
} } } }

View File

@ -47,21 +47,21 @@ namespace solidity {
#define T(name, string, precedence) #name, #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) TOKEN_LIST(T, T)
}; };
#undef T #undef T
#define T(name, string, precedence) string, #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) TOKEN_LIST(T, T)
}; };
#undef T #undef T
#define T(name, string, precedence) precedence, #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) TOKEN_LIST(T, T)
}; };
#undef T #undef T
@ -69,7 +69,7 @@ const int8_t Token::m_precedence[NUM_TOKENS] = {
#define KT(a, b, c) 'T', #define KT(a, b, c) 'T',
#define KK(a, b, c) 'K', #define KK(a, b, c) 'K',
const char Token::m_tokenType[] = { const char Token::m_tokenType[] = {
TOKEN_LIST(KT, KK) TOKEN_LIST(KT, KK)
}; };
#undef KT #undef KT
#undef KK #undef KK

554
Token.h
View File

@ -65,309 +65,309 @@ namespace solidity {
#define IGNORE_TOKEN(name, string, precedence) #define IGNORE_TOKEN(name, string, precedence)
#define TOKEN_LIST(T, K) \ #define TOKEN_LIST(T, K) \
/* End of source indicator. */ \ /* End of source indicator. */ \
T(EOS, "EOS", 0) \ T(EOS, "EOS", 0) \
\ \
/* Punctuators (ECMA-262, section 7.7, page 15). */ \ /* Punctuators (ECMA-262, section 7.7, page 15). */ \
T(LPAREN, "(", 0) \ T(LPAREN, "(", 0) \
T(RPAREN, ")", 0) \ T(RPAREN, ")", 0) \
T(LBRACK, "[", 0) \ T(LBRACK, "[", 0) \
T(RBRACK, "]", 0) \ T(RBRACK, "]", 0) \
T(LBRACE, "{", 0) \ T(LBRACE, "{", 0) \
T(RBRACE, "}", 0) \ T(RBRACE, "}", 0) \
T(COLON, ":", 0) \ T(COLON, ":", 0) \
T(SEMICOLON, ";", 0) \ T(SEMICOLON, ";", 0) \
T(PERIOD, ".", 0) \ T(PERIOD, ".", 0) \
T(CONDITIONAL, "?", 3) \ T(CONDITIONAL, "?", 3) \
T(INC, "++", 0) \ T(INC, "++", 0) \
T(DEC, "--", 0) \ T(DEC, "--", 0) \
T(ARROW, "=>", 0) \ T(ARROW, "=>", 0) \
\ \
/* Assignment operators. */ \ /* Assignment operators. */ \
/* IsAssignmentOp() and Assignment::is_compound() relies on */ \ /* IsAssignmentOp() and Assignment::is_compound() relies on */ \
/* this block of enum values being contiguous and sorted in the */ \ /* this block of enum values being contiguous and sorted in the */ \
/* same order! */ \ /* same order! */ \
T(INIT_VAR, "=init_var", 2) /* AST-use only. */ \ T(INIT_VAR, "=init_var", 2) /* AST-use only. */ \
T(INIT_LET, "=init_let", 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, "=init_const", 2) /* AST-use only. */ \
T(INIT_CONST_LEGACY, "=init_const_legacy", 2) /* AST-use only. */ \ T(INIT_CONST_LEGACY, "=init_const_legacy", 2) /* AST-use only. */ \
T(ASSIGN, "=", 2) \ T(ASSIGN, "=", 2) \
T(ASSIGN_BIT_OR, "|=", 2) \ T(ASSIGN_BIT_OR, "|=", 2) \
T(ASSIGN_BIT_XOR, "^=", 2) \ T(ASSIGN_BIT_XOR, "^=", 2) \
T(ASSIGN_BIT_AND, "&=", 2) \ T(ASSIGN_BIT_AND, "&=", 2) \
T(ASSIGN_SHL, "<<=", 2) \ T(ASSIGN_SHL, "<<=", 2) \
T(ASSIGN_SAR, ">>=", 2) \ T(ASSIGN_SAR, ">>=", 2) \
T(ASSIGN_SHR, ">>>=", 2) \ T(ASSIGN_SHR, ">>>=", 2) \
T(ASSIGN_ADD, "+=", 2) \ T(ASSIGN_ADD, "+=", 2) \
T(ASSIGN_SUB, "-=", 2) \ T(ASSIGN_SUB, "-=", 2) \
T(ASSIGN_MUL, "*=", 2) \ T(ASSIGN_MUL, "*=", 2) \
T(ASSIGN_DIV, "/=", 2) \ T(ASSIGN_DIV, "/=", 2) \
T(ASSIGN_MOD, "%=", 2) \ T(ASSIGN_MOD, "%=", 2) \
\ \
/* Binary operators sorted by precedence. */ \ /* Binary operators sorted by precedence. */ \
/* IsBinaryOp() relies on this block of enum values */ \ /* IsBinaryOp() relies on this block of enum values */ \
/* being contiguous and sorted in the same order! */ \ /* being contiguous and sorted in the same order! */ \
T(COMMA, ",", 1) \ T(COMMA, ",", 1) \
T(OR, "||", 4) \ T(OR, "||", 4) \
T(AND, "&&", 5) \ T(AND, "&&", 5) \
T(BIT_OR, "|", 6) \ T(BIT_OR, "|", 6) \
T(BIT_XOR, "^", 7) \ T(BIT_XOR, "^", 7) \
T(BIT_AND, "&", 8) \ T(BIT_AND, "&", 8) \
T(SHL, "<<", 11) \ T(SHL, "<<", 11) \
T(SAR, ">>", 11) \ T(SAR, ">>", 11) \
T(SHR, ">>>", 11) \ T(SHR, ">>>", 11) \
T(ROR, "rotate right", 11) /* only used by Crankshaft */ \ T(ROR, "rotate right", 11) /* only used by Crankshaft */ \
T(ADD, "+", 12) \ T(ADD, "+", 12) \
T(SUB, "-", 12) \ T(SUB, "-", 12) \
T(MUL, "*", 13) \ T(MUL, "*", 13) \
T(DIV, "/", 13) \ T(DIV, "/", 13) \
T(MOD, "%", 13) \ T(MOD, "%", 13) \
\ \
/* Compare operators sorted by precedence. */ \ /* Compare operators sorted by precedence. */ \
/* IsCompareOp() relies on this block of enum values */ \ /* IsCompareOp() relies on this block of enum values */ \
/* being contiguous and sorted in the same order! */ \ /* being contiguous and sorted in the same order! */ \
T(EQ, "==", 9) \ T(EQ, "==", 9) \
T(NE, "!=", 9) \ T(NE, "!=", 9) \
T(EQ_STRICT, "===", 9) \ T(EQ_STRICT, "===", 9) \
T(NE_STRICT, "!==", 9) \ T(NE_STRICT, "!==", 9) \
T(LT, "<", 10) \ T(LT, "<", 10) \
T(GT, ">", 10) \ T(GT, ">", 10) \
T(LTE, "<=", 10) \ T(LTE, "<=", 10) \
T(GTE, ">=", 10) \ T(GTE, ">=", 10) \
K(INSTANCEOF, "instanceof", 10) \ K(INSTANCEOF, "instanceof", 10) \
K(IN, "in", 10) \ K(IN, "in", 10) \
\ \
/* Unary operators. */ \ /* Unary operators. */ \
/* IsUnaryOp() relies on this block of enum values */ \ /* IsUnaryOp() relies on this block of enum values */ \
/* being contiguous and sorted in the same order! */ \ /* being contiguous and sorted in the same order! */ \
T(NOT, "!", 0) \ T(NOT, "!", 0) \
T(BIT_NOT, "~", 0) \ T(BIT_NOT, "~", 0) \
K(DELETE, "delete", 0) \ K(DELETE, "delete", 0) \
K(TYPEOF, "typeof", 0) \ K(TYPEOF, "typeof", 0) \
K(VOID, "void", 0) \ K(VOID, "void", 0) \
\ \
/* Keywords (ECMA-262, section 7.5.2, page 13). */ \ /* Keywords (ECMA-262, section 7.5.2, page 13). */ \
K(BREAK, "break", 0) \ K(BREAK, "break", 0) \
K(CASE, "case", 0) \ K(CASE, "case", 0) \
K(CATCH, "catch", 0) \ K(CATCH, "catch", 0) \
K(CONTINUE, "continue", 0) \ K(CONTINUE, "continue", 0) \
K(CONTRACT, "contract", 0) \ K(CONTRACT, "contract", 0) \
K(DEBUGGER, "debugger", 0) \ K(DEBUGGER, "debugger", 0) \
K(DEFAULT, "default", 0) \ K(DEFAULT, "default", 0) \
/* DELETE */ \ /* DELETE */ \
K(DO, "do", 0) \ K(DO, "do", 0) \
K(ELSE, "else", 0) \ K(ELSE, "else", 0) \
K(FINALLY, "finally", 0) \ K(FINALLY, "finally", 0) \
K(FOR, "for", 0) \ K(FOR, "for", 0) \
K(FUNCTION, "function", 0) \ K(FUNCTION, "function", 0) \
K(IF, "if", 0) \ K(IF, "if", 0) \
/* IN */ \ /* IN */ \
/* INSTANCEOF */ \ /* INSTANCEOF */ \
K(MAPPING, "mapping", 0) \ K(MAPPING, "mapping", 0) \
K(NEW, "new", 0) \ K(NEW, "new", 0) \
K(PUBLIC, "public", 0) \ K(PUBLIC, "public", 0) \
K(PRIVATE, "private", 0) \ K(PRIVATE, "private", 0) \
K(RETURN, "return", 0) \ K(RETURN, "return", 0) \
K(RETURNS, "returns", 0) \ K(RETURNS, "returns", 0) \
K(STRUCT, "struct", 0) \ K(STRUCT, "struct", 0) \
K(SWITCH, "switch", 0) \ K(SWITCH, "switch", 0) \
K(THIS, "this", 0) \ K(THIS, "this", 0) \
K(THROW, "throw", 0) \ K(THROW, "throw", 0) \
K(TRY, "try", 0) \ K(TRY, "try", 0) \
/* TYPEOF */ \ /* TYPEOF */ \
K(VAR, "var", 0) \ K(VAR, "var", 0) \
/* VOID */ \ /* VOID */ \
K(WHILE, "while", 0) \ K(WHILE, "while", 0) \
K(WITH, "with", 0) \ K(WITH, "with", 0) \
\ \
/* type keywords, keep them in this order, keep int as first keyword TODO more to be added */ \ /* type keywords, keep them in this order, keep int as first keyword TODO more to be added */ \
K(INT, "int", 0) \ K(INT, "int", 0) \
K(INT32, "int32", 0) \ K(INT32, "int32", 0) \
K(INT64, "int64", 0) \ K(INT64, "int64", 0) \
K(INT128, "int128", 0) \ K(INT128, "int128", 0) \
K(INT256, "int256", 0) \ K(INT256, "int256", 0) \
K(UINT, "uint", 0) \ K(UINT, "uint", 0) \
K(UINT32, "uint32", 0) \ K(UINT32, "uint32", 0) \
K(UINT64, "uint64", 0) \ K(UINT64, "uint64", 0) \
K(UINT128, "uint128", 0) \ K(UINT128, "uint128", 0) \
K(UINT256, "uint256", 0) \ K(UINT256, "uint256", 0) \
K(HASH, "hash", 0) \ K(HASH, "hash", 0) \
K(HASH32, "hash32", 0) \ K(HASH32, "hash32", 0) \
K(HASH64, "hash64", 0) \ K(HASH64, "hash64", 0) \
K(HASH128, "hash128", 0) \ K(HASH128, "hash128", 0) \
K(HASH256, "hash256", 0) \ K(HASH256, "hash256", 0) \
K(ADDRESS, "address", 0) \ K(ADDRESS, "address", 0) \
K(BOOL, "bool", 0) \ K(BOOL, "bool", 0) \
K(STRING_TYPE, "string", 0) \ K(STRING_TYPE, "string", 0) \
K(TEXT, "text", 0) \ K(TEXT, "text", 0) \
K(REAL, "real", 0) \ K(REAL, "real", 0) \
K(UREAL, "ureal", 0) \ K(UREAL, "ureal", 0) \
T(TYPES_END, NULL, 0) /* used as type enum end marker */ \ T(TYPES_END, NULL, 0) /* used as type enum end marker */ \
\ \
/* Literals (ECMA-262, section 7.8, page 16). */ \ /* Literals (ECMA-262, section 7.8, page 16). */ \
K(NULL_LITERAL, "null", 0) \ K(NULL_LITERAL, "null", 0) \
K(TRUE_LITERAL, "true", 0) \ K(TRUE_LITERAL, "true", 0) \
K(FALSE_LITERAL, "false", 0) \ K(FALSE_LITERAL, "false", 0) \
T(NUMBER, NULL, 0) \ T(NUMBER, NULL, 0) \
T(STRING_LITERAL, NULL, 0) \ T(STRING_LITERAL, NULL, 0) \
\ \
/* Identifiers (not keywords or future reserved words). */ \ /* Identifiers (not keywords or future reserved words). */ \
T(IDENTIFIER, NULL, 0) \ T(IDENTIFIER, NULL, 0) \
\ \
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \ /* Future reserved words (ECMA-262, section 7.6.1.2). */ \
T(FUTURE_RESERVED_WORD, NULL, 0) \ T(FUTURE_RESERVED_WORD, NULL, 0) \
T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \ T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \
K(CLASS, "class", 0) \ K(CLASS, "class", 0) \
K(CONST, "const", 0) \ K(CONST, "const", 0) \
K(EXPORT, "export", 0) \ K(EXPORT, "export", 0) \
K(EXTENDS, "extends", 0) \ K(EXTENDS, "extends", 0) \
K(IMPORT, "import", 0) \ K(IMPORT, "import", 0) \
K(LET, "let", 0) \ K(LET, "let", 0) \
K(STATIC, "static", 0) \ K(STATIC, "static", 0) \
/* K(YIELD, "yield", 0) */ \ /* K(YIELD, "yield", 0) */ \
K(SUPER, "super", 0) \ K(SUPER, "super", 0) \
\ \
/* Illegal token - not able to scan. */ \ /* Illegal token - not able to scan. */ \
T(ILLEGAL, "ILLEGAL", 0) \ T(ILLEGAL, "ILLEGAL", 0) \
\ \
/* Scanner-internal use only. */ \ /* Scanner-internal use only. */ \
T(WHITESPACE, NULL, 0) T(WHITESPACE, NULL, 0)
class Token { class Token {
public: public:
// All token values. // All token values.
#define T(name, string, precedence) name, #define T(name, string, precedence) name,
enum Value { enum Value {
TOKEN_LIST(T, T) TOKEN_LIST(T, T)
NUM_TOKENS NUM_TOKENS
}; };
#undef T #undef T
// Returns a string corresponding to the C++ token name // Returns a string corresponding to the C++ token name
// (e.g. "LT" for the token LT). // (e.g. "LT" for the token LT).
static const char* Name(Value tok) { static const char* Name(Value tok) {
BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned
return m_name[tok]; return m_name[tok];
} }
// Predicates // Predicates
static bool IsKeyword(Value tok) { static bool IsKeyword(Value tok) {
return m_tokenType[tok] == 'K'; return m_tokenType[tok] == 'K';
} }
static bool IsIdentifier(Value tok) { static bool IsIdentifier(Value tok) {
return tok == IDENTIFIER; return tok == IDENTIFIER;
} }
static bool IsElementaryTypeName(Value tok) { static bool IsElementaryTypeName(Value tok) {
return INT <= tok && tok < TYPES_END; return INT <= tok && tok < TYPES_END;
} }
static bool IsAssignmentOp(Value tok) { static bool IsAssignmentOp(Value tok) {
return INIT_VAR <= tok && tok <= ASSIGN_MOD; return INIT_VAR <= tok && tok <= ASSIGN_MOD;
} }
static bool IsBinaryOp(Value op) { static bool IsBinaryOp(Value op) {
return COMMA <= op && op <= MOD; return COMMA <= op && op <= MOD;
} }
static bool IsTruncatingBinaryOp(Value op) { static bool IsTruncatingBinaryOp(Value op) {
return BIT_OR <= op && op <= ROR; return BIT_OR <= op && op <= ROR;
} }
static bool IsCompareOp(Value op) { static bool IsCompareOp(Value op) {
return EQ <= op && op <= IN; return EQ <= op && op <= IN;
} }
static bool IsOrderedRelationalCompareOp(Value op) { static bool IsOrderedRelationalCompareOp(Value op) {
return op == LT || op == LTE || op == GT || op == GTE; return op == LT || op == LTE || op == GT || op == GTE;
} }
static bool IsEqualityOp(Value op) { static bool IsEqualityOp(Value op) {
return op == EQ || op == EQ_STRICT; return op == EQ || op == EQ_STRICT;
} }
static bool IsInequalityOp(Value op) { static bool IsInequalityOp(Value op) {
return op == NE || op == NE_STRICT; return op == NE || op == NE_STRICT;
} }
static bool IsArithmeticCompareOp(Value op) { static bool IsArithmeticCompareOp(Value op) {
return IsOrderedRelationalCompareOp(op) || return IsOrderedRelationalCompareOp(op) ||
IsEqualityOp(op) || IsInequalityOp(op); IsEqualityOp(op) || IsInequalityOp(op);
} }
static Value NegateCompareOp(Value op) { static Value NegateCompareOp(Value op) {
BOOST_ASSERT(IsArithmeticCompareOp(op)); BOOST_ASSERT(IsArithmeticCompareOp(op));
switch (op) { switch (op) {
case EQ: return NE; case EQ: return NE;
case NE: return EQ; case NE: return EQ;
case EQ_STRICT: return NE_STRICT; case EQ_STRICT: return NE_STRICT;
case NE_STRICT: return EQ_STRICT; case NE_STRICT: return EQ_STRICT;
case LT: return GTE; case LT: return GTE;
case GT: return LTE; case GT: return LTE;
case LTE: return GT; case LTE: return GT;
case GTE: return LT; case GTE: return LT;
default: default:
BOOST_ASSERT(false); // should not get here BOOST_ASSERT(false); // should not get here
return op; return op;
} }
} }
static Value ReverseCompareOp(Value op) { static Value ReverseCompareOp(Value op) {
BOOST_ASSERT(IsArithmeticCompareOp(op)); BOOST_ASSERT(IsArithmeticCompareOp(op));
switch (op) { switch (op) {
case EQ: return EQ; case EQ: return EQ;
case NE: return NE; case NE: return NE;
case EQ_STRICT: return EQ_STRICT; case EQ_STRICT: return EQ_STRICT;
case NE_STRICT: return NE_STRICT; case NE_STRICT: return NE_STRICT;
case LT: return GT; case LT: return GT;
case GT: return LT; case GT: return LT;
case LTE: return GTE; case LTE: return GTE;
case GTE: return LTE; case GTE: return LTE;
default: default:
BOOST_ASSERT(false); // should not get here BOOST_ASSERT(false); // should not get here
return op; return op;
} }
} }
static bool IsBitOp(Value op) { static bool IsBitOp(Value op) {
return (BIT_OR <= op && op <= SHR) || op == BIT_NOT; return (BIT_OR <= op && op <= SHR) || op == BIT_NOT;
} }
static bool IsUnaryOp(Value op) { static bool IsUnaryOp(Value op) {
return (NOT <= op && op <= VOID) || op == ADD || op == SUB; return (NOT <= op && op <= VOID) || op == ADD || op == SUB;
} }
static bool IsCountOp(Value op) { static bool IsCountOp(Value op) {
return op == INC || op == DEC; return op == INC || op == DEC;
} }
static bool IsShiftOp(Value op) { static bool IsShiftOp(Value op) {
return (SHL <= op) && (op <= SHR); return (SHL <= op) && (op <= SHR);
} }
// Returns a string corresponding to the JS token string // Returns a string corresponding to the JS token string
// (.e., "<" for the token LT) or NULL if the token doesn't // (.e., "<" for the token LT) or NULL if the token doesn't
// have a (unique) string (e.g. an IDENTIFIER). // have a (unique) string (e.g. an IDENTIFIER).
static const char* String(Value tok) { static const char* String(Value tok) {
BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned. BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned.
return m_string[tok]; return m_string[tok];
} }
// Returns the precedence > 0 for binary and compare // Returns the precedence > 0 for binary and compare
// operators; returns 0 otherwise. // operators; returns 0 otherwise.
static int Precedence(Value tok) { static int Precedence(Value tok) {
BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned. BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned.
return m_precedence[tok]; return m_precedence[tok];
} }
private: private:
static const char* const m_name[NUM_TOKENS]; static const char* const m_name[NUM_TOKENS];
static const char* const m_string[NUM_TOKENS]; static const char* const m_string[NUM_TOKENS];
static const int8_t m_precedence[NUM_TOKENS]; static const int8_t m_precedence[NUM_TOKENS];
static const char m_tokenType[NUM_TOKENS]; static const char m_tokenType[NUM_TOKENS];
}; };
} } } }