Skip to content

Commit

Permalink
all: import statement first implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
jumanji144 committed Nov 26, 2023
1 parent c13ada4 commit 1c80503
Show file tree
Hide file tree
Showing 13 changed files with 193 additions and 21 deletions.
1 change: 1 addition & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ add_library(libpl ${LIBRARY_TYPE}
source/pl/lib/std/hash.cpp
source/pl/lib/std/random.cpp
source/pl/core/resolvers.cpp
source/pl/core/parser_manager.cpp
)

if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
Expand Down
5 changes: 3 additions & 2 deletions lib/include/pl/core/ast/ast_node_compound_statement.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,22 @@ namespace pl::core::ast {
public Attributable {
public:
explicit ASTNodeCompoundStatement(std::vector<std::unique_ptr<ASTNode>> &&statements, bool newScope = false);
explicit ASTNodeCompoundStatement(std::vector<std::shared_ptr<ASTNode>> &&statements, bool newScope = false);
ASTNodeCompoundStatement(const ASTNodeCompoundStatement &other);

[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
return std::unique_ptr<ASTNode>(new ASTNodeCompoundStatement(*this));
}

[[nodiscard]] const std::vector<std::unique_ptr<ASTNode>>& getStatements() const { return this->m_statements; }
[[nodiscard]] const std::vector<std::shared_ptr<ASTNode>>& getStatements() const { return this->m_statements; }

[[nodiscard]] std::unique_ptr<ASTNode> evaluate(Evaluator *evaluator) const override;
[[nodiscard]] std::vector<std::shared_ptr<ptrn::Pattern>> createPatterns(Evaluator *evaluator) const override;
FunctionResult execute(Evaluator *evaluator) const override;
void addAttribute(std::unique_ptr<ASTNodeAttribute> &&attribute) override;

public:
std::vector<std::unique_ptr<ASTNode>> m_statements;
std::vector<std::shared_ptr<ASTNode>> m_statements;
bool m_newScope = false;
};

Expand Down
2 changes: 1 addition & 1 deletion lib/include/pl/core/errors/result.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace pl::hlp {
}

[[nodiscard]] bool is_ok() const {
return ok.has_value();
return !has_errs() && ok.has_value();
}

[[nodiscard]] bool is_err() const {
Expand Down
2 changes: 1 addition & 1 deletion lib/include/pl/core/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace pl::core {
std::map<std::string, std::shared_ptr<ast::ASTNodeTypeDecl>> m_types;

std::vector<TokenIter> m_matchedOptionals;
std::vector<std::vector<std::string>> m_currNamespace;
std::vector<std::vector<std::string>> m_currNamespace = { {} };

std::vector<std::string> m_globalDocComments;
i32 m_ignoreDocsCount = 0;
Expand Down
17 changes: 15 additions & 2 deletions lib/include/pl/core/parser_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,35 @@
#include <pl/core/resolver.hpp>

#include <utility>
#include <set>

namespace pl::core {

class ParserManager {
public:
explicit ParserManager() = default;

CompileResult<std::vector<std::shared_ptr<ast::ASTNode>>> parse(const api::Source* source, const std::string &namespacePrefix = "");
CompileResult<std::vector<std::shared_ptr<ast::ASTNode>>> parse(api::Source* source, const std::string &namespacePrefix = "");

void setResolvers(Resolver* resolvers) {
void setResolver(Resolver* resolvers) {
m_resolvers = resolvers;
}

void setPatternLanguage(PatternLanguage* patternLanguage) {
m_patternLanguage = patternLanguage;
}

[[nodiscard]] Resolver* getResolver() {
return m_resolvers;
}

private:
std::map<std::string, std::vector<std::shared_ptr<ast::ASTNode>>> m_astCache;

Resolver* m_resolvers = nullptr;
PatternLanguage* m_patternLanguage = nullptr;

std::set<api::Source*> m_onceIncluded;
};

}
8 changes: 7 additions & 1 deletion lib/source/pl/core/ast/ast_node_compound_statement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@

namespace pl::core::ast {

ASTNodeCompoundStatement::ASTNodeCompoundStatement(std::vector<std::unique_ptr<ASTNode>> &&statements, bool newScope) : m_statements(std::move(statements)), m_newScope(newScope) {
ASTNodeCompoundStatement::ASTNodeCompoundStatement(std::vector<std::unique_ptr<ASTNode>> &&statements, bool newScope) : m_newScope(newScope) {
for (auto &statement : statements) {
this->m_statements.emplace_back(std::move(statement));
}
}

ASTNodeCompoundStatement::ASTNodeCompoundStatement(std::vector<std::shared_ptr<ASTNode>> &&statements, bool newScope) : m_statements(statements), m_newScope(newScope) {
}

ASTNodeCompoundStatement::ASTNodeCompoundStatement(const ASTNodeCompoundStatement &other) : ASTNode(other), Attributable(other) {
Expand Down
2 changes: 1 addition & 1 deletion lib/source/pl/core/evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ namespace pl::core {
this->m_scopes.pop_back();
}

std::vector<ast::ASTNode*> unpackCompoundStatements(const std::vector<std::unique_ptr<ast::ASTNode>> &nodes) {
std::vector<ast::ASTNode*> unpackCompoundStatements(const std::vector<std::shared_ptr<ast::ASTNode>> &nodes) {
std::vector<ast::ASTNode*> result;

for (const auto &node : nodes) {
Expand Down
47 changes: 35 additions & 12 deletions lib/source/pl/core/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,16 +532,29 @@ namespace pl::core {
return create<ast::ASTNodeFunctionDefinition>(getNamespacePrefixedNames(functionName).back(), std::move(params), std::move(body), parameterPack, std::move(defaultParameters));
}

// identifier_path := identifier *(dot identifier)?
// string_path := string
//
// path := identifier_path | string_path
//
// 'import' path (colon colon identifier)? ('as' identifier *(colon colon identifier)?)?
std::unique_ptr<ast::ASTNode> Parser::parseImportStatement() {
// 'import' identifier ( colon colon identifier)* ('as' identifier)? semicolon
// parse consumed `import <identifier>` for us
auto name = getValue<Token::Identifier>(-1).get();
std::string path;
if(sequence(tkn::Literal::String)) {
path = std::get<std::string>(getValue<Token::Literal>(-1));
} else if(sequence(tkn::Literal::Identifier)) {
path = getValue<Token::Identifier>(-1).get();

while (sequence(tkn::Separator::Dot, tkn::Literal::Identifier)) {
path += "/";
path += getValue<Token::Identifier>(-1).get();
}

while (sequence(tkn::Operator::ScopeResolution, tkn::Literal::Identifier)) {
name += "/";
name += getValue<Token::Identifier>(-1).get();
path += ".pat";
}

// TODO: struct import

std::string alias;

if (sequence(tkn::Keyword::As)) {
Expand All @@ -551,10 +564,21 @@ namespace pl::core {
alias = getValue<Token::Identifier>(-1).get();
}

if (!sequence(tkn::Separator::Semicolon))
err::P0002.throwError(fmt::format("Expected ';' at end of import statement, got {}.", getFormattedToken(0)), {}, 1);
// resolve source
auto [resolvedSource, resolverErrors] = m_parserManager->getResolver()->resolve(path);
if(!resolverErrors.empty()) {
// handle all errors
err::P0003.throwError(resolverErrors[0], {}, 1);
}

return nullptr;
auto [parserAst, parserErrors] = m_parserManager->parse(resolvedSource.value(), alias);
if(!parserErrors.empty()) {
// handle all errors
err::P0003.throwError(parserErrors[0].getDescription(), {}, 1);
}

auto compoundStatement = create<ast::ASTNodeCompoundStatement>(std::move(parserAst.value()), false);
return compoundStatement;
}

std::unique_ptr<ast::ASTNode> Parser::parseFunctionVariableDecl(bool constant) {
Expand Down Expand Up @@ -1699,6 +1723,8 @@ namespace pl::core {
statement = parseBitfield();
else if (sequence(tkn::Keyword::Function, tkn::Literal::Identifier))
statement = parseFunctionDefinition();
else if (sequence(tkn::Keyword::Import))
statement = parseImportStatement();
else if (sequence(tkn::Keyword::Namespace))
return parseNamespace();
else {
Expand Down Expand Up @@ -1819,9 +1845,6 @@ namespace pl::core {
this->m_matchedOptionals.clear();
this->m_processedDocComments.clear();

this->m_currNamespace.clear();
this->m_currNamespace.emplace_back();

try {
auto program = parseTillToken(tkn::Separator::EndOfProgram);

Expand Down
70 changes: 70 additions & 0 deletions lib/source/pl/core/parser_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include <pl/core/parser_manager.hpp>
#include <pl/core/preprocessor.hpp>
#include <pl/core/validator.hpp>
#include <pl/core/parser.hpp>
#include <pl/core/lexer.hpp>

#include <wolv/utils/string.hpp>

using namespace pl::core;

CompileResult<std::vector<std::shared_ptr<ast::ASTNode>>>
ParserManager::parse(api::Source *source, const std::string &namespacePrefix) {
using result_t = CompileResult<std::vector<std::shared_ptr<ast::ASTNode>>>;

if (this->m_astCache.contains(source->source)) {
return result_t::good(this->m_astCache[source->source]);
}

if(m_onceIncluded.contains(source))
return result_t::good({});

auto parser = Parser();

std::vector<std::string> namespaces;
if (!namespacePrefix.empty()) {
namespaces = wolv::util::splitString(namespacePrefix, "::");
}

auto preprocessor = Preprocessor();

preprocessor.addPragmaHandler("namespace", [&](auto&, const std::string& value) {
if(namespacePrefix.empty())
namespaces = wolv::util::splitString(value, "::");
return true;
});

auto lexer = Lexer();
auto validator = Validator();

auto [preprocessedCode, preprocessorErrors] = preprocessor.preprocess(this->m_patternLanguage, source);
if (!preprocessorErrors.empty()) {
return result_t::err(preprocessorErrors);
}

source->content = preprocessedCode.value(); // update source object with preprocessed code

if(preprocessor.shouldOnlyIncludeOnce())
m_onceIncluded.insert(source);

auto [tokens, lexerErrors] = lexer.lex(source);

if (!lexerErrors.empty()) {
return result_t::err(lexerErrors);
}

parser.addNamespace(namespaces);
parser.setParserManager(this);

auto result = parser.parse(source->content, tokens.value());
if (result.has_errs())
return result;

if (!validator.validate(source->content, *result.ok, true, true)) {
return result_t::err({});
}

this->m_astCache[source->source] = result.ok.value();

return result;
}
5 changes: 4 additions & 1 deletion lib/source/pl/pattern_language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ namespace pl {

this->m_internals.preprocessor->setResolver(&this->m_resolvers);

this->m_parserManager.setResolvers(&this->m_resolvers);
this->m_parserManager.setResolver(&this->m_resolvers);
this->m_parserManager.setPatternLanguage(this);

this->m_internals.parser->setParserManager(&this->m_parserManager);
}

PatternLanguage::~PatternLanguage() {
Expand Down
26 changes: 26 additions & 0 deletions tests/include/test_patterns/test_pattern_import.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include "test_pattern.hpp"

namespace pl::test {

class TestPatternImport : public TestPattern {
public:
TestPatternImport() : TestPattern("Import") {
}
~TestPatternImport() override = default;

[[nodiscard]] std::string getSourceCode() const override {
return R"(
import IA as A;
fn main() {
A::a();
B::b();
C::c();
};
)";
}
};

}
27 changes: 27 additions & 0 deletions tests/source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ int runTests(int argc, char **argv) {
fmt::print("{}\n", message);
});

// Include test
runtime.addSource(R"(
#include <B>
#include <C>
Expand All @@ -78,6 +79,32 @@ int runTests(int argc, char **argv) {
fn c() {};
)", "C");

// Imports test
runtime.addSource(R"(
import IB;
import IC as C;
fn a() {};
)", "IA");

runtime.addSource(R"(
#pragma namespace B
import IC as C;
fn b() {};
)", "IB");

runtime.addSource(R"(
#pragma once
fn c() {};
)", "IC");

runtime.getResolver().registerProtocol("test", [&](const auto&) {
return hlp::Result<api::Source, std::string>::good(api::Source("fn test()", "test"));
});

auto &test = testPatterns[testName];

auto result = runtime.executeString(test->getSourceCode(), "<test: " + testName + ">");
Expand Down
2 changes: 2 additions & 0 deletions tests/source/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "test_patterns/test_pattern_doc_comments.hpp"
#include "test_patterns/test_pattern_strings.hpp"
#include "test_patterns/test_pattern_include.hpp"
#include "test_patterns/test_pattern_import.hpp"

std::array Tests = {
TEST(Placement),
Expand All @@ -41,6 +42,7 @@ std::array Tests = {
TEST(RValues),
TEST(Namespaces),
TEST(Include),
TEST(Import),
TEST(ExtraSemicolon),
TEST(Pointers),
TEST(Arrays),
Expand Down

0 comments on commit 1c80503

Please sign in to comment.