Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c31ac1a
Migrate code
shewitt-au Sep 6, 2025
7cca893
Add .gitignore to hide gen code
shewitt-au Sep 7, 2025
0e7758e
Fix max line len for last line without /n
shewitt-au Sep 14, 2025
d75495e
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Oct 17, 2025
c958609
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Oct 23, 2025
3212b7a
Cleanup some includes
shewitt-au Nov 4, 2025
5da959b
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Dec 2, 2025
9eb4c1d
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Dec 3, 2025
13382bd
2nd merge attempt
shewitt-au Dec 4, 2025
e79c143
Update libwolv submodule
shewitt-au Dec 4, 2025
ffdbc94
Merge branch 'master' of https://github.com/WerWolv/PatternLanguage i…
shewitt-au Dec 6, 2025
a67e554
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Dec 6, 2025
10a599c
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Dec 7, 2025
a9ac9f2
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Dec 29, 2025
f0fbb32
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Dec 31, 2025
5cd62ff
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Feb 27, 2026
43e9879
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Mar 15, 2026
f9dc530
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Mar 20, 2026
1105bd1
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Mar 21, 2026
56acdc3
Merge branch 'WerWolv:master' into new_lexer
shewitt-au Apr 27, 2026
5e4d893
Merge branch 'WerWolv:master' into new_lexer
shewitt-au May 3, 2026
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@
path = external/throwing_ptr
url = https://github.com/rockdreamer/throwing_ptr
ignore = dirty
[submodule "external/lexertl17"]
path = external/lexertl17
url = https://github.com/BenHanson/lexertl17.git
1 change: 1 addition & 0 deletions external/lexertl17
Submodule lexertl17 added at 5507ee
21 changes: 21 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@ else ()
message(STATUS "libpl static library is being created")
endif ()

add_subdirectory(lexer_gen)

set(PL_STATICLEXERPATH "${CMAKE_CURRENT_SOURCE_DIR}/include/pl/core/generated/lexer_static.hpp")

add_custom_command(
OUTPUT ${PL_STATICLEXERPATH}
COMMAND $<TARGET_FILE:lexer_gen> ${PL_STATICLEXERPATH}
DEPENDS lexer_gen
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating lexertl17 static lexer"
)

add_custom_target(run_lexer_gen
DEPENDS ${PL_STATICLEXERPATH}
)

