Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion lib/include/pl/core/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ namespace pl::core {
std::string m_aliasNamespaceString;
std::string m_autoNamespace;

enum class AllowKeywords : u8 {
None = 0,
Parent,
This,
Both
};

Location location() override;
// error helpers
void errorHere(const std::string &message);
Expand Down Expand Up @@ -173,6 +180,7 @@ namespace pl::core {
hlp::safe_unique_ptr<ast::ASTNode> parseFunctionStatement(bool needsSemicolon = true);
hlp::safe_unique_ptr<ast::ASTNode> parseFunctionVariableAssignment(const std::string &lvalue);
hlp::safe_unique_ptr<ast::ASTNode> parseFunctionVariableCompoundAssignment(const std::string &lvalue);
hlp::safe_unique_ptr<ast::ASTNode> parseFunctionVariableCompoundAssignment(TokenIter curr);
hlp::safe_unique_ptr<ast::ASTNode> parseFunctionControlFlowStatement();
std::vector<hlp::safe_unique_ptr<ast::ASTNode>> parseStatementBody(const std::function<hlp::safe_unique_ptr<ast::ASTNode>()> &memberParser);
hlp::safe_unique_ptr<ast::ASTNode> parseFunctionWhileLoop();
Expand Down Expand Up @@ -210,7 +218,9 @@ namespace pl::core {
std::vector<hlp::safe_shared_ptr<ast::ASTNode>> parseNamespace();
std::vector<hlp::safe_shared_ptr<ast::ASTNode>> parseStatements();

std::optional<i32> parseCompoundAssignment(const Token &token);
std::optional<i32> isCompoundAssignmentOperator(const Token &token);
std::optional<TokenIter> isCompoundAssignmentOperator(AllowKeywords allowKeywords = AllowKeywords::None);
std::optional<i32> isCompoundAssignmentOperator(i32 offset);

std::optional<Token::DocComment> parseDocComment(bool global);

Expand Down
94 changes: 80 additions & 14 deletions lib/source/pl/core/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -934,9 +934,11 @@ namespace pl::core {
statement = parseFunctionVariableAssignment(getValue<Token::Identifier>(-2).get());
else if (sequence(tkn::Operator::Dollar, tkn::Operator::Assign))
statement = parseFunctionVariableAssignment("$");
else if (const auto identifierOffset = parseCompoundAssignment(tkn::Literal::Identifier); identifierOffset.has_value())
else if (const auto identifierOffset = isCompoundAssignmentOperator(tkn::Literal::Identifier); identifierOffset.has_value())
statement = parseFunctionVariableCompoundAssignment(getValue<Token::Identifier>(*identifierOffset).get());
else if (parseCompoundAssignment(tkn::Operator::Dollar).has_value())
else if (const auto curr = isCompoundAssignmentOperator(AllowKeywords::Parent); curr.has_value())
statement = parseFunctionVariableCompoundAssignment(curr.value());
else if (isCompoundAssignmentOperator(tkn::Operator::Dollar).has_value())
statement = parseFunctionVariableCompoundAssignment("$");
else if (oneOf(tkn::Keyword::Return, tkn::Keyword::Break, tkn::Keyword::Continue))
statement = parseFunctionControlFlowStatement();
Expand All @@ -955,7 +957,7 @@ namespace pl::core {
} else if (sequence(tkn::Keyword::For, tkn::Separator::LeftParenthesis)) {
statement = parseFunctionForLoop();
needsSemicolon = false;
} else if (MATCHES(sequence(tkn::Literal::Identifier) && (peek(tkn::Separator::Dot) || (peek(tkn::Separator::LeftBracket, 0) && !peek(tkn::Separator::LeftBracket, 1))))) {
} else if (MATCHES((sequence(tkn::Literal::Identifier) || sequence(tkn::Keyword::Parent)) && (peek(tkn::Separator::Dot) || (peek(tkn::Separator::LeftBracket, 0) && !peek(tkn::Separator::LeftBracket, 1))))) {
statement = parseRValueAssignment();
} else if (sequence(tkn::Literal::Identifier)) {
const auto originalPos = this->m_curr;
Expand Down Expand Up @@ -1001,6 +1003,30 @@ namespace pl::core {
return create<ast::ASTNodeLValueAssignment>(lvalue, std::move(rvalue));
}

hlp::safe_unique_ptr<ast::ASTNode> Parser::parseFunctionVariableCompoundAssignment(TokenIter curr) {
m_curr = curr;
auto lhs = parseRValue();
Token::Operator op = getValue<Token::Operator>(0);
next();
if (op == Token::Operator::BoolLessThan) {
op = Token::Operator::LeftShift;
next();
} else if (op == Token::Operator::BoolGreaterThan) {
op = Token::Operator::RightShift;
next();
}
next();

auto rhs = parseMathematicalExpression();
if (rhs == nullptr)
return nullptr;

auto lhsCopy = lhs->clone();
rhs = create<ast::ASTNodeMathematicalExpression>(std::move(lhsCopy), std::move(rhs), op);

return create<ast::ASTNodeRValueAssignment>(std::move(lhs), std::move(rhs));
}

hlp::safe_unique_ptr<ast::ASTNode> Parser::parseFunctionVariableCompoundAssignment(const std::string &lvalue) {
auto op = getValue<Token::Operator>(-2);

Expand Down Expand Up @@ -1884,12 +1910,14 @@ namespace pl::core {

if (sequence(tkn::Operator::Dollar, tkn::Operator::Assign))
member = parseFunctionVariableAssignment("$");
else if (parseCompoundAssignment(tkn::Operator::Dollar).has_value())
else if (isCompoundAssignmentOperator(tkn::Operator::Dollar).has_value())
member = parseFunctionVariableCompoundAssignment("$");
else if (sequence(tkn::Literal::Identifier, tkn::Operator::Assign)) {
member = parseFunctionVariableAssignment(getValue<Token::Identifier>(-2).get());
} else if (const auto identifierOffset = parseCompoundAssignment(tkn::Literal::Identifier); identifierOffset.has_value())
} else if (const auto identifierOffset = isCompoundAssignmentOperator(tkn::Literal::Identifier); identifierOffset.has_value())
member = parseFunctionVariableCompoundAssignment(getValue<Token::Identifier>(*identifierOffset).get());
else if (const auto curr = isCompoundAssignmentOperator(AllowKeywords::Both); curr.has_value())
member = parseFunctionVariableCompoundAssignment(curr.value());
else if (MATCHES((sequence(tkn::Literal::Identifier) || sequence(tkn::Keyword::Parent) || sequence(tkn::Keyword::This)) && (peek(tkn::Separator::Dot) || (peek(tkn::Separator::LeftBracket, 0) && !peek(tkn::Separator::LeftBracket, 1)))))
member = parseRValueAssignment();
else if (peek(tkn::Keyword::Const) || peek(tkn::Keyword::BigEndian) || peek(tkn::Keyword::LittleEndian) || peek(tkn::ValueType::Any) || peek(tkn::Literal::Identifier)) {
Expand Down Expand Up @@ -2160,8 +2188,12 @@ namespace pl::core {
if (identifier != nullptr)
identifier->setType(Token::Identifier::IdentifierType::LocalVariable);
member = parseFunctionVariableAssignment(variableName);
} else if (const auto identifierOffset = parseCompoundAssignment(tkn::Literal::Identifier); identifierOffset.has_value())
} else if (const auto identifierOffset = isCompoundAssignmentOperator(tkn::Literal::Identifier); identifierOffset.has_value())
member = parseFunctionVariableCompoundAssignment(getValue<Token::Identifier>(*identifierOffset).get());
else if (const auto curr = isCompoundAssignmentOperator(AllowKeywords::Parent); curr.has_value())
member = parseFunctionVariableCompoundAssignment(curr.value());
else if (MATCHES((sequence(tkn::Literal::Identifier) || sequence(tkn::Keyword::Parent)) && (peek(tkn::Separator::Dot) || (peek(tkn::Separator::LeftBracket, 0) && !peek(tkn::Separator::LeftBracket, 1)))))
member = parseRValueAssignment();
else if (MATCHES(optional(tkn::Keyword::Unsigned) && sequence(tkn::Literal::Identifier, tkn::Operator::Colon))) {
auto fieldName = getValue<Token::Identifier>(-2).get();
auto identifier = std::get_if<Token::Identifier>(&((m_curr[-2]).value));
Expand Down Expand Up @@ -2643,8 +2675,12 @@ namespace pl::core {
statement = parseFunctionVariableAssignment(getValue<Token::Identifier>(-2).get());
else if (sequence(tkn::Operator::Dollar, tkn::Operator::Assign))
statement = parseFunctionVariableAssignment("$");
else if (const auto identifierOffset = parseCompoundAssignment(tkn::Literal::Identifier); identifierOffset.has_value())
else if (const auto identifierOffset = isCompoundAssignmentOperator(tkn::Literal::Identifier); identifierOffset.has_value())
statement = parseFunctionVariableCompoundAssignment(getValue<Token::Identifier>(*identifierOffset).get());
else if (const auto curr = isCompoundAssignmentOperator(); curr.has_value())
statement = parseFunctionVariableCompoundAssignment(curr.value());
else if (MATCHES(sequence(tkn::Literal::Identifier) && (peek(tkn::Separator::Dot) || (peek(tkn::Separator::LeftBracket, 0) && !peek(tkn::Separator::LeftBracket, 1)))))
statement = parseRValueAssignment();
else if (MATCHES(sequence(tkn::Keyword::Using, tkn::Literal::Identifier)))
statement = parseUsingDeclaration();
else if (sequence(tkn::Keyword::Import))
Expand Down Expand Up @@ -2704,23 +2740,53 @@ namespace pl::core {
return hlp::moveToVector(std::move(statement));
}

std::optional<i32> Parser::parseCompoundAssignment(const Token &token) {
std::optional<i32> Parser::isCompoundAssignmentOperator(const Token &token) {
auto save = m_curr;

if (sequence(token)) {
if (auto offset = isCompoundAssignmentOperator(-1); offset.has_value())
return offset;
}

m_curr = save;
return std::nullopt;
}

std::optional<i32> Parser::isCompoundAssignmentOperator(i32 offset) {
const static std::array SingleTokens = { tkn::Operator::Plus, tkn::Operator::Minus, tkn::Operator::Star, tkn::Operator::Slash, tkn::Operator::Percent, tkn::Operator::BitOr, tkn::Operator::BitAnd, tkn::Operator::BitXor };
const static std::array DoubleTokens = { tkn::Operator::BoolLessThan, tkn::Operator::BoolGreaterThan };

for (auto &singleToken : SingleTokens) {
if (sequence(token, singleToken, tkn::Operator::Assign))
return -3;
for (auto &token : SingleTokens) {
if (sequence(token, tkn::Operator::Assign))
return -2 + offset;
}

for (auto &doubleTokens : DoubleTokens) {
if (sequence(token, doubleTokens, doubleTokens, tkn::Operator::Assign))
return -4;
for (auto &token : DoubleTokens) {
if (sequence(token, token, tkn::Operator::Assign))
return -3 + offset;
}

return std::nullopt;
}

std::optional<Parser::TokenIter> Parser::isCompoundAssignmentOperator(AllowKeywords allowKeywords) {
auto save = this->m_curr;
bool allowParent = ((u32)allowKeywords & (u32)AllowKeywords::Parent) != 0;
bool allowThis = ((u32)allowKeywords & (u32)AllowKeywords::This) != 0;
if (MATCHES((sequence(tkn::Literal::Identifier) || (allowParent && sequence(tkn::Keyword::Parent)) || (allowThis && sequence(tkn::Keyword::This))) && (peek(tkn::Separator::Dot) || (peek(tkn::Separator::LeftBracket, 0) && !peek(tkn::Separator::LeftBracket, 1))))) {
auto result = m_curr;
auto lhs = parseRValue();
if (lhs == nullptr) {
m_curr = save;
return std::nullopt;
}
if (isCompoundAssignmentOperator(-1).has_value())
return result;
}
m_curr = save;
return std::nullopt;
}

hlp::safe_shared_ptr<ast::ASTNodeTypeDecl> Parser::addType(const std::string &name, hlp::safe_unique_ptr<ast::ASTNode> &&node) {
auto typeName = getNamespacePrefixedNames(name).back();

Expand Down
Loading