mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge branch 'develop' into natspec_export_json
This commit is contained in:
commit
df4db1de07
12
AST.cpp
12
AST.cpp
@ -378,6 +378,9 @@ void Assignment::checkTypeRequirements()
|
|||||||
{
|
{
|
||||||
m_leftHandSide->checkTypeRequirements();
|
m_leftHandSide->checkTypeRequirements();
|
||||||
m_leftHandSide->requireLValue();
|
m_leftHandSide->requireLValue();
|
||||||
|
//@todo later, assignments to structs might be possible, but not to mappings
|
||||||
|
if (!m_leftHandSide->getType()->isValueType() && !m_leftHandSide->isLocalLValue())
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Assignment to non-local non-value lvalue."));
|
||||||
m_rightHandSide->expectType(*m_leftHandSide->getType());
|
m_rightHandSide->expectType(*m_leftHandSide->getType());
|
||||||
m_type = m_leftHandSide->getType();
|
m_type = m_leftHandSide->getType();
|
||||||
if (m_assigmentOperator != Token::ASSIGN)
|
if (m_assigmentOperator != Token::ASSIGN)
|
||||||
@ -403,7 +406,7 @@ void Expression::expectType(Type const& _expectedType)
|
|||||||
|
|
||||||
void Expression::requireLValue()
|
void Expression::requireLValue()
|
||||||
{
|
{
|
||||||
if (!isLvalue())
|
if (!isLValue())
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue."));
|
BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue."));
|
||||||
m_lvalueRequested = true;
|
m_lvalueRequested = true;
|
||||||
}
|
}
|
||||||
@ -495,7 +498,8 @@ void MemberAccess::checkTypeRequirements()
|
|||||||
m_type = type.getMemberType(*m_memberName);
|
m_type = type.getMemberType(*m_memberName);
|
||||||
if (!m_type)
|
if (!m_type)
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found in " + type.toString()));
|
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found in " + type.toString()));
|
||||||
m_isLvalue = (type.getCategory() == Type::Category::STRUCT && m_type->getCategory() != Type::Category::MAPPING);
|
//@todo later, this will not always be STORAGE
|
||||||
|
m_lvalue = type.getCategory() == Type::Category::STRUCT ? LValueType::STORAGE : LValueType::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexAccess::checkTypeRequirements()
|
void IndexAccess::checkTypeRequirements()
|
||||||
@ -507,7 +511,7 @@ void IndexAccess::checkTypeRequirements()
|
|||||||
MappingType const& type = dynamic_cast<MappingType const&>(*m_base->getType());
|
MappingType const& type = dynamic_cast<MappingType const&>(*m_base->getType());
|
||||||
m_index->expectType(*type.getKeyType());
|
m_index->expectType(*type.getKeyType());
|
||||||
m_type = type.getValueType();
|
m_type = type.getValueType();
|
||||||
m_isLvalue = m_type->getCategory() != Type::Category::MAPPING;
|
m_lvalue = LValueType::STORAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Identifier::checkTypeRequirements()
|
void Identifier::checkTypeRequirements()
|
||||||
@ -521,7 +525,7 @@ void Identifier::checkTypeRequirements()
|
|||||||
if (!variable->getType())
|
if (!variable->getType())
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined."));
|
BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined."));
|
||||||
m_type = variable->getType();
|
m_type = variable->getType();
|
||||||
m_isLvalue = true;
|
m_lvalue = variable->isLocalVariable() ? LValueType::LOCAL : LValueType::STORAGE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//@todo can we unify these with TypeName::toType()?
|
//@todo can we unify these with TypeName::toType()?
|
||||||
|
23
AST.h
23
AST.h
@ -88,11 +88,16 @@ public:
|
|||||||
Declaration(Location const& _location, ASTPointer<ASTString> const& _name):
|
Declaration(Location const& _location, ASTPointer<ASTString> const& _name):
|
||||||
ASTNode(_location), m_name(_name) {}
|
ASTNode(_location), m_name(_name) {}
|
||||||
|
|
||||||
/// Returns the declared name.
|
/// @returns the declared name.
|
||||||
ASTString const& getName() const { return *m_name; }
|
ASTString const& getName() const { return *m_name; }
|
||||||
|
/// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
|
||||||
|
/// Available only after name and type resolution step.
|
||||||
|
Declaration* getScope() const { return m_scope; }
|
||||||
|
void setScope(Declaration* const& _scope) { m_scope = _scope; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ASTPointer<ASTString> m_name;
|
ASTPointer<ASTString> m_name;
|
||||||
|
Declaration* m_scope;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -237,6 +242,8 @@ public:
|
|||||||
std::shared_ptr<Type const> const& getType() const { return m_type; }
|
std::shared_ptr<Type const> const& getType() const { return m_type; }
|
||||||
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
|
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
|
||||||
|
|
||||||
|
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition*>(getScope()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
|
ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
|
||||||
|
|
||||||
@ -521,12 +528,16 @@ private:
|
|||||||
*/
|
*/
|
||||||
class Expression: public ASTNode
|
class Expression: public ASTNode
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
enum class LValueType { NONE, LOCAL, STORAGE };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Expression(Location const& _location): ASTNode(_location), m_isLvalue(false), m_lvalueRequested(false) {}
|
Expression(Location const& _location): ASTNode(_location), m_lvalue(LValueType::NONE), m_lvalueRequested(false) {}
|
||||||
virtual void checkTypeRequirements() = 0;
|
virtual void checkTypeRequirements() = 0;
|
||||||
|
|
||||||
std::shared_ptr<Type const> const& getType() const { return m_type; }
|
std::shared_ptr<Type const> const& getType() const { return m_type; }
|
||||||
bool isLvalue() const { return m_isLvalue; }
|
bool isLValue() const { return m_lvalue != LValueType::NONE; }
|
||||||
|
bool isLocalLValue() const { return m_lvalue == LValueType::LOCAL; }
|
||||||
|
|
||||||
/// Helper function, infer the type via @ref checkTypeRequirements and then check that it
|
/// Helper function, infer the type via @ref checkTypeRequirements and then check that it
|
||||||
/// is implicitly convertible to @a _expectedType. If not, throw exception.
|
/// is implicitly convertible to @a _expectedType. If not, throw exception.
|
||||||
@ -541,9 +552,9 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
//! Inferred type of the expression, only filled after a call to checkTypeRequirements().
|
//! Inferred type of the expression, only filled after a call to checkTypeRequirements().
|
||||||
std::shared_ptr<Type const> m_type;
|
std::shared_ptr<Type const> m_type;
|
||||||
//! Whether or not this expression is an lvalue, i.e. something that can be assigned to.
|
//! If this expression is an lvalue (i.e. something that can be assigned to) and is stored
|
||||||
//! This is set during calls to @a checkTypeRequirements()
|
//! locally or in storage. This is set during calls to @a checkTypeRequirements()
|
||||||
bool m_isLvalue;
|
LValueType m_lvalue;
|
||||||
//! Whether the outer expression requested the address (true) or the value (false) of this expression.
|
//! Whether the outer expression requested the address (true) or the value (false) of this expression.
|
||||||
bool m_lvalueRequested;
|
bool m_lvalueRequested;
|
||||||
};
|
};
|
||||||
|
@ -324,7 +324,7 @@ bool Compiler::visit(ExpressionStatement& _expressionStatement)
|
|||||||
{
|
{
|
||||||
Expression& expression = _expressionStatement.getExpression();
|
Expression& expression = _expressionStatement.getExpression();
|
||||||
ExpressionCompiler::compileExpression(m_context, expression);
|
ExpressionCompiler::compileExpression(m_context, expression);
|
||||||
Type::Category category = expression.getType()->getCategory();
|
// Type::Category category = expression.getType()->getCategory();
|
||||||
for (unsigned i = 0; i < expression.getType()->getSizeOnStack(); ++i)
|
for (unsigned i = 0; i < expression.getType()->getSizeOnStack(); ++i)
|
||||||
m_context << eth::Instruction::POP;
|
m_context << eth::Instruction::POP;
|
||||||
return false;
|
return false;
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* Scope - object that holds declaration of names.
|
* Scope - object that holds declaration of names.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libsolidity/Scope.h>
|
#include <libsolidity/DeclarationContainer.h>
|
||||||
#include <libsolidity/AST.h>
|
#include <libsolidity/AST.h>
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
@ -28,7 +28,7 @@ namespace dev
|
|||||||
namespace solidity
|
namespace solidity
|
||||||
{
|
{
|
||||||
|
|
||||||
bool Scope::registerDeclaration(Declaration& _declaration)
|
bool DeclarationContainer::registerDeclaration(Declaration& _declaration)
|
||||||
{
|
{
|
||||||
if (m_declarations.find(_declaration.getName()) != m_declarations.end())
|
if (m_declarations.find(_declaration.getName()) != m_declarations.end())
|
||||||
return false;
|
return false;
|
||||||
@ -36,13 +36,13 @@ bool Scope::registerDeclaration(Declaration& _declaration)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Declaration* Scope::resolveName(ASTString const& _name, bool _recursive) const
|
Declaration* DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const
|
||||||
{
|
{
|
||||||
auto result = m_declarations.find(_name);
|
auto result = m_declarations.find(_name);
|
||||||
if (result != m_declarations.end())
|
if (result != m_declarations.end())
|
||||||
return result->second;
|
return result->second;
|
||||||
if (_recursive && m_enclosingScope)
|
if (_recursive && m_enclosingContainer)
|
||||||
return m_enclosingScope->resolveName(_name, true);
|
return m_enclosingContainer->resolveName(_name, true);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -36,18 +36,20 @@ namespace solidity
|
|||||||
* Container that stores mappings betwee names and declarations. It also contains a link to the
|
* Container that stores mappings betwee names and declarations. It also contains a link to the
|
||||||
* enclosing scope.
|
* enclosing scope.
|
||||||
*/
|
*/
|
||||||
class Scope
|
class DeclarationContainer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Scope(Scope* _enclosingScope = nullptr): m_enclosingScope(_enclosingScope) {}
|
explicit DeclarationContainer(Declaration* _enclosingDeclaration = nullptr, DeclarationContainer* _enclosingContainer = nullptr):
|
||||||
|
m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {}
|
||||||
/// Registers the declaration in the scope unless its name is already declared. Returns true iff
|
/// Registers the declaration in the scope unless its name is already declared. Returns true iff
|
||||||
/// it was not yet declared.
|
/// it was not yet declared.
|
||||||
bool registerDeclaration(Declaration& _declaration);
|
bool registerDeclaration(Declaration& _declaration);
|
||||||
Declaration* resolveName(ASTString const& _name, bool _recursive = false) const;
|
Declaration* resolveName(ASTString const& _name, bool _recursive = false) const;
|
||||||
Scope* getEnclosingScope() const { return m_enclosingScope; }
|
Declaration* getEnclosingDeclaration() const { return m_enclosingDeclaration; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Scope* m_enclosingScope;
|
Declaration* m_enclosingDeclaration;
|
||||||
|
DeclarationContainer* m_enclosingContainer;
|
||||||
std::map<ASTString, Declaration*> m_declarations;
|
std::map<ASTString, Declaration*> m_declarations;
|
||||||
};
|
};
|
||||||
|
|
@ -78,9 +78,9 @@ Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name
|
|||||||
return m_currentScope->resolveName(_name, _recursive);
|
return m_currentScope->resolveName(_name, _recursive);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclarationRegistrationHelper::DeclarationRegistrationHelper(map<ASTNode const*, Scope>& _scopes,
|
DeclarationRegistrationHelper::DeclarationRegistrationHelper(map<ASTNode const*, DeclarationContainer>& _scopes,
|
||||||
ASTNode& _astRoot):
|
ASTNode& _astRoot):
|
||||||
m_scopes(_scopes), m_currentScope(&m_scopes[nullptr])
|
m_scopes(_scopes), m_currentScope(nullptr)
|
||||||
{
|
{
|
||||||
_astRoot.accept(*this);
|
_astRoot.accept(*this);
|
||||||
}
|
}
|
||||||
@ -135,31 +135,30 @@ bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node)
|
void DeclarationRegistrationHelper::enterNewSubScope(Declaration& _declaration)
|
||||||
{
|
{
|
||||||
map<ASTNode const*, Scope>::iterator iter;
|
map<ASTNode const*, DeclarationContainer>::iterator iter;
|
||||||
bool newlyAdded;
|
bool newlyAdded;
|
||||||
tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope));
|
tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, DeclarationContainer(m_currentScope, &m_scopes[m_currentScope]));
|
||||||
if (asserts(newlyAdded))
|
if (asserts(newlyAdded))
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to add new scope."));
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to add new scope."));
|
||||||
m_currentScope = &iter->second;
|
m_currentScope = &_declaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::closeCurrentScope()
|
void DeclarationRegistrationHelper::closeCurrentScope()
|
||||||
{
|
{
|
||||||
if (asserts(m_currentScope))
|
if (asserts(m_currentScope))
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Closed non-existing scope."));
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Closed non-existing scope."));
|
||||||
m_currentScope = m_currentScope->getEnclosingScope();
|
m_currentScope = m_scopes[m_currentScope].getEnclosingDeclaration();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope)
|
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope)
|
||||||
{
|
{
|
||||||
if (asserts(m_currentScope))
|
if (!m_scopes[m_currentScope].registerDeclaration(_declaration))
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration registered without scope."));
|
|
||||||
if (!m_currentScope->registerDeclaration(_declaration))
|
|
||||||
BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation())
|
BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation())
|
||||||
<< errinfo_comment("Identifier already declared."));
|
<< errinfo_comment("Identifier already declared."));
|
||||||
//@todo the exception should also contain the location of the first declaration
|
//@todo the exception should also contain the location of the first declaration
|
||||||
|
_declaration.setScope(m_currentScope);
|
||||||
if (_opensScope)
|
if (_opensScope)
|
||||||
enterNewSubScope(_declaration);
|
enterNewSubScope(_declaration);
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
#include <libsolidity/Scope.h>
|
#include <libsolidity/DeclarationContainer.h>
|
||||||
#include <libsolidity/ASTVisitor.h>
|
#include <libsolidity/ASTVisitor.h>
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
@ -61,9 +61,9 @@ private:
|
|||||||
/// Maps nodes declaring a scope to scopes, i.e. ContractDefinition and FunctionDeclaration,
|
/// Maps nodes declaring a scope to scopes, i.e. ContractDefinition and FunctionDeclaration,
|
||||||
/// where nullptr denotes the global scope. Note that structs are not scope since they do
|
/// where nullptr denotes the global scope. Note that structs are not scope since they do
|
||||||
/// not contain code.
|
/// not contain code.
|
||||||
std::map<ASTNode const*, Scope> m_scopes;
|
std::map<ASTNode const*, DeclarationContainer> m_scopes;
|
||||||
|
|
||||||
Scope* m_currentScope;
|
DeclarationContainer* m_currentScope;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,7 +73,7 @@ private:
|
|||||||
class DeclarationRegistrationHelper: private ASTVisitor
|
class DeclarationRegistrationHelper: private ASTVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeclarationRegistrationHelper(std::map<ASTNode const*, Scope>& _scopes, ASTNode& _astRoot);
|
DeclarationRegistrationHelper(std::map<ASTNode const*, DeclarationContainer>& _scopes, ASTNode& _astRoot);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool visit(ContractDefinition& _contract);
|
bool visit(ContractDefinition& _contract);
|
||||||
@ -85,12 +85,12 @@ private:
|
|||||||
void endVisit(VariableDefinition& _variableDefinition);
|
void endVisit(VariableDefinition& _variableDefinition);
|
||||||
bool visit(VariableDeclaration& _declaration);
|
bool visit(VariableDeclaration& _declaration);
|
||||||
|
|
||||||
void enterNewSubScope(ASTNode& _node);
|
void enterNewSubScope(Declaration& _declaration);
|
||||||
void closeCurrentScope();
|
void closeCurrentScope();
|
||||||
void registerDeclaration(Declaration& _declaration, bool _opensScope);
|
void registerDeclaration(Declaration& _declaration, bool _opensScope);
|
||||||
|
|
||||||
std::map<ASTNode const*, Scope>& m_scopes;
|
std::map<ASTNode const*, DeclarationContainer>& m_scopes;
|
||||||
Scope* m_currentScope;
|
Declaration* m_currentScope;
|
||||||
FunctionDefinition* m_currentFunction;
|
FunctionDefinition* m_currentFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
195
Scanner.cpp
195
Scanner.cpp
@ -194,7 +194,6 @@ Token::Value Scanner::selectToken(char _next, Token::Value _then, Token::Value _
|
|||||||
return _else;
|
return _else;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Scanner::skipWhitespace()
|
bool Scanner::skipWhitespace()
|
||||||
{
|
{
|
||||||
int const startPosition = getSourcePos();
|
int const startPosition = getSourcePos();
|
||||||
@ -204,7 +203,6 @@ bool Scanner::skipWhitespace()
|
|||||||
return getSourcePos() != startPosition;
|
return getSourcePos() != startPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Token::Value Scanner::skipSingleLineComment()
|
Token::Value Scanner::skipSingleLineComment()
|
||||||
{
|
{
|
||||||
// The line terminator at the end of the line is not considered
|
// The line terminator at the end of the line is not considered
|
||||||
@ -215,7 +213,6 @@ Token::Value Scanner::skipSingleLineComment()
|
|||||||
return Token::WHITESPACE;
|
return Token::WHITESPACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For the moment this function simply consumes a single line triple slash doc comment
|
|
||||||
Token::Value Scanner::scanDocumentationComment()
|
Token::Value Scanner::scanDocumentationComment()
|
||||||
{
|
{
|
||||||
LiteralScope literal(this, LITERAL_TYPE_COMMENT);
|
LiteralScope literal(this, LITERAL_TYPE_COMMENT);
|
||||||
@ -545,14 +542,12 @@ Token::Value Scanner::scanString()
|
|||||||
return Token::STRING_LITERAL;
|
return Token::STRING_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Scanner::scanDecimalDigits()
|
void Scanner::scanDecimalDigits()
|
||||||
{
|
{
|
||||||
while (isDecimalDigit(m_char))
|
while (isDecimalDigit(m_char))
|
||||||
addLiteralCharAndAdvance();
|
addLiteralCharAndAdvance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Token::Value Scanner::scanNumber(char _charSeen)
|
Token::Value Scanner::scanNumber(char _charSeen)
|
||||||
{
|
{
|
||||||
enum { DECIMAL, HEX, BINARY } kind = DECIMAL;
|
enum { DECIMAL, HEX, BINARY } kind = DECIMAL;
|
||||||
@ -623,186 +618,18 @@ Token::Value Scanner::scanNumber(char _charSeen)
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Keyword Matcher
|
// Keyword Matcher
|
||||||
|
|
||||||
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
|
|
||||||
KEYWORD_GROUP('a') \
|
|
||||||
KEYWORD("address", Token::ADDRESS) \
|
|
||||||
KEYWORD_GROUP('b') \
|
|
||||||
KEYWORD("break", Token::BREAK) \
|
|
||||||
KEYWORD("bool", Token::BOOL) \
|
|
||||||
KEYWORD_GROUP('c') \
|
|
||||||
KEYWORD("case", Token::CASE) \
|
|
||||||
KEYWORD("const", Token::CONST) \
|
|
||||||
KEYWORD("continue", Token::CONTINUE) \
|
|
||||||
KEYWORD("contract", Token::CONTRACT) \
|
|
||||||
KEYWORD_GROUP('d') \
|
|
||||||
KEYWORD("default", Token::DEFAULT) \
|
|
||||||
KEYWORD("delete", Token::DELETE) \
|
|
||||||
KEYWORD("do", Token::DO) \
|
|
||||||
KEYWORD_GROUP('e') \
|
|
||||||
KEYWORD("else", Token::ELSE) \
|
|
||||||
KEYWORD("extends", Token::EXTENDS) \
|
|
||||||
KEYWORD_GROUP('f') \
|
|
||||||
KEYWORD("false", Token::FALSE_LITERAL) \
|
|
||||||
KEYWORD("for", Token::FOR) \
|
|
||||||
KEYWORD("function", Token::FUNCTION) \
|
|
||||||
KEYWORD_GROUP('h') \
|
|
||||||
KEYWORD("hash", Token::HASH) \
|
|
||||||
KEYWORD("hash8", Token::HASH8) \
|
|
||||||
KEYWORD("hash16", Token::HASH16) \
|
|
||||||
KEYWORD("hash24", Token::HASH24) \
|
|
||||||
KEYWORD("hash32", Token::HASH32) \
|
|
||||||
KEYWORD("hash40", Token::HASH40) \
|
|
||||||
KEYWORD("hash48", Token::HASH48) \
|
|
||||||
KEYWORD("hash56", Token::HASH56) \
|
|
||||||
KEYWORD("hash64", Token::HASH64) \
|
|
||||||
KEYWORD("hash72", Token::HASH72) \
|
|
||||||
KEYWORD("hash80", Token::HASH80) \
|
|
||||||
KEYWORD("hash88", Token::HASH88) \
|
|
||||||
KEYWORD("hash96", Token::HASH96) \
|
|
||||||
KEYWORD("hash104", Token::HASH104) \
|
|
||||||
KEYWORD("hash112", Token::HASH112) \
|
|
||||||
KEYWORD("hash120", Token::HASH120) \
|
|
||||||
KEYWORD("hash128", Token::HASH128) \
|
|
||||||
KEYWORD("hash136", Token::HASH136) \
|
|
||||||
KEYWORD("hash144", Token::HASH144) \
|
|
||||||
KEYWORD("hash152", Token::HASH152) \
|
|
||||||
KEYWORD("hash160", Token::HASH160) \
|
|
||||||
KEYWORD("hash168", Token::HASH168) \
|
|
||||||
KEYWORD("hash178", Token::HASH176) \
|
|
||||||
KEYWORD("hash184", Token::HASH184) \
|
|
||||||
KEYWORD("hash192", Token::HASH192) \
|
|
||||||
KEYWORD("hash200", Token::HASH200) \
|
|
||||||
KEYWORD("hash208", Token::HASH208) \
|
|
||||||
KEYWORD("hash216", Token::HASH216) \
|
|
||||||
KEYWORD("hash224", Token::HASH224) \
|
|
||||||
KEYWORD("hash232", Token::HASH232) \
|
|
||||||
KEYWORD("hash240", Token::HASH240) \
|
|
||||||
KEYWORD("hash248", Token::HASH248) \
|
|
||||||
KEYWORD("hash256", Token::HASH256) \
|
|
||||||
KEYWORD_GROUP('i') \
|
|
||||||
KEYWORD("if", Token::IF) \
|
|
||||||
KEYWORD("in", Token::IN) \
|
|
||||||
KEYWORD("int", Token::INT) \
|
|
||||||
KEYWORD("int8", Token::INT8) \
|
|
||||||
KEYWORD("int16", Token::INT16) \
|
|
||||||
KEYWORD("int24", Token::INT24) \
|
|
||||||
KEYWORD("int32", Token::INT32) \
|
|
||||||
KEYWORD("int40", Token::INT40) \
|
|
||||||
KEYWORD("int48", Token::INT48) \
|
|
||||||
KEYWORD("int56", Token::INT56) \
|
|
||||||
KEYWORD("int64", Token::INT64) \
|
|
||||||
KEYWORD("int72", Token::INT72) \
|
|
||||||
KEYWORD("int80", Token::INT80) \
|
|
||||||
KEYWORD("int88", Token::INT88) \
|
|
||||||
KEYWORD("int96", Token::INT96) \
|
|
||||||
KEYWORD("int104", Token::INT104) \
|
|
||||||
KEYWORD("int112", Token::INT112) \
|
|
||||||
KEYWORD("int120", Token::INT120) \
|
|
||||||
KEYWORD("int128", Token::INT128) \
|
|
||||||
KEYWORD("int136", Token::INT136) \
|
|
||||||
KEYWORD("int144", Token::INT144) \
|
|
||||||
KEYWORD("int152", Token::INT152) \
|
|
||||||
KEYWORD("int160", Token::INT160) \
|
|
||||||
KEYWORD("int168", Token::INT168) \
|
|
||||||
KEYWORD("int178", Token::INT176) \
|
|
||||||
KEYWORD("int184", Token::INT184) \
|
|
||||||
KEYWORD("int192", Token::INT192) \
|
|
||||||
KEYWORD("int200", Token::INT200) \
|
|
||||||
KEYWORD("int208", Token::INT208) \
|
|
||||||
KEYWORD("int216", Token::INT216) \
|
|
||||||
KEYWORD("int224", Token::INT224) \
|
|
||||||
KEYWORD("int232", Token::INT232) \
|
|
||||||
KEYWORD("int240", Token::INT240) \
|
|
||||||
KEYWORD("int248", Token::INT248) \
|
|
||||||
KEYWORD("int256", Token::INT256) \
|
|
||||||
KEYWORD_GROUP('l') \
|
|
||||||
KEYWORD_GROUP('m') \
|
|
||||||
KEYWORD("mapping", Token::MAPPING) \
|
|
||||||
KEYWORD_GROUP('n') \
|
|
||||||
KEYWORD("new", Token::NEW) \
|
|
||||||
KEYWORD("null", Token::NULL_LITERAL) \
|
|
||||||
KEYWORD_GROUP('p') \
|
|
||||||
KEYWORD("private", Token::PRIVATE) \
|
|
||||||
KEYWORD("public", Token::PUBLIC) \
|
|
||||||
KEYWORD_GROUP('r') \
|
|
||||||
KEYWORD("real", Token::REAL) \
|
|
||||||
KEYWORD("return", Token::RETURN) \
|
|
||||||
KEYWORD("returns", Token::RETURNS) \
|
|
||||||
KEYWORD_GROUP('s') \
|
|
||||||
KEYWORD("string", Token::STRING_TYPE) \
|
|
||||||
KEYWORD("struct", Token::STRUCT) \
|
|
||||||
KEYWORD("switch", Token::SWITCH) \
|
|
||||||
KEYWORD_GROUP('t') \
|
|
||||||
KEYWORD("text", Token::TEXT) \
|
|
||||||
KEYWORD("true", Token::TRUE_LITERAL) \
|
|
||||||
KEYWORD_GROUP('u') \
|
|
||||||
KEYWORD("uint", Token::UINT) \
|
|
||||||
KEYWORD("uint8", Token::UINT8) \
|
|
||||||
KEYWORD("uint16", Token::UINT16) \
|
|
||||||
KEYWORD("uint24", Token::UINT24) \
|
|
||||||
KEYWORD("uint32", Token::UINT32) \
|
|
||||||
KEYWORD("uint40", Token::UINT40) \
|
|
||||||
KEYWORD("uint48", Token::UINT48) \
|
|
||||||
KEYWORD("uint56", Token::UINT56) \
|
|
||||||
KEYWORD("uint64", Token::UINT64) \
|
|
||||||
KEYWORD("uint72", Token::UINT72) \
|
|
||||||
KEYWORD("uint80", Token::UINT80) \
|
|
||||||
KEYWORD("uint88", Token::UINT88) \
|
|
||||||
KEYWORD("uint96", Token::UINT96) \
|
|
||||||
KEYWORD("uint104", Token::UINT104) \
|
|
||||||
KEYWORD("uint112", Token::UINT112) \
|
|
||||||
KEYWORD("uint120", Token::UINT120) \
|
|
||||||
KEYWORD("uint128", Token::UINT128) \
|
|
||||||
KEYWORD("uint136", Token::UINT136) \
|
|
||||||
KEYWORD("uint144", Token::UINT144) \
|
|
||||||
KEYWORD("uint152", Token::UINT152) \
|
|
||||||
KEYWORD("uint160", Token::UINT160) \
|
|
||||||
KEYWORD("uint168", Token::UINT168) \
|
|
||||||
KEYWORD("uint178", Token::UINT176) \
|
|
||||||
KEYWORD("uint184", Token::UINT184) \
|
|
||||||
KEYWORD("uint192", Token::UINT192) \
|
|
||||||
KEYWORD("uint200", Token::UINT200) \
|
|
||||||
KEYWORD("uint208", Token::UINT208) \
|
|
||||||
KEYWORD("uint216", Token::UINT216) \
|
|
||||||
KEYWORD("uint224", Token::UINT224) \
|
|
||||||
KEYWORD("uint232", Token::UINT232) \
|
|
||||||
KEYWORD("uint240", Token::UINT240) \
|
|
||||||
KEYWORD("uint248", Token::UINT248) \
|
|
||||||
KEYWORD("uint256", Token::UINT256) \
|
|
||||||
KEYWORD("ureal", Token::UREAL) \
|
|
||||||
KEYWORD_GROUP('v') \
|
|
||||||
KEYWORD("var", Token::VAR) \
|
|
||||||
KEYWORD_GROUP('w') \
|
|
||||||
KEYWORD("while", Token::WHILE) \
|
|
||||||
|
|
||||||
|
static Token::Value keywordOrIdentifierToken(string const& _input)
|
||||||
static Token::Value KeywordOrIdentifierToken(string const& _input)
|
|
||||||
{
|
{
|
||||||
if (asserts(!_input.empty()))
|
// The following macros are used inside TOKEN_LIST and cause non-keyword tokens to be ignored
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError());
|
// and keywords to be put inside the keywords variable.
|
||||||
int const kMinLength = 2;
|
#define KEYWORD(name, string, precedence) {string, Token::name},
|
||||||
int const kMaxLength = 10;
|
#define TOKEN(name, string, precedence)
|
||||||
if (_input.size() < kMinLength || _input.size() > kMaxLength)
|
static const map<string, Token::Value> keywords({TOKEN_LIST(TOKEN, KEYWORD)});
|
||||||
return Token::IDENTIFIER;
|
#undef KEYWORD
|
||||||
switch (_input[0])
|
#undef TOKEN
|
||||||
{
|
auto it = keywords.find(_input);
|
||||||
default:
|
return it == keywords.end() ? Token::IDENTIFIER : it->second;
|
||||||
#define KEYWORD_GROUP_CASE(ch) \
|
|
||||||
break; \
|
|
||||||
case ch:
|
|
||||||
#define KEYWORD(keyword, token) \
|
|
||||||
{ \
|
|
||||||
/* 'keyword' is a char array, so sizeof(keyword) is */ \
|
|
||||||
/* strlen(keyword) plus 1 for the NUL char. */ \
|
|
||||||
int const keywordLength = sizeof(keyword) - 1; \
|
|
||||||
BOOST_STATIC_ASSERT(keywordLength >= kMinLength); \
|
|
||||||
BOOST_STATIC_ASSERT(keywordLength <= kMaxLength); \
|
|
||||||
if (_input == keyword) \
|
|
||||||
return token; \
|
|
||||||
}
|
|
||||||
KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
|
|
||||||
}
|
|
||||||
return Token::IDENTIFIER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Value Scanner::scanIdentifierOrKeyword()
|
Token::Value Scanner::scanIdentifierOrKeyword()
|
||||||
@ -815,7 +642,7 @@ Token::Value Scanner::scanIdentifierOrKeyword()
|
|||||||
while (isIdentifierPart(m_char))
|
while (isIdentifierPart(m_char))
|
||||||
addLiteralCharAndAdvance();
|
addLiteralCharAndAdvance();
|
||||||
literal.complete();
|
literal.complete();
|
||||||
return KeywordOrIdentifierToken(m_nextToken.literal);
|
return keywordOrIdentifierToken(m_nextToken.literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
char CharStream::advanceAndGet(size_t _chars)
|
char CharStream::advanceAndGet(size_t _chars)
|
||||||
|
14
Token.h
14
Token.h
@ -314,25 +314,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Predicates
|
// Predicates
|
||||||
static bool isKeyword(Value tok) { return m_tokenType[tok] == 'K'; }
|
|
||||||
static bool isIdentifier(Value tok) { return tok == IDENTIFIER; }
|
|
||||||
static bool isElementaryTypeName(Value tok) { return INT <= tok && tok < TYPES_END; }
|
static bool isElementaryTypeName(Value tok) { return INT <= tok && tok < TYPES_END; }
|
||||||
static bool isAssignmentOp(Value tok) { return ASSIGN <= tok && tok <= ASSIGN_MOD; }
|
static bool isAssignmentOp(Value tok) { return ASSIGN <= tok && tok <= ASSIGN_MOD; }
|
||||||
static bool isBinaryOp(Value op) { return COMMA <= op && op <= MOD; }
|
static bool isBinaryOp(Value op) { return COMMA <= op && op <= MOD; }
|
||||||
static bool isTruncatingBinaryOp(Value op) { return BIT_OR <= op && op <= SHR; }
|
|
||||||
static bool isArithmeticOp(Value op) { return ADD <= op && op <= MOD; }
|
static bool isArithmeticOp(Value op) { return ADD <= op && op <= MOD; }
|
||||||
static bool isCompareOp(Value op) { return EQ <= op && op <= IN; }
|
static bool isCompareOp(Value op) { return EQ <= op && op <= IN; }
|
||||||
static bool isOrderedRelationalCompareOp(Value op)
|
|
||||||
{
|
|
||||||
return op == LT || op == LTE || op == GT || op == GTE;
|
|
||||||
}
|
|
||||||
static bool isEqualityOp(Value op) { return op == EQ; }
|
|
||||||
static bool isInequalityOp(Value op) { return op == NE; }
|
|
||||||
static bool isArithmeticCompareOp(Value op)
|
|
||||||
{
|
|
||||||
return isOrderedRelationalCompareOp(op) ||
|
|
||||||
isEqualityOp(op) || isInequalityOp(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Value AssignmentToBinaryOp(Value op)
|
static Value AssignmentToBinaryOp(Value op)
|
||||||
{
|
{
|
||||||
|
@ -295,9 +295,9 @@ u256 StructType::getStorageOffsetOfMember(string const& _name) const
|
|||||||
u256 offset;
|
u256 offset;
|
||||||
for (ASTPointer<VariableDeclaration> variable: m_struct.getMembers())
|
for (ASTPointer<VariableDeclaration> variable: m_struct.getMembers())
|
||||||
{
|
{
|
||||||
offset += variable->getType()->getStorageSize();
|
|
||||||
if (variable->getName() == _name)
|
if (variable->getName() == _name)
|
||||||
return offset;
|
return offset;
|
||||||
|
offset += variable->getType()->getStorageSize();
|
||||||
}
|
}
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested."));
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested."));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user