mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Syntax changes for catching custom errors.
This commit is contained in:
parent
b3261d7b0f
commit
edf3529db6
@ -994,9 +994,10 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement)
|
|||||||
TryCatchClause const* panicClause = nullptr;
|
TryCatchClause const* panicClause = nullptr;
|
||||||
TryCatchClause const* errorClause = nullptr;
|
TryCatchClause const* errorClause = nullptr;
|
||||||
TryCatchClause const* lowLevelClause = nullptr;
|
TryCatchClause const* lowLevelClause = nullptr;
|
||||||
|
map<ErrorDefinition const*, TryCatchClause const*> seenErrors;
|
||||||
for (auto const& clause: _tryStatement.clauses() | ranges::views::drop_exactly(1) | views::dereferenceChecked)
|
for (auto const& clause: _tryStatement.clauses() | ranges::views::drop_exactly(1) | views::dereferenceChecked)
|
||||||
{
|
{
|
||||||
if (clause.errorName() == "")
|
if (clause.kind() == TryCatchClause::Kind::Fallback)
|
||||||
{
|
{
|
||||||
if (lowLevelClause)
|
if (lowLevelClause)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
@ -1022,59 +1023,85 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement)
|
|||||||
"). You need at least a Byzantium-compatible EVM or use `catch { ... }`."
|
"). You need at least a Byzantium-compatible EVM or use `catch { ... }`."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else if (clause.errorName() == "Error" || clause.errorName() == "Panic")
|
|
||||||
{
|
|
||||||
if (!m_evmVersion.supportsReturndata())
|
|
||||||
m_errorReporter.typeError(
|
|
||||||
1812_error,
|
|
||||||
clause.location(),
|
|
||||||
"This catch clause type cannot be used on the selected EVM version (" +
|
|
||||||
m_evmVersion.name() +
|
|
||||||
"). You need at least a Byzantium-compatible EVM or use `catch { ... }`."
|
|
||||||
);
|
|
||||||
|
|
||||||
if (clause.errorName() == "Error")
|
if (!m_evmVersion.supportsReturndata())
|
||||||
{
|
m_errorReporter.typeError(
|
||||||
if (errorClause)
|
1812_error,
|
||||||
m_errorReporter.typeError(
|
clause.location(),
|
||||||
1036_error,
|
"This catch clause type cannot be used on the selected EVM version (" +
|
||||||
clause.location(),
|
m_evmVersion.name() +
|
||||||
SecondarySourceLocation{}.append("The first clause is here:", errorClause->location()),
|
"). You need at least a Byzantium-compatible EVM or use `catch { ... }`."
|
||||||
"This try statement already has an \"Error\" catch clause."
|
);
|
||||||
);
|
|
||||||
errorClause = &clause;
|
if (clause.kind() == TryCatchClause::Kind::Error)
|
||||||
if (
|
{
|
||||||
!clause.parameters() ||
|
if (errorClause)
|
||||||
clause.parameters()->parameters().size() != 1 ||
|
m_errorReporter.typeError(
|
||||||
*clause.parameters()->parameters().front()->type() != *TypeProvider::stringMemory()
|
1036_error,
|
||||||
)
|
clause.location(),
|
||||||
m_errorReporter.typeError(2943_error, clause.location(), "Expected `catch Error(string memory ...) { ... }`.");
|
SecondarySourceLocation{}.append("The first clause is here:", errorClause->location()),
|
||||||
}
|
"This try statement already has an \"Error\" catch clause."
|
||||||
else
|
);
|
||||||
{
|
errorClause = &clause;
|
||||||
if (panicClause)
|
if (
|
||||||
m_errorReporter.typeError(
|
!clause.parameters() ||
|
||||||
6732_error,
|
clause.parameters()->parameters().size() != 1 ||
|
||||||
clause.location(),
|
*clause.parameters()->parameters().front()->type() != *TypeProvider::stringMemory()
|
||||||
SecondarySourceLocation{}.append("The first clause is here:", panicClause->location()),
|
)
|
||||||
"This try statement already has a \"Panic\" catch clause."
|
m_errorReporter.typeError(2943_error, clause.location(), "Expected `catch Error(string memory ...) { ... }`.");
|
||||||
);
|
}
|
||||||
panicClause = &clause;
|
else if (clause.kind() == TryCatchClause::Kind::Panic)
|
||||||
if (
|
{
|
||||||
!clause.parameters() ||
|
if (panicClause)
|
||||||
clause.parameters()->parameters().size() != 1 ||
|
m_errorReporter.typeError(
|
||||||
*clause.parameters()->parameters().front()->type() != *TypeProvider::uint256()
|
6732_error,
|
||||||
)
|
clause.location(),
|
||||||
m_errorReporter.typeError(1271_error, clause.location(), "Expected `catch Panic(uint ...) { ... }`.");
|
SecondarySourceLocation{}.append("The first clause is here:", panicClause->location()),
|
||||||
}
|
"This try statement already has a \"Panic\" catch clause."
|
||||||
|
);
|
||||||
|
panicClause = &clause;
|
||||||
|
if (
|
||||||
|
!clause.parameters() ||
|
||||||
|
clause.parameters()->parameters().size() != 1 ||
|
||||||
|
*clause.parameters()->parameters().front()->type() != *TypeProvider::uint256()
|
||||||
|
)
|
||||||
|
m_errorReporter.typeError(1271_error, clause.location(), "Expected `catch Panic(uint ...) { ... }`.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_errorReporter.typeError(
|
{
|
||||||
3542_error,
|
solAssert(clause.kind() == TryCatchClause::Kind::UserDefined, "");
|
||||||
clause.location(),
|
solAssert(*clause.errorName().annotation().requiredLookup == VirtualLookup::Static, "");
|
||||||
"Invalid catch clause name. Expected either `catch (...)`, `catch Error(...)`, or `catch Panic(...)`."
|
ErrorDefinition const* error = dynamic_cast<ErrorDefinition const*>(clause.errorName().annotation().referencedDeclaration);
|
||||||
);
|
if (!error)
|
||||||
|
{
|
||||||
|
m_errorReporter.typeError(1178_error, clause.location(), "Expected the name of an error.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!seenErrors.emplace(error, &clause).second)
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
6853_error,
|
||||||
|
clause.location(),
|
||||||
|
SecondarySourceLocation{}.append("The first clause is here:", seenErrors[error]->location()),
|
||||||
|
"This try statement already has a \"" + error->name() + "\" catch clause."
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
!clause.parameters() ||
|
||||||
|
clause.parameters()->parameters().size() != error->parameters().size()
|
||||||
|
)
|
||||||
|
m_errorReporter.typeError(1271_error, clause.location(), "Expected `catch Panic(uint ...) { ... }`.");
|
||||||
|
else
|
||||||
|
for (auto&& [varDecl, parameter]: ranges::views::zip(clause.parameters()->parameters(), error->parameters()))
|
||||||
|
if (*varDecl->type() != *parameter->type())
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
63958_error,
|
||||||
|
varDecl->location(),
|
||||||
|
("Expected a parameter of type \"" + parameter->type()->toString(true) + "\" ") +
|
||||||
|
("but got \"" + varDecl->type()->toString(true) + "\"")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -856,13 +856,14 @@ string Literal::getChecksummedAddress() const
|
|||||||
TryCatchClause const* TryStatement::successClause() const
|
TryCatchClause const* TryStatement::successClause() const
|
||||||
{
|
{
|
||||||
solAssert(m_clauses.size() > 0, "");
|
solAssert(m_clauses.size() > 0, "");
|
||||||
|
solAssert(m_clauses.front()->kind() == TryCatchClause::Kind::Success, "");
|
||||||
return m_clauses[0].get();
|
return m_clauses[0].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
TryCatchClause const* TryStatement::panicClause() const
|
TryCatchClause const* TryStatement::panicClause() const
|
||||||
{
|
{
|
||||||
for (size_t i = 1; i < m_clauses.size(); ++i)
|
for (size_t i = 1; i < m_clauses.size(); ++i)
|
||||||
if (m_clauses[i]->errorName() == "Panic")
|
if (m_clauses[i]->kind() == TryCatchClause::Kind::Panic)
|
||||||
return m_clauses[i].get();
|
return m_clauses[i].get();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -870,7 +871,7 @@ TryCatchClause const* TryStatement::panicClause() const
|
|||||||
TryCatchClause const* TryStatement::errorClause() const
|
TryCatchClause const* TryStatement::errorClause() const
|
||||||
{
|
{
|
||||||
for (size_t i = 1; i < m_clauses.size(); ++i)
|
for (size_t i = 1; i < m_clauses.size(); ++i)
|
||||||
if (m_clauses[i]->errorName() == "Error")
|
if (m_clauses[i]->kind() == TryCatchClause::Kind::Error)
|
||||||
return m_clauses[i].get();
|
return m_clauses[i].get();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -878,7 +879,7 @@ TryCatchClause const* TryStatement::errorClause() const
|
|||||||
TryCatchClause const* TryStatement::fallbackClause() const
|
TryCatchClause const* TryStatement::fallbackClause() const
|
||||||
{
|
{
|
||||||
for (size_t i = 1; i < m_clauses.size(); ++i)
|
for (size_t i = 1; i < m_clauses.size(); ++i)
|
||||||
if (m_clauses[i]->errorName().empty())
|
if (m_clauses[i]->kind() == TryCatchClause::Kind::Fallback)
|
||||||
return m_clauses[i].get();
|
return m_clauses[i].get();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1503,29 +1503,46 @@ private:
|
|||||||
class TryCatchClause: public ASTNode, public Scopable, public ScopeOpener
|
class TryCatchClause: public ASTNode, public Scopable, public ScopeOpener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum Kind
|
||||||
|
{
|
||||||
|
Success,
|
||||||
|
Panic,
|
||||||
|
Error,
|
||||||
|
Fallback,
|
||||||
|
UserDefined
|
||||||
|
};
|
||||||
|
|
||||||
TryCatchClause(
|
TryCatchClause(
|
||||||
int64_t _id,
|
int64_t _id,
|
||||||
SourceLocation const& _location,
|
SourceLocation const& _location,
|
||||||
ASTPointer<ASTString> _errorName,
|
Kind _kind,
|
||||||
|
ASTPointer<IdentifierPath> _errorName,
|
||||||
ASTPointer<ParameterList> _parameters,
|
ASTPointer<ParameterList> _parameters,
|
||||||
ASTPointer<Block> _block
|
ASTPointer<Block> _block
|
||||||
):
|
):
|
||||||
ASTNode(_id, _location),
|
ASTNode(_id, _location),
|
||||||
|
m_kind(_kind),
|
||||||
m_errorName(std::move(_errorName)),
|
m_errorName(std::move(_errorName)),
|
||||||
m_parameters(std::move(_parameters)),
|
m_parameters(std::move(_parameters)),
|
||||||
m_block(std::move(_block))
|
m_block(std::move(_block))
|
||||||
{}
|
{
|
||||||
|
solAssert(!!m_errorName == (m_kind == Kind::UserDefined), "");
|
||||||
|
}
|
||||||
void accept(ASTVisitor& _visitor) override;
|
void accept(ASTVisitor& _visitor) override;
|
||||||
void accept(ASTConstVisitor& _visitor) const override;
|
void accept(ASTConstVisitor& _visitor) const override;
|
||||||
|
|
||||||
ASTString const& errorName() const { return *m_errorName; }
|
|
||||||
|
Kind kind() const { return m_kind; }
|
||||||
|
/// @returns the name of the error. Should only be called if catch kind is UserDefined.
|
||||||
|
IdentifierPath const& errorName() const { return *m_errorName; }
|
||||||
ParameterList const* parameters() const { return m_parameters.get(); }
|
ParameterList const* parameters() const { return m_parameters.get(); }
|
||||||
Block const& block() const { return *m_block; }
|
Block const& block() const { return *m_block; }
|
||||||
|
|
||||||
TryCatchClauseAnnotation& annotation() const override;
|
TryCatchClauseAnnotation& annotation() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ASTPointer<ASTString> m_errorName;
|
Kind m_kind;
|
||||||
|
ASTPointer<IdentifierPath> m_errorName;
|
||||||
ASTPointer<ParameterList> m_parameters;
|
ASTPointer<ParameterList> m_parameters;
|
||||||
ASTPointer<Block> m_block;
|
ASTPointer<Block> m_block;
|
||||||
};
|
};
|
||||||
@ -1535,6 +1552,8 @@ private:
|
|||||||
* Syntax:
|
* Syntax:
|
||||||
* try <call> returns (uint x, uint y) {
|
* try <call> returns (uint x, uint y) {
|
||||||
* // success code
|
* // success code
|
||||||
|
* } catch Custom(uint data) {
|
||||||
|
* // custom error handler
|
||||||
* } catch Panic(uint errorCode) {
|
* } catch Panic(uint errorCode) {
|
||||||
* // panic
|
* // panic
|
||||||
* } catch Error(string memory cause) {
|
* } catch Error(string memory cause) {
|
||||||
|
|||||||
@ -578,7 +578,10 @@ bool ASTJsonConverter::visit(IfStatement const& _node)
|
|||||||
bool ASTJsonConverter::visit(TryCatchClause const& _node)
|
bool ASTJsonConverter::visit(TryCatchClause const& _node)
|
||||||
{
|
{
|
||||||
setJsonNode(_node, "TryCatchClause", {
|
setJsonNode(_node, "TryCatchClause", {
|
||||||
make_pair("errorName", _node.errorName()),
|
make_pair("kind", catchClauseKind(_node.kind())),
|
||||||
|
make_pair("errorName", toJsonOrNull(
|
||||||
|
_node.kind() == TryCatchClause::Kind::UserDefined ? &_node.errorName() : nullptr
|
||||||
|
)),
|
||||||
make_pair("parameters", toJsonOrNull(_node.parameters())),
|
make_pair("parameters", toJsonOrNull(_node.parameters())),
|
||||||
make_pair("block", toJson(_node.block()))
|
make_pair("block", toJson(_node.block()))
|
||||||
});
|
});
|
||||||
@ -931,6 +934,19 @@ string ASTJsonConverter::functionCallKind(FunctionCallKind _kind)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string ASTJsonConverter::catchClauseKind(TryCatchClause::Kind _kind)
|
||||||
|
{
|
||||||
|
switch (_kind)
|
||||||
|
{
|
||||||
|
case TryCatchClause::Kind::Success: return "success";
|
||||||
|
case TryCatchClause::Kind::Panic: return "panic";
|
||||||
|
case TryCatchClause::Kind::Error: return "error";
|
||||||
|
case TryCatchClause::Kind::Fallback: return "fallback";
|
||||||
|
case TryCatchClause::Kind::UserDefined: return "userDefined";
|
||||||
|
}
|
||||||
|
solAssert(false, "Unknown kind of catch clause.");
|
||||||
|
}
|
||||||
|
|
||||||
string ASTJsonConverter::literalTokenKind(Token _token)
|
string ASTJsonConverter::literalTokenKind(Token _token)
|
||||||
{
|
{
|
||||||
switch (_token)
|
switch (_token)
|
||||||
|
|||||||
@ -153,6 +153,7 @@ private:
|
|||||||
static std::string location(VariableDeclaration::Location _location);
|
static std::string location(VariableDeclaration::Location _location);
|
||||||
static std::string contractKind(ContractKind _kind);
|
static std::string contractKind(ContractKind _kind);
|
||||||
static std::string functionCallKind(FunctionCallKind _kind);
|
static std::string functionCallKind(FunctionCallKind _kind);
|
||||||
|
static std::string catchClauseKind(TryCatchClause::Kind _kind);
|
||||||
static std::string literalTokenKind(Token _token);
|
static std::string literalTokenKind(Token _token);
|
||||||
static std::string type(Expression const& _expression);
|
static std::string type(Expression const& _expression);
|
||||||
static std::string type(VariableDeclaration const& _varDecl);
|
static std::string type(VariableDeclaration const& _varDecl);
|
||||||
|
|||||||
@ -642,7 +642,8 @@ ASTPointer<TryCatchClause> ASTJsonImporter::createTryCatchClause(Json::Value con
|
|||||||
{
|
{
|
||||||
return createASTNode<TryCatchClause>(
|
return createASTNode<TryCatchClause>(
|
||||||
_node,
|
_node,
|
||||||
memberAsASTString(_node, "errorName"),
|
tryCatchClauseKind(_node),
|
||||||
|
nullOrCast<IdentifierPath>(member(_node, "errorName")),
|
||||||
nullOrCast<ParameterList>(member(_node, "parameters")),
|
nullOrCast<ParameterList>(member(_node, "parameters")),
|
||||||
convertJsonToASTNode<Block>(member(_node, "block"))
|
convertJsonToASTNode<Block>(member(_node, "block"))
|
||||||
);
|
);
|
||||||
@ -959,6 +960,24 @@ bool ASTJsonImporter::memberAsBool(Json::Value const& _node, string const& _name
|
|||||||
|
|
||||||
// =========== JSON to definition helpers =======================
|
// =========== JSON to definition helpers =======================
|
||||||
|
|
||||||
|
TryCatchClause::Kind ASTJsonImporter::tryCatchClauseKind(Json::Value const& _node)
|
||||||
|
{
|
||||||
|
astAssert(!member(_node, "kind").isNull(), "");
|
||||||
|
if (_node["kind"].asString() == "success")
|
||||||
|
return TryCatchClause::Kind::Success;
|
||||||
|
else if (_node["kind"].asString() == "error")
|
||||||
|
return TryCatchClause::Kind::Error;
|
||||||
|
else if (_node["kind"].asString() == "panic")
|
||||||
|
return TryCatchClause::Kind::Panic;
|
||||||
|
else if (_node["kind"].asString() == "fallback")
|
||||||
|
return TryCatchClause::Kind::Fallback;
|
||||||
|
else if (_node["kind"].asString() == "userDefined")
|
||||||
|
return TryCatchClause::Kind::UserDefined;
|
||||||
|
else
|
||||||
|
astAssert(false, "Unknown try catch clause kind");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
ContractKind ASTJsonImporter::contractKind(Json::Value const& _node)
|
ContractKind ASTJsonImporter::contractKind(Json::Value const& _node)
|
||||||
{
|
{
|
||||||
ContractKind kind;
|
ContractKind kind;
|
||||||
|
|||||||
@ -144,6 +144,7 @@ private:
|
|||||||
Visibility visibility(Json::Value const& _node);
|
Visibility visibility(Json::Value const& _node);
|
||||||
StateMutability stateMutability(Json::Value const& _node);
|
StateMutability stateMutability(Json::Value const& _node);
|
||||||
VariableDeclaration::Location location(Json::Value const& _node);
|
VariableDeclaration::Location location(Json::Value const& _node);
|
||||||
|
TryCatchClause::Kind tryCatchClauseKind(Json::Value const& _node);
|
||||||
ContractKind contractKind(Json::Value const& _node);
|
ContractKind contractKind(Json::Value const& _node);
|
||||||
Token literalTokenKind(Json::Value const& _node);
|
Token literalTokenKind(Json::Value const& _node);
|
||||||
Literal::SubDenomination subdenomination(Json::Value const& _node);
|
Literal::SubDenomination subdenomination(Json::Value const& _node);
|
||||||
|
|||||||
@ -542,6 +542,8 @@ void TryCatchClause::accept(ASTVisitor& _visitor)
|
|||||||
{
|
{
|
||||||
if (_visitor.visit(*this))
|
if (_visitor.visit(*this))
|
||||||
{
|
{
|
||||||
|
if (m_errorName)
|
||||||
|
m_errorName->accept(_visitor);
|
||||||
if (m_parameters)
|
if (m_parameters)
|
||||||
m_parameters->accept(_visitor);
|
m_parameters->accept(_visitor);
|
||||||
m_block->accept(_visitor);
|
m_block->accept(_visitor);
|
||||||
@ -553,6 +555,8 @@ void TryCatchClause::accept(ASTConstVisitor& _visitor) const
|
|||||||
{
|
{
|
||||||
if (_visitor.visit(*this))
|
if (_visitor.visit(*this))
|
||||||
{
|
{
|
||||||
|
if (m_errorName)
|
||||||
|
m_errorName->accept(_visitor);
|
||||||
if (m_parameters)
|
if (m_parameters)
|
||||||
m_parameters->accept(_visitor);
|
m_parameters->accept(_visitor);
|
||||||
m_block->accept(_visitor);
|
m_block->accept(_visitor);
|
||||||
|
|||||||
@ -975,14 +975,14 @@ void ContractCompiler::handleCatch(vector<ASTPointer<TryCatchClause>> const& _ca
|
|||||||
ASTPointer<TryCatchClause> panic{};
|
ASTPointer<TryCatchClause> panic{};
|
||||||
ASTPointer<TryCatchClause> fallback{};
|
ASTPointer<TryCatchClause> fallback{};
|
||||||
for (size_t i = 1; i < _catchClauses.size(); ++i)
|
for (size_t i = 1; i < _catchClauses.size(); ++i)
|
||||||
if (_catchClauses[i]->errorName() == "Error")
|
if (_catchClauses[i]->kind() == TryCatchClause::Kind::Error)
|
||||||
error = _catchClauses[i];
|
error = _catchClauses[i];
|
||||||
else if (_catchClauses[i]->errorName() == "Panic")
|
else if (_catchClauses[i]->kind() == TryCatchClause::Kind::Panic)
|
||||||
panic = _catchClauses[i];
|
panic = _catchClauses[i];
|
||||||
else if (_catchClauses[i]->errorName().empty())
|
else if (_catchClauses[i]->kind() == TryCatchClause::Kind::Fallback)
|
||||||
fallback = _catchClauses[i];
|
fallback = _catchClauses[i];
|
||||||
else
|
else
|
||||||
solAssert(false, "");
|
solUnimplementedAssert(false, "");
|
||||||
|
|
||||||
solAssert(_catchClauses.size() == 1ul + (error ? 1 : 0) + (panic ? 1 : 0) + (fallback ? 1 : 0), "");
|
solAssert(_catchClauses.size() == 1ul + (error ? 1 : 0) + (panic ? 1 : 0) + (fallback ? 1 : 0), "");
|
||||||
|
|
||||||
|
|||||||
@ -1323,7 +1323,7 @@ ASTPointer<TryStatement> Parser::parseTryStatement(ASTPointer<ASTString> const&
|
|||||||
ASTPointer<Block> successBlock = parseBlock();
|
ASTPointer<Block> successBlock = parseBlock();
|
||||||
successClauseFactory.setEndPositionFromNode(successBlock);
|
successClauseFactory.setEndPositionFromNode(successBlock);
|
||||||
clauses.emplace_back(successClauseFactory.createNode<TryCatchClause>(
|
clauses.emplace_back(successClauseFactory.createNode<TryCatchClause>(
|
||||||
make_shared<ASTString>(), returnsParameters, successBlock
|
TryCatchClause::Kind::Success, ASTPointer<IdentifierPath>{}, returnsParameters, successBlock
|
||||||
));
|
));
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -1342,20 +1342,42 @@ ASTPointer<TryCatchClause> Parser::parseCatchClause()
|
|||||||
RecursionGuard recursionGuard(*this);
|
RecursionGuard recursionGuard(*this);
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
expectToken(Token::Catch);
|
expectToken(Token::Catch);
|
||||||
ASTPointer<ASTString> errorName = make_shared<string>();
|
TryCatchClause::Kind kind;
|
||||||
|
ASTPointer<IdentifierPath> errorName;
|
||||||
ASTPointer<ParameterList> errorParameters;
|
ASTPointer<ParameterList> errorParameters;
|
||||||
if (m_scanner->currentToken() != Token::LBrace)
|
if (m_scanner->currentToken() != Token::LBrace)
|
||||||
{
|
{
|
||||||
if (m_scanner->currentToken() == Token::Identifier)
|
if (m_scanner->currentToken() == Token::Identifier)
|
||||||
errorName = expectIdentifierToken();
|
{
|
||||||
|
string name = m_scanner->currentLiteral();
|
||||||
|
if (name == "Error")
|
||||||
|
{
|
||||||
|
kind = TryCatchClause::Kind::Error;
|
||||||
|
m_scanner->next();
|
||||||
|
}
|
||||||
|
else if (name == "Panic")
|
||||||
|
{
|
||||||
|
kind = TryCatchClause::Kind::Panic;
|
||||||
|
m_scanner->next();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errorName = parseIdentifierPath();
|
||||||
|
kind = TryCatchClause::Kind::UserDefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
kind = TryCatchClause::Kind::Fallback;
|
||||||
VarDeclParserOptions options;
|
VarDeclParserOptions options;
|
||||||
options.allowEmptyName = true;
|
options.allowEmptyName = true;
|
||||||
options.allowLocationSpecifier = true;
|
options.allowLocationSpecifier = true;
|
||||||
errorParameters = parseParameterList(options, !errorName->empty());
|
errorParameters = parseParameterList(options);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
kind = TryCatchClause::Kind::Fallback;
|
||||||
ASTPointer<Block> block = parseBlock();
|
ASTPointer<Block> block = parseBlock();
|
||||||
nodeFactory.setEndPositionFromNode(block);
|
nodeFactory.setEndPositionFromNode(block);
|
||||||
return nodeFactory.createNode<TryCatchClause>(errorName, errorParameters, block);
|
return nodeFactory.createNode<TryCatchClause>(kind, errorName, errorParameters, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTPointer<WhileStatement> Parser::parseWhileStatement(ASTPointer<ASTString> const& _docString)
|
ASTPointer<WhileStatement> Parser::parseWhileStatement(ASTPointer<ASTString> const& _docString)
|
||||||
|
|||||||
@ -7,5 +7,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 3542: (93-119): Invalid catch clause name. Expected either `catch (...)`, `catch Error(...)`, or `catch Panic(...)`.
|
// DeclarationError 7920: (99-105): Identifier not found or not unique.
|
||||||
// TypeError 3542: (120-143): Invalid catch clause name. Expected either `catch (...)`, `catch Error(...)`, or `catch Panic(...)`.
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user