mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Corrected indentation.
This commit is contained in:
parent
0a1ebe4f51
commit
c3faa433ef
22
AST.cpp
22
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
|
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
228
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
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
10
BaseTypes.h
10
BaseTypes.h
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
356
Parser.cpp
356
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
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
73
Parser.h
73
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
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
806
Scanner.cpp
806
Scanner.cpp
@ -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
296
Scanner.h
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
@ -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
554
Token.h
@ -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];
|
||||||
};
|
};
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
Loading…
Reference in New Issue
Block a user