v0.4.2-alpha
[Fix][Impl] 为了消除类构造带来的语法歧义,同时保持实现简洁和括号省略的语法,自此版本,引入了 `new` 操作符
造成歧义的原方法:
if a == A{}
条件是 a == A,还是 a == A{} ?
因此,现在使用 new a_struct{}来构造类
[Opti] 相较于 Fig v0.4.1-alpha版本,release O3同编译条件下
Fib普通递归法性能提升 ~50%
具体方式:
增加了小整数优化,-128~127的整数现在会直接从IntPool获取而不是新构造
...忘了
[Fix] 类构造 shorthand模式忘写了,现在补上了
[Feat][Impl] 类型声明现在接受一个表达式,原为Identifier。实现 var start: time.Time = time.now() 的效果
这是符合语法和语言特性的支持,类型为一等公民。类似Python的 <class 'type'>
[Impl] 修改了部分错误输出的细节
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
#include "Ast/Statements/ErrorFlow.hpp"
|
||||
#include "Ast/Statements/ImplementSt.hpp"
|
||||
#include "Ast/astBase.hpp"
|
||||
#include "Ast/functionParameters.hpp"
|
||||
#include "Error/error.hpp"
|
||||
#include "Token/token.hpp"
|
||||
#include <Ast/Statements/ErrorFlow.hpp>
|
||||
#include <Ast/Statements/ImplementSt.hpp>
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Ast/functionParameters.hpp>
|
||||
#include <Error/error.hpp>
|
||||
#include <Token/token.hpp>
|
||||
#include <Parser/parser.hpp>
|
||||
|
||||
namespace Fig
|
||||
@@ -54,17 +54,17 @@ namespace Fig
|
||||
|
||||
// // 点运算符
|
||||
// {Ast::Operator::Dot, {40, 41}},
|
||||
{Ast::Operator::TernaryCond, {3, 2}},
|
||||
};
|
||||
|
||||
const std::unordered_map<Ast::Operator, Parser::Precedence> Parser::unaryOpPrecedence = {
|
||||
{Ast::Operator::Subtract, 150}, // -
|
||||
{Ast::Operator::BitAnd, 150}, // &
|
||||
{Ast::Operator::BitNot, 150}, // ~
|
||||
{Ast::Operator::Not, 150}, // !
|
||||
{Ast::Operator::BitAnd, 150}, // &
|
||||
{Ast::Operator::BitNot, 150}, // ~
|
||||
{Ast::Operator::Not, 150}, // !
|
||||
};
|
||||
|
||||
Ast::VarDef
|
||||
Parser::__parseVarDef(bool isPublic)
|
||||
Ast::VarDef Parser::__parseVarDef(bool isPublic)
|
||||
{
|
||||
// entry: current is keyword `var` or `const`
|
||||
bool isConst = (currentToken().getType() == TokenType::Const ? true : false);
|
||||
@@ -72,31 +72,31 @@ namespace Fig
|
||||
expect(TokenType::Identifier);
|
||||
FString name = currentToken().getValue();
|
||||
next();
|
||||
FString tiName = ValueType::Any.name;
|
||||
Ast::Expression declaredType = nullptr;
|
||||
bool hasSpecificType = false;
|
||||
if (isThis(TokenType::Colon)) // :
|
||||
{
|
||||
expectPeek(TokenType::Identifier, FString(u8"Type name"));
|
||||
next();
|
||||
tiName = currentToken().getValue();
|
||||
next();
|
||||
next(); // consume `:`
|
||||
declaredType = parseExpression(0, TokenType::Assign, TokenType::Semicolon);
|
||||
hasSpecificType = true;
|
||||
}
|
||||
if (isThis(TokenType::Semicolon))
|
||||
{
|
||||
next(); // consume `;`, no using expectConsume here cause we don't need to check again
|
||||
return makeAst<Ast::VarDefAst>(isPublic, isConst, name, tiName, nullptr);
|
||||
return makeAst<Ast::VarDefAst>(isPublic, isConst, name, declaredType, nullptr, false);
|
||||
}
|
||||
if (!isThis(TokenType::Assign) and !isThis(TokenType::Walrus)) expect(TokenType::Assign, u8"assign or walrus");
|
||||
bool followupType = false;
|
||||
|
||||
if (isThis(TokenType::Walrus))
|
||||
{
|
||||
if (hasSpecificType) throwAddressableError<SyntaxError>(FString(u8""));
|
||||
tiName = Parser::varDefTypeFollowed;
|
||||
followupType = true;
|
||||
}
|
||||
next();
|
||||
Ast::Expression exp = parseExpression(0);
|
||||
expectSemicolon();
|
||||
return makeAst<Ast::VarDefAst>(isPublic, isConst, name, tiName, exp);
|
||||
return makeAst<Ast::VarDefAst>(isPublic, isConst, name, declaredType, exp, followupType);
|
||||
}
|
||||
|
||||
ObjectPtr Parser::__parseValue()
|
||||
@@ -133,18 +133,12 @@ namespace Fig
|
||||
return std::make_shared<Object>(i);
|
||||
}
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LiteralString)
|
||||
{
|
||||
return std::make_shared<Object>(_val);
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LiteralString) { return std::make_shared<Object>(_val); }
|
||||
else if (currentToken().getType() == TokenType::LiteralBool)
|
||||
{
|
||||
return std::make_shared<Object>((_val == u8"true" ? true : false));
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LiteralNull)
|
||||
{
|
||||
return Object::getNullInstance();
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LiteralNull) { return Object::getNullInstance(); }
|
||||
else
|
||||
{
|
||||
throw std::runtime_error(std::string("Internal Error at: ") + std::string(__func__));
|
||||
@@ -237,17 +231,17 @@ namespace Fig
|
||||
next();
|
||||
expect(TokenType::LeftParen);
|
||||
Ast::FunctionParameters params = __parseFunctionParameters();
|
||||
FString retTiName = ValueType::Any.name;
|
||||
|
||||
Ast::Expression returnType;
|
||||
|
||||
if (isThis(TokenType::RightArrow)) // ->
|
||||
{
|
||||
next(); // skip `->`
|
||||
expect(TokenType::Identifier);
|
||||
retTiName = currentToken().getValue();
|
||||
next(); // skip return type
|
||||
returnType = parseExpression(0, TokenType::LeftBrace, TokenType::Semicolon);
|
||||
}
|
||||
expect(TokenType::LeftBrace);
|
||||
Ast::BlockStatement body = __parseBlockStatement();
|
||||
return makeAst<Ast::FunctionDefSt>(funcName, params, isPublic, retTiName, body);
|
||||
return makeAst<Ast::FunctionDefSt>(funcName, params, isPublic, returnType, body);
|
||||
}
|
||||
Ast::StructDef Parser::__parseStructDef(bool isPublic)
|
||||
{
|
||||
@@ -289,13 +283,11 @@ namespace Fig
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(std::format("expect field name or field attribute")));
|
||||
}
|
||||
FString tiName = ValueType::Any.name;
|
||||
Ast::Expression fieldType = nullptr;
|
||||
if (isThis(TokenType::Colon))
|
||||
{
|
||||
next();
|
||||
expect(TokenType::Identifier, u8"type name");
|
||||
tiName = currentToken().getValue();
|
||||
next();
|
||||
next(); // consume `:`
|
||||
fieldType = parseExpression(0, TokenType::Assign, TokenType::Semicolon);
|
||||
}
|
||||
Ast::Expression initExpr = nullptr;
|
||||
if (isThis(TokenType::Assign))
|
||||
@@ -305,7 +297,7 @@ namespace Fig
|
||||
initExpr = parseExpression(0);
|
||||
}
|
||||
expectSemicolon();
|
||||
return Ast::StructDefField(am, fieldName, tiName, initExpr);
|
||||
return Ast::StructDefField(am, fieldName, fieldType, initExpr);
|
||||
};
|
||||
std::vector<Ast::Statement> stmts;
|
||||
std::vector<Ast::StructDefField> fields;
|
||||
@@ -318,10 +310,7 @@ namespace Fig
|
||||
next(); // consume `}`
|
||||
break;
|
||||
}
|
||||
if (isThis(TokenType::Identifier))
|
||||
{
|
||||
fields.push_back(__parseStructField(false));
|
||||
}
|
||||
if (isThis(TokenType::Identifier)) { fields.push_back(__parseStructField(false)); }
|
||||
else if (isThis(TokenType::Public))
|
||||
{
|
||||
if (isNext(TokenType::Const))
|
||||
@@ -361,23 +350,18 @@ namespace Fig
|
||||
next(); // consume `struct`
|
||||
stmts.push_back(__parseStructDef(false));
|
||||
}
|
||||
else if (isThis(TokenType::Const))
|
||||
{
|
||||
fields.push_back(__parseStructField(false));
|
||||
}
|
||||
else if (isThis(TokenType::Const)) { fields.push_back(__parseStructField(false)); }
|
||||
else if (isThis(TokenType::Variable))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString("Variables are not allowed to be defined within a structure."));
|
||||
throwAddressableError<SyntaxError>(
|
||||
FString("Variables are not allowed to be defined within a structure."));
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString("Invalid syntax"));
|
||||
}
|
||||
}
|
||||
if (!braceClosed)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString("braces are not closed"));
|
||||
}
|
||||
if (!braceClosed) { throwAddressableError<SyntaxError>(FString("braces are not closed")); }
|
||||
return makeAst<Ast::StructDefSt>(isPublic, structName, fields, makeAst<Ast::BlockStatementAst>(stmts));
|
||||
}
|
||||
|
||||
@@ -409,27 +393,18 @@ namespace Fig
|
||||
expect(TokenType::RightArrow); // ->
|
||||
next(); // consume `->`
|
||||
|
||||
expect(TokenType::Identifier, u8"return type");
|
||||
FString returnType = currentToken().getValue();
|
||||
next(); // consume return type
|
||||
Ast::Expression returnType = parseExpression(0, TokenType::LeftBrace, TokenType::Semicolon);
|
||||
|
||||
if (isThis(TokenType::LeftBrace))
|
||||
{
|
||||
Ast::BlockStatement block = __parseBlockStatement();
|
||||
|
||||
methods.push_back(Ast::InterfaceMethod(
|
||||
funcName,
|
||||
paras,
|
||||
returnType,
|
||||
block));
|
||||
methods.push_back(Ast::InterfaceMethod(funcName, paras, returnType, block));
|
||||
continue;
|
||||
}
|
||||
expectSemicolon();
|
||||
|
||||
methods.push_back(Ast::InterfaceMethod(
|
||||
funcName,
|
||||
paras,
|
||||
returnType));
|
||||
methods.push_back(Ast::InterfaceMethod(funcName, paras, returnType));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -454,7 +429,7 @@ namespace Fig
|
||||
FString structName = currentToken().getValue();
|
||||
next(); // consume name
|
||||
expect(TokenType::LeftBrace); // {
|
||||
next(); // consume `{`
|
||||
next(); // consume `{`
|
||||
|
||||
std::vector<Ast::ImplementMethod> methods;
|
||||
|
||||
@@ -473,10 +448,7 @@ namespace Fig
|
||||
Ast::FunctionParameters paras = __parseFunctionParameters();
|
||||
expect(TokenType::LeftBrace);
|
||||
Ast::BlockStatement body = __parseBlockStatement();
|
||||
methods.push_back(Ast::ImplementMethod(
|
||||
funcName,
|
||||
paras,
|
||||
body));
|
||||
methods.push_back(Ast::ImplementMethod(funcName, paras, body));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -501,18 +473,18 @@ namespace Fig
|
||||
{
|
||||
// entry: current is `try`
|
||||
next(); // consume `try`
|
||||
|
||||
|
||||
/*
|
||||
try
|
||||
{
|
||||
...
|
||||
...
|
||||
}
|
||||
catch(e: IOError)
|
||||
{
|
||||
}
|
||||
catch(e: TimeOutError)
|
||||
{
|
||||
}
|
||||
}
|
||||
*/
|
||||
expect(TokenType::LeftBrace);
|
||||
Ast::BlockStatement body = __parseBlockStatement();
|
||||
@@ -540,15 +512,13 @@ namespace Fig
|
||||
hasType = true;
|
||||
}
|
||||
expect(TokenType::RightParen); // )
|
||||
next(); // consume `)`
|
||||
expect(TokenType::LeftBrace); // {
|
||||
next(); // consume `)`
|
||||
expect(TokenType::LeftBrace); // {
|
||||
Ast::BlockStatement catchBody = __parseBlockStatement();
|
||||
|
||||
if (hasType)
|
||||
if (hasType) { catches.push_back(Ast::Catch(errVarName, errVarType, catchBody)); }
|
||||
else
|
||||
{
|
||||
catches.push_back(Ast::Catch(errVarName, errVarType, catchBody));
|
||||
}
|
||||
else {
|
||||
catches.push_back(Ast::Catch(errVarName, catchBody));
|
||||
}
|
||||
}
|
||||
@@ -563,7 +533,7 @@ namespace Fig
|
||||
expect(TokenType::LeftBrace);
|
||||
finallyBlock = __parseBlockStatement();
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -575,17 +545,11 @@ namespace Fig
|
||||
{
|
||||
Ast::Statement stmt;
|
||||
if (isThis(TokenType::EndOfFile)) { return makeAst<Ast::EofStmt>(); }
|
||||
else if (isThis(TokenType::Import))
|
||||
{
|
||||
stmt = __parseImport();
|
||||
}
|
||||
else if (isThis(TokenType::Import)) { stmt = __parseImport(); }
|
||||
else if (isThis(TokenType::Public))
|
||||
{
|
||||
next(); // consume `public`
|
||||
if (isThis(TokenType::Variable) || isThis(TokenType::Const))
|
||||
{
|
||||
stmt = __parseVarDef(true);
|
||||
}
|
||||
if (isThis(TokenType::Variable) || isThis(TokenType::Const)) { stmt = __parseVarDef(true); }
|
||||
else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
|
||||
{
|
||||
next();
|
||||
@@ -596,19 +560,14 @@ namespace Fig
|
||||
next();
|
||||
stmt = __parseStructDef(true);
|
||||
}
|
||||
else if (isThis(TokenType::Interface))
|
||||
{
|
||||
stmt = __parseInterfaceDef(true);
|
||||
}
|
||||
else if (isThis(TokenType::Interface)) { stmt = __parseInterfaceDef(true); }
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(u8"Expected `var`, `const`, `function`, `struct` or `interface` after `public`"));
|
||||
throwAddressableError<SyntaxError>(
|
||||
FString(u8"Expected `var`, `const`, `function`, `struct` or `interface` after `public`"));
|
||||
}
|
||||
}
|
||||
else if (isThis(TokenType::Variable) || isThis(TokenType::Const))
|
||||
{
|
||||
stmt = __parseVarDef(false);
|
||||
}
|
||||
else if (isThis(TokenType::Variable) || isThis(TokenType::Const)) { stmt = __parseVarDef(false); }
|
||||
else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
|
||||
{
|
||||
next();
|
||||
@@ -626,50 +585,20 @@ namespace Fig
|
||||
next();
|
||||
stmt = __parseInterfaceDef(false);
|
||||
}
|
||||
else if (isThis(TokenType::Implement))
|
||||
{
|
||||
stmt = __parseImplement();
|
||||
}
|
||||
else if (isThis(TokenType::If))
|
||||
{
|
||||
stmt = __parseIf();
|
||||
}
|
||||
else if (isThis(TokenType::Implement)) { stmt = __parseImplement(); }
|
||||
else if (isThis(TokenType::If)) { stmt = __parseIf(); }
|
||||
else if (isThis(TokenType::Else))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(u8"`else` without matching `if`"));
|
||||
}
|
||||
else if (isThis(TokenType::LeftBrace))
|
||||
{
|
||||
stmt = __parseBlockStatement();
|
||||
}
|
||||
else if (isThis(TokenType::While))
|
||||
{
|
||||
stmt = __parseWhile();
|
||||
}
|
||||
else if (isThis(TokenType::For))
|
||||
{
|
||||
stmt = __parseFor();
|
||||
}
|
||||
else if (isThis(TokenType::Return))
|
||||
{
|
||||
stmt = __parseReturn();
|
||||
}
|
||||
else if (isThis(TokenType::Break))
|
||||
{
|
||||
stmt = __parseBreak();
|
||||
}
|
||||
else if (isThis(TokenType::Continue))
|
||||
{
|
||||
stmt = __parseContinue();
|
||||
}
|
||||
else if (isThis(TokenType::Throw))
|
||||
{
|
||||
stmt = __parseThrow();
|
||||
}
|
||||
else if (isThis(TokenType::Try))
|
||||
{
|
||||
stmt = __parseTry();
|
||||
}
|
||||
else if (isThis(TokenType::LeftBrace)) { stmt = __parseBlockStatement(); }
|
||||
else if (isThis(TokenType::While)) { stmt = __parseWhile(); }
|
||||
else if (isThis(TokenType::For)) { stmt = __parseFor(); }
|
||||
else if (isThis(TokenType::Return)) { stmt = __parseReturn(); }
|
||||
else if (isThis(TokenType::Break)) { stmt = __parseBreak(); }
|
||||
else if (isThis(TokenType::Continue)) { stmt = __parseContinue(); }
|
||||
else if (isThis(TokenType::Throw)) { stmt = __parseThrow(); }
|
||||
else if (isThis(TokenType::Try)) { stmt = __parseTry(); }
|
||||
else if (allowExp)
|
||||
{
|
||||
// expression statement
|
||||
@@ -677,7 +606,7 @@ namespace Fig
|
||||
expectSemicolon();
|
||||
stmt = makeAst<Ast::ExpressionStmtAst>(exp);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(u8"invalid syntax", currentAAI.line, currentAAI.column);
|
||||
}
|
||||
@@ -766,7 +695,7 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
condition = parseExpression(0);
|
||||
condition = parseExpression(0, TokenType::LeftBrace);
|
||||
}
|
||||
expect(TokenType::LeftBrace); // {
|
||||
Ast::BlockStatement body = __parseBlockStatement();
|
||||
@@ -784,7 +713,8 @@ namespace Fig
|
||||
throwAddressableError<SyntaxError>(u8"BlockStatement cannot be used as for loop increment");
|
||||
}
|
||||
|
||||
if (isThis(TokenType::If) || isThis(TokenType::While) || isThis(TokenType::For) || isThis(TokenType::Return) || isThis(TokenType::Break) || isThis(TokenType::Continue))
|
||||
if (isThis(TokenType::If) || isThis(TokenType::While) || isThis(TokenType::For) || isThis(TokenType::Return)
|
||||
|| isThis(TokenType::Break) || isThis(TokenType::Continue))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(u8"Control flow statements cannot be used as for loop increment");
|
||||
}
|
||||
@@ -799,8 +729,7 @@ namespace Fig
|
||||
// TODO: support enumeration
|
||||
next(); // consume `for`
|
||||
bool paren = isThis(TokenType::LeftParen);
|
||||
if (paren)
|
||||
next(); // consume `(`
|
||||
if (paren) next(); // consume `(`
|
||||
// support 3-part for loop
|
||||
// for init; condition; increment {}
|
||||
Ast::Statement initStmt = __parseStatement(false); // auto check ``
|
||||
@@ -813,8 +742,7 @@ namespace Fig
|
||||
// auto guard = disableSemicolon();
|
||||
incrementStmt = __parseIncrementStatement();
|
||||
} // after parse increment, semicolon check state restored
|
||||
if (paren)
|
||||
expectConsume(TokenType::RightParen); // consume `)` if has `(`
|
||||
if (paren) expectConsume(TokenType::RightParen); // consume `)` if has `(`
|
||||
expect(TokenType::LeftBrace); // {
|
||||
Ast::BlockStatement body = __parseBlockStatement(); // auto consume `}`
|
||||
return makeAst<Ast::ForSt>(initStmt, condition, incrementStmt, body);
|
||||
@@ -938,10 +866,7 @@ namespace Fig
|
||||
{
|
||||
if (mode == 0)
|
||||
{
|
||||
if (isThis(TokenType::Identifier) && isNext(TokenType::Colon))
|
||||
{
|
||||
mode = 2;
|
||||
}
|
||||
if (isThis(TokenType::Identifier) && isNext(TokenType::Colon)) { mode = 2; }
|
||||
else if (isThis(TokenType::Identifier) && (isNext(TokenType::Comma) || isNext(TokenType::RightBrace)))
|
||||
{
|
||||
mode = 3;
|
||||
@@ -985,17 +910,19 @@ namespace Fig
|
||||
}
|
||||
else if (!isThis(TokenType::RightBrace))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(
|
||||
std::format("Expect `,` or `}}` in struct initialization expression, got {}",
|
||||
currentToken().toString().toBasicString())));
|
||||
throwAddressableError<SyntaxError>(
|
||||
FString(std::format("Expect `,` or `}}` in struct initialization expression, got {}",
|
||||
currentToken().toString().toBasicString())));
|
||||
}
|
||||
}
|
||||
expect(TokenType::RightBrace);
|
||||
next(); // consume `}`
|
||||
return makeAst<Ast::InitExprAst>(structe, args,
|
||||
(mode == 1 ? Ast::InitExprAst::InitMode::Positional :
|
||||
(mode == 2 ? Ast::InitExprAst::InitMode::Named : Ast::InitExprAst::InitMode::Shorthand)));
|
||||
return makeAst<Ast::InitExprAst>(
|
||||
structe,
|
||||
args,
|
||||
static_cast<Ast::InitExprAst::InitMode>(mode));
|
||||
}
|
||||
|
||||
Ast::Expression Parser::__parseTupleOrParenExpr()
|
||||
{
|
||||
next();
|
||||
@@ -1017,8 +944,7 @@ namespace Fig
|
||||
{
|
||||
next(); // consume ','
|
||||
|
||||
if (currentToken().getType() == TokenType::RightParen)
|
||||
break;
|
||||
if (currentToken().getType() == TokenType::RightParen) break;
|
||||
|
||||
elements.push_back(parseExpression(0));
|
||||
}
|
||||
@@ -1069,10 +995,7 @@ namespace Fig
|
||||
expect(TokenType::Identifier, u8"package name");
|
||||
path.push_back(currentToken().getValue());
|
||||
next(); // consume package name
|
||||
if (isThis(TokenType::Semicolon))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (isThis(TokenType::Semicolon)) { break; }
|
||||
else if (isThis(TokenType::Dot))
|
||||
{
|
||||
next(); // consume `.`
|
||||
@@ -1092,8 +1015,7 @@ namespace Fig
|
||||
Ast::Operator op;
|
||||
|
||||
Token tok = currentToken();
|
||||
if (tok == EOFTok)
|
||||
throwAddressableError<SyntaxError>(FString(u8"Unexpected end of expression"));
|
||||
if (tok == EOFTok) throwAddressableError<SyntaxError>(FString(u8"Unexpected end of expression"));
|
||||
if (tok.getType() == stop || tok.getType() == stop2)
|
||||
{
|
||||
if (lhs == nullptr) throwAddressableError<SyntaxError>(FString(u8"Expected expression"));
|
||||
@@ -1139,6 +1061,14 @@ namespace Fig
|
||||
next();
|
||||
lhs = makeAst<Ast::UnaryExprAst>(op, parseExpression(bp, stop, stop2));
|
||||
}
|
||||
else if (tok.getType() == TokenType::New)
|
||||
{
|
||||
// `new` now is an independent syntax
|
||||
next();
|
||||
Ast::Expression operand = parseExpression(bp, TokenType::LeftBrace);
|
||||
expect(TokenType::LeftBrace);
|
||||
lhs = __parseInitExpr(operand);
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(u8"Unexpected token in expression:") + tok.toString());
|
||||
@@ -1148,21 +1078,31 @@ namespace Fig
|
||||
while (true)
|
||||
{
|
||||
tok = currentToken();
|
||||
if (tok.getType() == stop || tok.getType() == stop2|| tok == EOFTok) break;
|
||||
if (tok.getType() == stop || tok.getType() == stop2 || tok == EOFTok) break;
|
||||
|
||||
/* Postfix */
|
||||
|
||||
if (tok.getType() == TokenType::LeftBrace)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(
|
||||
FString(u8"Since Fig v0.4.2, please use new struct{} to avoid syntax ambiguity"));
|
||||
}
|
||||
|
||||
if (tok.getType() == TokenType::LeftParen)
|
||||
{
|
||||
lhs = __parseCall(lhs);
|
||||
continue;
|
||||
}
|
||||
// else if (tok.getType() == TokenType::LeftBrace) { lhs = __parseInitExpr(lhs); }
|
||||
/*
|
||||
since Fig v0.4.2, use new struct{};
|
||||
|
||||
if (tok.getType() == TokenType::LeftBrace)
|
||||
{
|
||||
lhs = __parseInitExpr(lhs);
|
||||
continue;
|
||||
}
|
||||
if a == A{}
|
||||
is A{} struct init?
|
||||
or A a variable, {} is the body?
|
||||
|
||||
fuck.
|
||||
*/
|
||||
|
||||
// member access: a.b
|
||||
if (tok.getType() == TokenType::Dot)
|
||||
@@ -1189,15 +1129,17 @@ namespace Fig
|
||||
lhs = makeAst<Ast::IndexExprAst>(lhs, indexExpr);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ternary
|
||||
if (tok.getType() == TokenType::Question)
|
||||
{
|
||||
auto [lbp, rbp] = getBindingPower(Ast::Operator::TernaryCond);
|
||||
if (bp >= lbp) break;
|
||||
|
||||
next(); // consume ?
|
||||
Ast::Expression trueExpr = parseExpression(0, TokenType::Colon, stop2);
|
||||
expect(TokenType::Colon);
|
||||
next(); // consume :
|
||||
Ast::Expression falseExpr = parseExpression(0, TokenType::Semicolon, stop2);
|
||||
Ast::Expression trueExpr = parseExpression(0, TokenType::Colon);
|
||||
expectConsume(TokenType::Colon);
|
||||
|
||||
Ast::Expression falseExpr = parseExpression(0);
|
||||
lhs = makeAst<Ast::TernaryExprAst>(lhs, trueExpr, falseExpr);
|
||||
continue;
|
||||
}
|
||||
@@ -1219,10 +1161,7 @@ namespace Fig
|
||||
{
|
||||
output.clear();
|
||||
Token tok = currentToken();
|
||||
if (tok == EOFTok)
|
||||
{
|
||||
return output;
|
||||
}
|
||||
if (tok == EOFTok) { return output; }
|
||||
|
||||
while (!isEOF())
|
||||
{
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Ast/astBase.hpp"
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Ast/ast.hpp>
|
||||
#include <Lexer/lexer.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Error/error.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <print>
|
||||
#include <source_location>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -248,7 +247,7 @@ namespace Fig
|
||||
|
||||
[[nodiscard]] SemicolonDisabler disableSemicolon() { return SemicolonDisabler(this); }
|
||||
|
||||
void expectSemicolon()
|
||||
void expectSemicolon(std::source_location loc = std::source_location::current())
|
||||
{
|
||||
// if need semicolon and stream has `;`, consume it. if not need semicolon, do nothing
|
||||
|
||||
@@ -263,18 +262,18 @@ namespace Fig
|
||||
}
|
||||
|
||||
// normal semicolon check
|
||||
expectConsume(TokenType::Semicolon);
|
||||
expectConsume(TokenType::Semicolon, loc);
|
||||
}
|
||||
|
||||
void expectConsume(TokenType type, FString expected)
|
||||
void expectConsume(TokenType type, FString expected, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
expect(type, expected);
|
||||
expect(type, expected, loc);
|
||||
next();
|
||||
}
|
||||
|
||||
void expectConsume(TokenType type)
|
||||
void expectConsume(TokenType type, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
expect(type);
|
||||
expect(type, loc);
|
||||
next();
|
||||
}
|
||||
|
||||
@@ -314,6 +313,8 @@ namespace Fig
|
||||
Ast::MapExpr __parseMapExpr(); // entry: current is `{`
|
||||
|
||||
Ast::InitExpr __parseInitExpr(Ast::Expression); // entry: current is `{`, ahead is struct type exp.
|
||||
|
||||
|
||||
Ast::Expression __parseTupleOrParenExpr(); // entry: current is `(`
|
||||
|
||||
Ast::FunctionLiteralExpr __parseFunctionLiteralExpr(); // entry: current is Token::LParen after Token::Function
|
||||
|
||||
Reference in New Issue
Block a user