aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian <c@ethdev.com>2014-10-09 18:28:37 +0800
committerChristian <c@ethdev.com>2014-10-09 18:36:17 +0800
commitc3faa433ef2cb864764320adcb3c980b0fab7c0d (patch)
tree1dee4defd620c5532c8c65ff334123fc80856b80
parent0a1ebe4f516a5c1e8ebc12798a94529bdda9b6df (diff)
downloaddexon-solidity-c3faa433ef2cb864764320adcb3c980b0fab7c0d.tar.gz
dexon-solidity-c3faa433ef2cb864764320adcb3c980b0fab7c0d.tar.zst
dexon-solidity-c3faa433ef2cb864764320adcb3c980b0fab7c0d.zip
Corrected indentation.
-rw-r--r--AST.cpp22
-rw-r--r--AST.h228
-rw-r--r--BaseTypes.h10
-rw-r--r--Parser.cpp382
-rw-r--r--Parser.h73
-rw-r--r--Scanner.cpp894
-rw-r--r--Scanner.h354
-rw-r--r--Token.cpp8
-rw-r--r--Token.h594
9 files changed, 1292 insertions, 1273 deletions
diff --git a/AST.cpp b/AST.cpp
index ba50b7c6..76e1ff44 100644
--- a/AST.cpp
+++ b/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 <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
diff --git a/AST.h b/AST.h
index 86c5022d..dad257f2 100644
--- a/AST.h
+++ b/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 <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
@@ -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<StructDefinition> const& _definedStructs,
- vecptr<VariableDeclaration> const& _stateVariables,
- vecptr<FunctionDefinition> 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<StructDefinition> const& _definedStructs,
+ vecptr<VariableDeclaration> const& _stateVariables,
+ vecptr<FunctionDefinition> const& _definedFunctions)
+ : ASTNode(_location), m_name(_name),
+ m_definedStructs(_definedStructs),
+ m_stateVariables(_stateVariables),
+ m_definedFunctions(_definedFunctions)
+ {}
private:
- std::string m_name;
- vecptr<StructDefinition> m_definedStructs;
- vecptr<VariableDeclaration> m_stateVariables;
- vecptr<FunctionDefinition> m_definedFunctions;
+ std::string m_name;
+ vecptr<StructDefinition> m_definedStructs;
+ vecptr<VariableDeclaration> m_stateVariables;
+ vecptr<FunctionDefinition> m_definedFunctions;
};
class StructDefinition : public ASTNode
{
public:
- StructDefinition(Location const& _location,
- std::string const& _name,
- vecptr<VariableDeclaration> const& _members)
- : ASTNode(_location), m_name(_name), m_members(_members)
- {}
+ StructDefinition(Location const& _location,
+ std::string const& _name,
+ vecptr<VariableDeclaration> const& _members)
+ : ASTNode(_location), m_name(_name), m_members(_members)
+ {}
private:
- std::string m_name;
- vecptr<VariableDeclaration> m_members;
+ std::string m_name;
+ vecptr<VariableDeclaration> 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<VariableDeclaration> const& _parameters)
- : ASTNode(_location), m_parameters(_parameters)
- {}
+ ParameterList(Location const& _location, vecptr<VariableDeclaration> const& _parameters)
+ : ASTNode(_location), m_parameters(_parameters)
+ {}
private:
- vecptr<VariableDeclaration> m_parameters;
+ vecptr<VariableDeclaration> m_parameters;
};
class FunctionDefinition : public ASTNode
{
public:
- FunctionDefinition(Location const& _location, std::string const& _name, bool _isPublic,
- ptr<ParameterList> const& _parameters,
- bool _isDeclaredConst,
- ptr<ParameterList> const& _returnParameters,
- ptr<Block> 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<ParameterList> const& _parameters,
+ bool _isDeclaredConst,
+ ptr<ParameterList> const& _returnParameters,
+ ptr<Block> 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<ParameterList> m_parameters;
- bool m_isDeclaredConst;
- ptr<ParameterList> m_returnParameters;
- ptr<Block> m_body;
+ std::string m_name;
+ bool m_isPublic;
+ ptr<ParameterList> m_parameters;
+ bool m_isDeclaredConst;
+ ptr<ParameterList> m_returnParameters;
+ ptr<Block> m_body;
};
class VariableDeclaration : public ASTNode
{
public:
- VariableDeclaration(Location const& _location,
- ptr<TypeName> const& _type,
- std::string const& _name)
- : ASTNode(_location), m_type(_type), m_name(_name)
- {}
+ VariableDeclaration(Location const& _location,
+ ptr<TypeName> const& _type,
+ std::string const& _name)
+ : ASTNode(_location), m_type(_type), m_name(_name)
+ {}
private:
- ptr<TypeName> m_type; ///< can be empty ("var")
- std::string m_name;
+ ptr<TypeName> 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<ElementaryTypeName> const& _keyType,
- ptr<TypeName> const& _valueType)
- : TypeName(_location), m_keyType(_keyType), m_valueType(_valueType)
- {}
+ Mapping(Location const& _location, ptr<ElementaryTypeName> const& _keyType,
+ ptr<TypeName> const& _valueType)
+ : TypeName(_location), m_keyType(_keyType), m_valueType(_valueType)
+ {}
private:
- ptr<ElementaryTypeName> m_keyType;
- ptr<TypeName> m_valueType;
+ ptr<ElementaryTypeName> m_keyType;
+ ptr<TypeName> 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<Statement> const& _statements)
+ : Statement(_location), m_statements(_statements)
+ {}
private:
- vecptr<Statement> m_statements;
+ vecptr<Statement> m_statements;
};
class IfStatement : public Statement
{
private:
- ptr<Expression> m_condition;
- ptr<Statement> m_trueBody;
- ptr<Statement> m_falseBody;
+ ptr<Expression> m_condition;
+ ptr<Statement> m_trueBody;
+ ptr<Statement> m_falseBody;
};
class BreakableStatement : public Statement
@@ -224,8 +224,8 @@ class BreakableStatement : public Statement
class WhileStatement : public BreakableStatement
{
private:
- ptr<Expression> m_condition;
- ptr<Statement> m_body;
+ ptr<Expression> m_condition;
+ ptr<Statement> m_body;
};
class Continue : public Statement
@@ -241,15 +241,15 @@ class Break : public Statement
class Return : public Statement
{
private:
- ptr<Expression> m_expression;
+ ptr<Expression> m_expression;
};
class VariableAssignment : public Statement
{
private:
- ptr<VariableDeclaration> m_variable;
- Token::Value m_assigmentOperator;
- ptr<Expression> m_rightHandSide; ///< can be missing
+ ptr<VariableDeclaration> m_variable;
+ Token::Value m_assigmentOperator;
+ ptr<Expression> m_rightHandSide; ///< can be missing
};
class Expression : public Statement
@@ -265,47 +265,47 @@ private:
class Assignment : public Expression
{
private:
- ptr<Expression> m_leftHandSide;
- Token::Value m_assigmentOperator;
- ptr<Expression> m_rightHandSide;
+ ptr<Expression> m_leftHandSide;
+ Token::Value m_assigmentOperator;
+ ptr<Expression> m_rightHandSide;
};
class UnaryOperation : public Expression
{
private:
- Token::Value m_operator;
- ptr<Expression> m_subExpression;
- bool isPrefix;
+ Token::Value m_operator;
+ ptr<Expression> m_subExpression;
+ bool isPrefix;
};
class BinaryOperation : public Expression
{
private:
- ptr<Expression> m_left;
- ptr<Expression> m_right;
- Token::Value m_operator;
+ ptr<Expression> m_left;
+ ptr<Expression> 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<Expression> 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<Expression> m_arguments;
};
class MemberAccess : public Expression
{
private:
- ptr<Expression> m_expression;
- std::string m_memberName;
+ ptr<Expression> m_expression;
+ std::string m_memberName;
};
class IndexAccess : public Expression
{
- ptr<Expression> m_base;
- ptr<Expression> m_index;
+ ptr<Expression> m_base;
+ ptr<Expression> 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/BaseTypes.h b/BaseTypes.h
index 2e92b07e..a037f655 100644
--- a/BaseTypes.h
+++ b/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/Parser.cpp b/Parser.cpp
index 2df1b576..2886b2c1 100644
--- a/Parser.cpp
+++ b/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 <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
@@ -30,9 +30,9 @@ namespace solidity {
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
{
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<ASTNode>& _node)
- {
- m_location.end = _node->getLocation().end;
- }
-
- /// @todo: check that this actually uses perfect forwarding
- template <class NodeType, typename... Args>
- ptr<NodeType> createNode(Args&&... _args)
- {
- if (m_location.end < 0) markEndPosition();
- return std::make_shared<NodeType>(m_location, std::forward<Args>(_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<ASTNode>& _node)
+ {
+ m_location.end = _node->getLocation().end;
+ }
+
+ /// @todo: check that this actually uses perfect forwarding
+ template <class NodeType, typename... Args>
+ ptr<NodeType> createNode(Args&&... _args)
+ {
+ if (m_location.end < 0) markEndPosition();
+ return std::make_shared<NodeType>(m_location, std::forward<Args>(_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<ContractDefinition> Parser::parseContractDefinition()
{
- ASTNodeFactory nodeFactory(*this);
-
- expectToken(Token::CONTRACT);
- std::string name = expectIdentifier();
- expectToken(Token::LBRACE);
-
- vecptr<StructDefinition> structs;
- vecptr<VariableDeclaration> stateVariables;
- vecptr<FunctionDefinition> 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<ContractDefinition>(name, structs, stateVariables, functions);
+ ASTNodeFactory nodeFactory(*this);
+
+ expectToken(Token::CONTRACT);
+ std::string name = expectIdentifier();
+ expectToken(Token::LBRACE);
+
+ vecptr<StructDefinition> structs;
+ vecptr<VariableDeclaration> stateVariables;
+ vecptr<FunctionDefinition> 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<ContractDefinition>(name, structs, stateVariables, functions);
}
ptr<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)
{
- ASTNodeFactory nodeFactory(*this);
-
- expectToken(Token::FUNCTION);
- std::string name(expectIdentifier());
- ptr<ParameterList> parameters(parseParameterList());
- bool isDeclaredConst = false;
- if (m_scanner->getCurrentToken() == Token::CONST) {
- isDeclaredConst = true;
- m_scanner->next();
- }
- ptr<ParameterList> returnParameters;
- if (m_scanner->getCurrentToken() == Token::RETURNS) {
- m_scanner->next();
- returnParameters = parseParameterList();
- }
- ptr<Block> block = parseBlock();
- nodeFactory.setEndPositionFromNode(block);
- return nodeFactory.createNode<FunctionDefinition>(name, _isPublic, parameters,
- isDeclaredConst, returnParameters, block);
+ ASTNodeFactory nodeFactory(*this);
+
+ expectToken(Token::FUNCTION);
+ std::string name(expectIdentifier());
+ ptr<ParameterList> parameters(parseParameterList());
+ bool isDeclaredConst = false;
+ if (m_scanner->getCurrentToken() == Token::CONST) {
+ isDeclaredConst = true;
+ m_scanner->next();
+ }
+ ptr<ParameterList> returnParameters;
+ if (m_scanner->getCurrentToken() == Token::RETURNS) {
+ m_scanner->next();
+ returnParameters = parseParameterList();
+ }
+ ptr<Block> block = parseBlock();
+ nodeFactory.setEndPositionFromNode(block);
+ return nodeFactory.createNode<FunctionDefinition>(name, _isPublic, parameters,
+ isDeclaredConst, returnParameters, block);
}
ptr<StructDefinition> Parser::parseStructDefinition()
{
- ASTNodeFactory nodeFactory(*this);
-
- expectToken(Token::STRUCT);
- std::string name = expectIdentifier();
- vecptr<VariableDeclaration> 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<StructDefinition>(name, members);
+ ASTNodeFactory nodeFactory(*this);
+
+ expectToken(Token::STRUCT);
+ std::string name = expectIdentifier();
+ vecptr<VariableDeclaration> 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<StructDefinition>(name, members);
}
ptr<VariableDeclaration> Parser::parseVariableDeclaration()
{
- ASTNodeFactory nodeFactory(*this);
+ ASTNodeFactory nodeFactory(*this);
- ptr<TypeName> type = parseTypeName();
- nodeFactory.markEndPosition();
- std::string name = expectIdentifier();
- return nodeFactory.createNode<VariableDeclaration>(type, name);
+ ptr<TypeName> type = parseTypeName();
+ nodeFactory.markEndPosition();
+ std::string name = expectIdentifier();
+ return nodeFactory.createNode<VariableDeclaration>(type, name);
}
ptr<TypeName> Parser::parseTypeName()
{
- ptr<TypeName> type;
- Token::Value token = m_scanner->getCurrentToken();
- if (Token::IsElementaryTypeName(token)) {
- type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(token);
- m_scanner->next();
- } else if (token == Token::VAR) {
- type = ASTNodeFactory(*this).createNode<TypeName>();
- m_scanner->next();
- } else if (token == Token::MAPPING) {
- type = parseMapping();
- } else if (token == Token::IDENTIFIER) {
- type = ASTNodeFactory(*this).createNode<UserDefinedTypeName>(m_scanner->getCurrentLiteral());
- m_scanner->next();
- } else {
- throwExpectationError("Expected type name");
- }
-
- return type;
+ ptr<TypeName> type;
+ Token::Value token = m_scanner->getCurrentToken();
+ if (Token::IsElementaryTypeName(token)) {
+ type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(token);
+ m_scanner->next();
+ } else if (token == Token::VAR) {
+ type = ASTNodeFactory(*this).createNode<TypeName>();
+ m_scanner->next();
+ } else if (token == Token::MAPPING) {
+ type = parseMapping();
+ } else if (token == Token::IDENTIFIER) {
+ type = ASTNodeFactory(*this).createNode<UserDefinedTypeName>(m_scanner->getCurrentLiteral());
+ m_scanner->next();
+ } else {
+ throwExpectationError("Expected type name");
+ }
+
+ return type;
}
ptr<Mapping> 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<ElementaryTypeName> keyType;
- keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(m_scanner->getCurrentToken());
- m_scanner->next();
+ if (!Token::IsElementaryTypeName(m_scanner->getCurrentToken()))
+ throwExpectationError("Expected elementary type name for mapping key type");
+ ptr<ElementaryTypeName> keyType;
+ keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(m_scanner->getCurrentToken());
+ m_scanner->next();
- expectToken(Token::ARROW);
- ptr<TypeName> valueType = parseTypeName();
- nodeFactory.markEndPosition();
- expectToken(Token::RPAREN);
+ expectToken(Token::ARROW);
+ ptr<TypeName> valueType = parseTypeName();
+ nodeFactory.markEndPosition();
+ expectToken(Token::RPAREN);
- return nodeFactory.createNode<Mapping>(keyType, valueType);
+ return nodeFactory.createNode<Mapping>(keyType, valueType);
}
ptr<ParameterList> Parser::parseParameterList()
{
- ASTNodeFactory nodeFactory(*this);
-
- vecptr<VariableDeclaration> 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<ParameterList>(parameters);
+ ASTNodeFactory nodeFactory(*this);
+
+ vecptr<VariableDeclaration> 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<ParameterList>(parameters);
}
ptr<Block> 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<Block>();
+
+ ASTNodeFactory nodeFactory(*this);
+ expectToken(Token::LBRACE);
+ vecptr<Statement> statements;
+ while (m_scanner->getCurrentToken() != Token::RBRACE) {
+ m_scanner->next();
+ statements.push_back(parseStatement());
+ }
+ 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)
{
- 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/Parser.h b/Parser.h
index 96f1d688..65409a29 100644
--- a/Parser.h
+++ b/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 <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
@@ -32,37 +32,38 @@ class Scanner;
class Parser
{
public:
- ptr<ASTNode> parse(std::shared_ptr<Scanner> const& _scanner);
+ ptr<ASTNode> parse(std::shared_ptr<Scanner> 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<ContractDefinition> parseContractDefinition();
- ptr<FunctionDefinition> parseFunctionDefinition(bool _isPublic);
- ptr<StructDefinition> parseStructDefinition();
- ptr<VariableDeclaration> parseVariableDeclaration();
- ptr<TypeName> parseTypeName();
- ptr<Mapping> parseMapping();
- ptr<ParameterList> parseParameterList();
- ptr<Block> parseBlock();
- /// @}
+ /// Parsing functions for the AST nodes
+ /// @{
+ ptr<ContractDefinition> parseContractDefinition();
+ ptr<FunctionDefinition> parseFunctionDefinition(bool _isPublic);
+ ptr<StructDefinition> parseStructDefinition();
+ ptr<VariableDeclaration> parseVariableDeclaration();
+ ptr<TypeName> parseTypeName();
+ ptr<Mapping> parseMapping();
+ ptr<ParameterList> parseParameterList();
+ ptr<Block> parseBlock();
+ ptr<Statement> 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<Scanner> m_scanner;
+ std::shared_ptr<Scanner> m_scanner;
};
} }
diff --git a/Scanner.cpp b/Scanner.cpp
index 836e0d09..334da8e7 100644
--- a/Scanner.cpp
+++ b/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<size_type>(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<size_type>(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<int, int> CharStream::translatePositionToLineColumn(int _position) const
{
- using size_type = std::string::size_type;
- size_type searchPosition = std::min<size_type>(m_source.size(), _position);
- int lineNumber = std::count(m_source.begin(), m_source.begin() + searchPosition, '\n');
-
- size_type lineStart;
- if (searchPosition == 0) {
- lineStart = 0;
- } else {
- lineStart = m_source.rfind('\n', searchPosition - 1);
- lineStart = lineStart == std::string::npos ? 0 : lineStart + 1;
- }
-
- return std::tuple<int, int>(lineNumber, searchPosition - lineStart);
+ using size_type = std::string::size_type;
+ size_type searchPosition = std::min<size_type>(m_source.size(), _position);
+ int lineNumber = std::count(m_source.begin(), m_source.begin() + searchPosition, '\n');
+
+ size_type lineStart;
+ if (searchPosition == 0) {
+ lineStart = 0;
+ } else {
+ lineStart = m_source.rfind('\n', searchPosition - 1);
+ lineStart = lineStart == std::string::npos ? 0 : lineStart + 1;
+ }
+
+ return std::tuple<int, int>(lineNumber, searchPosition - lineStart);
}
diff --git a/Scanner.h b/Scanner.h
index 7b1408c0..4bc84111 100644
--- a/Scanner.h
+++ b/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<int, int> 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<int, int> 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<int, int> 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<int, int> 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/Token.cpp b/Token.cpp
index 6ae6456a..0264f7e8 100644
--- a/Token.cpp
+++ b/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/Token.h b/Token.h
index 4476b383..2ff5067b 100644
--- a/Token.h
+++ b/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];
};
} }