add_library(libpl ${LIBRARY_TYPE}
source/pl/helpers/utils.cpp

Expand Down Expand Up @@ -53,7 +69,11 @@ add_library(libpl ${LIBRARY_TYPE}

source/pl/core/token.cpp
source/pl/core/evaluator.cpp

source/pl/core/lexer.cpp
$<$<NOT:$<CONFIG:Debug>>:${PL_STATICLEXERPATH}>
$<$<CONFIG:Debug>:source/pl/core/lexer_sm.cpp>

source/pl/core/parser.cpp
source/pl/core/preprocessor.cpp
source/pl/core/validator.cpp
Expand Down Expand Up @@ -103,6 +123,7 @@ endif ()

target_include_directories(libpl PUBLIC include ../external/throwing_ptr/include)
target_include_directories(libpl_includes INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include ../external/throwing_ptr/include)
target_include_directories(libpl PRIVATE include ../external/lexertl17/include)
target_link_libraries(libpl PRIVATE ${FMT_LIBRARIES})
target_link_libraries(libpl PUBLIC wolv::types wolv::io wolv::utils wolv::hash wolv::containers)

Expand Down
2 changes: 2 additions & 0 deletions lib/include/pl/core/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Ignore generated code folder
generated/
59 changes: 42 additions & 17 deletions lib/include/pl/core/errors/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,33 +131,27 @@ namespace pl::core::err {
std::vector<Location> m_trace;
};

class ErrorCollector {
class ErrorCollectorExplicitLocation
{
public:

virtual ~ErrorCollector() = default;

virtual Location location() = 0;
virtual ~ErrorCollectorExplicitLocation() = default;

template <typename... Args>
void error(const fmt::format_string<Args...>& fmt, Args&&... args) {
this->m_errors.emplace_back(fmt::format(fmt, std::forward<Args>(args)...), location());
void error(const Location &location, const fmt::format_string<Args...> &fmt, Args&&... args) {
this->m_errors.emplace_back(fmt::format(fmt, std::forward<Args>(args)...), location);
}

void error(const std::string &message) {
this->m_errors.emplace_back(message, location());
}

void errorDesc(const std::string &message, const std::string &description) {
this->m_errors.emplace_back(message, description, location());
void errorDesc(const Location &location, const std::string &message, const std::string &description) {
this->m_errors.emplace_back(message, description, location);
}

template<typename... Args>
void errorDesc(const fmt::format_string<Args...>& message, const std::string &description, Args&&... args) {
this->m_errors.emplace_back(fmt::format(message, std::forward<Args>(args)...), description, location());
void errorDesc(const Location &location, const fmt::format_string<Args...>& message, const std::string &description, Args&&... args) {
this->m_errors.emplace_back(fmt::format(message, std::forward<Args>(args)...), description, location);
}

void error(CompileError& error) {
error.getTrace().push_back(location());
void error(const Location &location, CompileError& error) {
error.getTrace().push_back(location);
this->m_errors.push_back(std::move(error));
}

Expand Down Expand Up @@ -189,8 +183,39 @@ namespace pl::core::err {
void clear() {
this->m_errors.clear();
}

private:
std::vector<CompileError> m_errors;
};

class ErrorCollector : public ErrorCollectorExplicitLocation {
public:

virtual ~ErrorCollector() = default;

virtual Location location() = 0;

template <typename... Args>
void error(const fmt::format_string<Args...> &fmt, Args&&... args) {
this->ErrorCollectorExplicitLocation::error(location(), fmt, std::forward<Args>(args)...);
}

void error(const std::string &message) {
this->errorAt(location(), message);
}

void errorDesc(const std::string &message, const std::string &description) {
this->ErrorCollectorExplicitLocation::errorDesc(location(), message, description);
}

template<typename... Args>
void errorDesc(const fmt::format_string<Args...>& message, const std::string &description, Args&&... args) {
this->ErrorCollectorExplicitLocation::errorDesc(location(), message, description, std::forward<Args>(args)...);
}

void error(CompileError& error) {
this->ErrorCollectorExplicitLocation::error(location(), error);
}
};

}
71 changes: 16 additions & 55 deletions lib/include/pl/core/lexer.hpp
Original file line number Diff line number Diff line change
@@ -1,72 +1,33 @@
// "Lexer.hpp"
#pragma once

#include <pl/helpers/types.hpp>
#include <pl/core/errors/error.hpp>

#include <pl/core/token.hpp>

#include <fmt/core.h>

#include <cstddef>
#include <optional>
#include <string>
#include <string_view>
#include <vector>

#include <pl/core/token.hpp>
#include <pl/core/errors/error.hpp>
#include <pl/core/errors/result.hpp>

namespace pl::core {

class Lexer : err::ErrorCollector {
class Lexer : err::ErrorCollectorExplicitLocation {
public:
Lexer() = default;
Lexer();

void reset();

hlp::CompileResult<std::vector<Token>> lex(const api::Source *source);
size_t getLongestLineLength() const { return m_longestLineLength; }
void reset();

private:
[[nodiscard]] char peek(size_t p = 1) const;
bool processToken(auto parserFunction, const std::string_view& identifier);
Location location() override;
std::optional<Token::Literal> parseInteger(std::string_view literal, const auto &location);
std::optional<double> parseFloatingPoint(std::string_view literal, const char suffix, const auto &location);
std::optional<char> parseCharacter(const char* &pchar, const char* e, const auto &location);
std::optional<Token> parseStringLiteral(std::string_view literal, const auto &location);

std::optional<char> parseCharacter();
std::optional<Token> parseOperator();
std::optional<Token> parseSeparator();
std::optional<Token> parseOneLineComment();
std::optional<Token> parseOneLineDocComment();
std::optional<Token> parseMultiLineComment();
std::optional<Token> parseMultiLineDocComment();
std::optional<Token> parseKeyword(const std::string_view &identifier);
std::optional<Token> parseType(const std::string_view &identifier);
std::optional<Token> parseDirectiveName(const std::string_view &identifier);
std::optional<Token> parseNamedOperator(const std::string_view &identifier);
std::optional<Token> parseConstant(const std::string_view &identifier);
std::optional<Token> parseStringLiteral();
std::optional<Token> parseDirectiveArgument();
std::optional<Token> parseDirectiveValue();
std::optional<Token::Literal> parseIntegerLiteral(std::string_view literal);

std::optional<double> parseFloatingPoint(std::string_view literal, char suffix);
std::optional<u128> parseInteger(std::string_view literal);

Token makeToken(const Token& token, size_t length = 1);
static Token makeTokenAt(const Token& token, Location& location, size_t length = 1);
void addToken(const Token& token);
bool hasTheLineEnded(const char &ch) {
if(ch == '\n') {
m_longestLineLength = std::max(m_longestLineLength, m_cursor - m_lineBegin);
m_line++;
m_lineBegin = m_cursor;
return true;
}
return false;
}
std::string m_sourceCode;
const api::Source* m_source = nullptr;
std::vector<Token> m_tokens;
size_t m_cursor = 0;
u32 m_line = 0;
u32 m_lineBegin = 0;
size_t m_longestLineLength = 0;
u32 m_errorLength = 0;
std::size_t m_longestLineLength = 0;
};
}

} // namespace pl::core
23 changes: 23 additions & 0 deletions lib/include/pl/core/lexer_sm.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <lexertl/state_machine.hpp>

namespace pl::core {

namespace {

namespace LexerToken {

enum {
EndOfFile, NewLine, KWNamedOpTypeConstIdent, SingleLineComment,
MultiLineCommentOpen, MultiLineCommentClose, String, Separator,
Directive, DirectiveType, DirectiveParam, Operator, Char,
Integer, FPNumber
};

}
}

void newLexerBuild(lexertl::state_machine &sm);

}
12 changes: 12 additions & 0 deletions lib/lexer_gen/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
set(SOURCES
../source/pl/core/lexer_sm.cpp
main.cpp
)

add_executable(lexer_gen ${SOURCES})

target_include_directories(lexer_gen PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../include
)

target_include_directories(lexer_gen PRIVATE include ../../external/lexertl17/include)
39 changes: 39 additions & 0 deletions lib/lexer_gen/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
Build a "static" lexer in release builds.

Static in the sense that the state machine is built in a pre-build
step to optimize application start-up time.
*/
#include <pl/core/lexer_sm.hpp>

#include <lexertl/state_machine.hpp>
#include <lexertl/generate_cpp.hpp>

#include <fstream>
#include <filesystem>

int main(int argc, char *argv[])
{
if (argc!=2)
return 1;

try
{
std::filesystem::path argPath(argv[1]);
std::filesystem::path genDir = argPath.parent_path();
std::filesystem::create_directory(genDir);
}
catch (const std::filesystem::filesystem_error &fse)
{
return 1;
}

lexertl::state_machine sm;
pl::core::newLexerBuild(sm);
sm.minimise();

std::ofstream ofs(argv[1]);
lexertl::table_based_cpp::generate("lookup", sm, false, ofs);

return 0;
}
Loading
Loading