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
2 changes: 2 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ add_library(libpl ${LIBRARY_TYPE}
source/pl/core/ast/ast_node_while_statement.cpp

source/pl/core/ast/visitors/ast_validator.cpp
source/pl/core/ast/visitors/control_flow_validator.cpp
source/pl/core/ast/visitors/scope_validator.cpp

source/pl/core/token.cpp
source/pl/core/evaluator.cpp
Expand Down
18 changes: 18 additions & 0 deletions lib/include/pl/core/ast/visitors/control_flow_validator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include <pl/core/ast/visitors/ast_validator.hpp>

namespace pl::core {
class ControlFlowValidator final : public ASTValidator {
uint32_t m_loopsCount = 0;

void reset() override;

void visit(ast::ASTNodeFunctionDefinition& node) override;
void visit(ast::ASTNodeWhileStatement& node) override;
void visit(ast::ASTNodeMatchStatement& node) override;
void visit(ast::ASTNodeTryCatchStatement& node) override;
void visit(ast::ASTNodeConditionalStatement& node) override;
void visit(ast::ASTNodeControlFlowStatement& node) override;
};
}
55 changes: 55 additions & 0 deletions lib/include/pl/core/ast/visitors/scope_validator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#pragma once

#include <pl/core/ast/visitors/ast_validator.hpp>
#include <stack>

namespace pl::core {
class ScopeValidator final : public ASTValidator {

struct Scope {
std::unordered_set<std::string> m_names;

[[nodiscard]] bool newIdentifier(const std::string& name);

void mergeWith(Scope& from);
};

std::stack<Scope> m_scopes;

u32 m_curNonFuncScopes = 0;

public:
ScopeValidator();

private:
void reset() override;

void pushScope();
void pushScope(Scope&& scope);
void popScope();
Scope &currentScope();

[[nodiscard]] bool isFunctionScope() const;

[[nodiscard]] bool newIdentifier(const std::string& name);


void visit(ast::ASTNodeVariableDecl& node) override;
void visit(ast::ASTNodeArrayVariableDecl& node) override;
void visit(ast::ASTNodePointerVariableDecl& node) override;
void visit(ast::ASTNodeBitfieldField& node) override;
void visit(ast::ASTNodeMultiVariableDecl& node) override;
void visit(ast::ASTNodeTypeDecl& node) override;
void visit(ast::ASTNodeStruct& node) override;
void visit(ast::ASTNodeUnion& node) override;
void visit(ast::ASTNodeBitfield& node) override;
void visit(ast::ASTNodeBitfieldArrayVariableDecl& node) override;
void visit(ast::ASTNodeEnum& node) override;
void visit(ast::ASTNodeConditionalStatement& node) override;
void visit(ast::ASTNodeFunctionDefinition& node) override;
void visit(ast::ASTNodeCompoundStatement& node) override;
void visit(ast::ASTNodeWhileStatement& node) override;
void visit(ast::ASTNodeMatchStatement& node) override;
void visit(ast::ASTNodeTryCatchStatement& node) override;
};
}
30 changes: 1 addition & 29 deletions lib/include/pl/core/validator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,6 @@ namespace pl::core {

namespace ast { class ASTNode; }

class Validator : err::ErrorCollector {
using Result = hlp::CompileResult<bool>;
public:
Validator() = default;

Result validate(const std::vector<std::shared_ptr<ast::ASTNode>> &ast);

void setRecursionDepth(const u32 limit) {
this->m_maxRecursionDepth = std::min<u32>(limit, 255);
}

private:
bool validateNodes(const std::vector<std::unique_ptr<ast::ASTNode>> &nodes, bool newScope = true);
bool validateNodes(const std::vector<std::shared_ptr<ast::ASTNode>> &nodes, bool newScope = true);
bool validateNode(const std::shared_ptr<ast::ASTNode>& node, bool newScope = true);
bool validateNode(ast::ASTNode *node, std::unordered_set<std::string>& identifiers);

Location location() override;

u32 m_maxRecursionDepth = 32;
u32 m_recursionDepth = 0;

ast::ASTNode *m_lastNode = nullptr;
std::set<ast::ASTNode*> m_validatedNodes;
std::list<std::unordered_set<std::string>> m_identifiers;
};

class ValidatorPipeline {
public:
using Result = hlp::CompileResult<bool>;
Expand All @@ -53,7 +26,7 @@ namespace pl::core {

template <std::derived_from<ASTValidator>... Vs>
ValidatorPipeline(std::unique_ptr<Vs>... validators) {
(add(validators), ...);
(add(std::move(validators)), ...);
}

void add(std::unique_ptr<ASTValidator> validator);
Expand All @@ -63,5 +36,4 @@ namespace pl::core {
private:
std::vector<std::unique_ptr<ASTValidator>> m_validators;
};

}
2 changes: 0 additions & 2 deletions lib/include/pl/pattern_language.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ namespace pl {
class Preprocessor;
class Lexer;
class Parser;
class Validator;
class ValidatorPipeline;
class Evaluator;

Expand Down Expand Up @@ -65,7 +64,6 @@ namespace pl {
std::unique_ptr<core::Preprocessor> preprocessor;
std::unique_ptr<core::Lexer> lexer;
std::unique_ptr<core::Parser> parser;
std::unique_ptr<core::Validator> validator;
std::unique_ptr<core::ValidatorPipeline> validatorPipeline;
std::unique_ptr<core::Evaluator> evaluator;
};
Expand Down
69 changes: 69 additions & 0 deletions lib/source/pl/core/ast/visitors/control_flow_validator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

#include <pl/core/ast/visitors/control_flow_validator.hpp>

#include <pl/core/ast/ast_node_function_definition.hpp>
#include <pl/core/ast/ast_node_control_flow_statement.hpp>
#include <pl/core/ast/ast_node_try_catch_statement.hpp>
#include <pl/core/ast/ast_node_while_statement.hpp>
#include <pl/core/ast/ast_node_match_statement.hpp>
#include <pl/core/ast/ast_node_conditional_statement.hpp>

namespace pl::core {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I can tell, this only handles control flow statements in functions but not inside types, correct?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

void ControlFlowValidator::visit(ast::ASTNodeFunctionDefinition &node) {
visitTypeErasedNodes(node.getBody());
}

void ControlFlowValidator::visit(ast::ASTNodeWhileStatement &node) {
++m_loopsCount;
visitTypeErasedNodes(node.getBody());
--m_loopsCount;
}

void ControlFlowValidator::visit(ast::ASTNodeMatchStatement &node) {
if (const auto& default_case = node.getDefaultCase(); default_case) {
const auto& body = (*default_case).body;
visitTypeErasedNodes(body);
}
for (const auto& match_case: node.getNonDefaultCases()) {
visitTypeErasedNodes(match_case.body);
}
}

void ControlFlowValidator::visit(ast::ASTNodeTryCatchStatement &node) {
visitTypeErasedNodes(node.getTryBody());
visitTypeErasedNodes(node.getCatchBody());
}

void ControlFlowValidator::visit(ast::ASTNodeConditionalStatement &node) {
visitTypeErasedNodes(node.getTrueBody());
visitTypeErasedNodes(node.getFalseBody());
}

void ControlFlowValidator::visit(ast::ASTNodeControlFlowStatement &node) {
if (m_loopsCount > 0) {
// Nothing bad.
return;
}
// Could be bad, let's check

auto type = node.getType();
switch (type) {
case ControlFlowStatement::Break: {
error("Break statements can only be used within a loop.");
return;
}
case ControlFlowStatement::Continue: {
error("Continue statements can only be used within a loop.");
return;
}
default: {
return;
}
}
}

void ControlFlowValidator::reset() {
// This can't become anything else, but why not make it explicit...
m_loopsCount = 0;
}
}
Loading
Loading