[VER] 0.3.4-alpha
[FEAT] 异常系统, try/catch/finally
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
#include "Ast/Statements/ErrorFlow.hpp"
|
||||
#include "Ast/Statements/ImplementSt.hpp"
|
||||
#include "Ast/astBase.hpp"
|
||||
#include "Ast/functionParameters.hpp"
|
||||
@@ -30,6 +31,7 @@ namespace Fig
|
||||
{Ast::Operator::LessEqual, {8, 9}},
|
||||
{Ast::Operator::Greater, {8, 9}},
|
||||
{Ast::Operator::GreaterEqual, {8, 9}},
|
||||
{Ast::Operator::Is, {8, 9}},
|
||||
|
||||
// 位运算
|
||||
{Ast::Operator::BitAnd, {6, 7}},
|
||||
@@ -478,6 +480,89 @@ namespace Fig
|
||||
return makeAst<Ast::ImplementAst>(interfaceName, structName, methods);
|
||||
}
|
||||
|
||||
Ast::Throw Parser::__parseThrow()
|
||||
{
|
||||
// entry: current is `throw`
|
||||
next(); // consume `throw`
|
||||
Ast::Expression exp = parseExpression(0);
|
||||
expect(TokenType::Semicolon);
|
||||
next(); // consume `;`
|
||||
return makeAst<Ast::ThrowSt>(exp);
|
||||
}
|
||||
|
||||
Ast::Try Parser::__parseTry()
|
||||
{
|
||||
// entry: current is `try`
|
||||
next(); // consume `try`
|
||||
|
||||
/*
|
||||
try
|
||||
{
|
||||
...
|
||||
}
|
||||
catch(e: IOError)
|
||||
{
|
||||
}
|
||||
catch(e: TimeOutError)
|
||||
{
|
||||
}
|
||||
*/
|
||||
expect(TokenType::LeftBrace);
|
||||
Ast::BlockStatement body = __parseBlockStatement();
|
||||
std::vector<Ast::Catch> catches;
|
||||
Ast::BlockStatement finallyBlock = nullptr;
|
||||
while (true)
|
||||
{
|
||||
if (isThis(TokenType::Catch))
|
||||
{
|
||||
next(); // consume `catch`
|
||||
expect(TokenType::LeftParen);
|
||||
next(); // consume `(`
|
||||
expect(TokenType::Identifier, u8"error receive var name");
|
||||
FString errVarName = currentToken().getValue();
|
||||
next(); // consume name
|
||||
|
||||
bool hasType = false;
|
||||
FString errVarType;
|
||||
if (isThis(TokenType::Colon)) // :
|
||||
{
|
||||
next();
|
||||
expect(TokenType::Identifier, u8"error type");
|
||||
errVarType = currentToken().getValue();
|
||||
next(); // consume var type
|
||||
hasType = true;
|
||||
}
|
||||
expect(TokenType::RightParen); // )
|
||||
next(); // consume `)`
|
||||
expect(TokenType::LeftBrace); // {
|
||||
Ast::BlockStatement catchBody = __parseBlockStatement();
|
||||
|
||||
if (hasType)
|
||||
{
|
||||
catches.push_back(Ast::Catch(errVarName, errVarType, catchBody));
|
||||
}
|
||||
else {
|
||||
catches.push_back(Ast::Catch(errVarName, catchBody));
|
||||
}
|
||||
}
|
||||
else if (isThis(TokenType::Finally))
|
||||
{
|
||||
if (finallyBlock != nullptr)
|
||||
{
|
||||
throw SyntaxError(u8"Duplicate try finally-block", currentAAI.line, currentAAI.column);
|
||||
}
|
||||
next(); // consume `finally`
|
||||
expect(TokenType::LeftBrace);
|
||||
finallyBlock = __parseBlockStatement();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return makeAst<Ast::TrySt>(body, catches, finallyBlock);
|
||||
}
|
||||
|
||||
Ast::Statement Parser::__parseStatement()
|
||||
{
|
||||
Ast::Statement stmt;
|
||||
@@ -568,6 +653,14 @@ namespace Fig
|
||||
{
|
||||
stmt = __parseContinue();
|
||||
}
|
||||
else if (isThis(TokenType::Throw))
|
||||
{
|
||||
stmt = __parseThrow();
|
||||
}
|
||||
else if (isThis(TokenType::Try))
|
||||
{
|
||||
stmt = __parseTry();
|
||||
}
|
||||
else
|
||||
{
|
||||
// expression statement
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <Error/error.hpp>
|
||||
|
||||
#include <print>
|
||||
#include <source_location>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <stack>
|
||||
@@ -211,43 +212,43 @@ namespace Fig
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void expectPeek(TokenType type)
|
||||
void expectPeek(TokenType type, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
if (peekToken().getType() != type)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`",
|
||||
magic_enum::enum_name(type),
|
||||
magic_enum::enum_name(peekToken().getType()))));
|
||||
magic_enum::enum_name(peekToken().getType()))), loc);
|
||||
}
|
||||
}
|
||||
|
||||
void expect(TokenType type)
|
||||
void expect(TokenType type, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
if (currentToken().getType() != type)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`",
|
||||
magic_enum::enum_name(type),
|
||||
magic_enum::enum_name(currentToken().getType()))));
|
||||
magic_enum::enum_name(currentToken().getType()))), loc);
|
||||
}
|
||||
}
|
||||
|
||||
void expectPeek(TokenType type, FString expected)
|
||||
void expectPeek(TokenType type, FString expected, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
if (peekToken().getType() != type)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`",
|
||||
expected.toBasicString(),
|
||||
magic_enum::enum_name(peekToken().getType()))));
|
||||
magic_enum::enum_name(peekToken().getType()))), loc);
|
||||
}
|
||||
}
|
||||
|
||||
void expect(TokenType type, FString expected)
|
||||
void expect(TokenType type, FString expected, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
if (currentToken().getType() != type)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`",
|
||||
expected.toBasicString(),
|
||||
magic_enum::enum_name(currentToken().getType()))));
|
||||
magic_enum::enum_name(currentToken().getType()))), loc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,6 +317,9 @@ namespace Fig
|
||||
Ast::InterfaceDef __parseInterfaceDef(bool); // entry: current is Token::Identifier (interface name) arg(isPublic: bool)
|
||||
Ast::Implement __parseImplement(); // entry: current is `impl`
|
||||
|
||||
Ast::Throw __parseThrow(); // entry: current is `throw`
|
||||
Ast::Try __parseTry(); // entry: current is `try`
|
||||
|
||||
Ast::BinaryExpr __parseInfix(Ast::Expression, Ast::Operator, Precedence);
|
||||
Ast::UnaryExpr __parsePrefix(Ast::Operator, Precedence);
|
||||
Ast::Expression __parseCall(Ast::Expression);
|
||||
|
||||
Reference in New Issue
Block a user