summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSlendi <slendi@socopon.com>2023-07-31 00:08:51 +0300
committerSlendi <slendi@socopon.com>2023-07-31 00:11:16 +0300
commit86cbf9cb889107c6fd6caea7a4fe791f06ecfc66 (patch)
tree878fab6988833f84dba74a64ccb5773721d0bf28
Initial commit
Signed-off-by: Slendi <slendi@socopon.com>
-rw-r--r--.clang-format207
-rw-r--r--.gitignore5
-rw-r--r--LICENSE.md16
-rw-r--r--holyparser.hpp585
-rw-r--r--meson.build73
-rw-r--r--rpl.cpp37
-rw-r--r--src/holyasm.gperf385
-rw-r--r--src/holylexer.cpp492
-rw-r--r--src/holyparser.cpp796
-rw-r--r--subprojects/fmt.wrap13
-rw-r--r--subprojects/wrapdb.json2880
-rw-r--r--test_holyparser.cpp325
12 files changed, 5814 insertions, 0 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..9d272c1
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,207 @@
+---
+BasedOnStyle: WebKit
+AccessModifierOffset: -2
+AlignAfterOpenBracket: DontAlign
+AlignArrayOfStructures: None
+AlignConsecutiveAssignments:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ PadOperators: true
+AlignConsecutiveBitFields:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ PadOperators: false
+AlignConsecutiveDeclarations:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ PadOperators: false
+AlignConsecutiveMacros:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ PadOperators: false
+AlignEscapedNewlines: Left
+AlignOperands: Align
+AlignTrailingComments: true
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: Always
+AllowShortCaseLabelsOnASingleLine: true
+AllowShortEnumsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: WithoutElse
+AllowShortLambdasOnASingleLine: All
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: MultiLine
+AttributeMacros:
+ - __capability
+BinPackArguments: true
+BinPackParameters: true
+BitFieldColonSpacing: Both
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: true
+ AfterControlStatement: Never
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: true
+ AfterObjCDeclaration: false
+ AfterStruct: true
+ AfterUnion: true
+ AfterExternBlock: false
+ BeforeCatch: false
+ BeforeElse: false
+ BeforeLambdaBody: false
+ BeforeWhile: false
+ IndentBraces: false
+ SplitEmptyFunction: false
+ SplitEmptyRecord: true
+ SplitEmptyNamespace: false
+BreakAfterJavaFieldAnnotations: false
+BreakBeforeBinaryOperators: All
+BreakBeforeBraces: Custom
+BreakBeforeConceptDeclarations: Always
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: BeforeComma
+BreakInheritanceList: BeforeColon
+BreakStringLiterals: true
+ColumnLimit: 90
+CommentPragmas: "^ IWYU pragma:"
+CompactNamespaces: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: false
+DerivePointerAlignment: false
+DisableFormat: false
+EmptyLineAfterAccessModifier: Never
+EmptyLineBeforeAccessModifier: LogicalBlock
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: false
+ForEachMacros:
+ - foreach
+ - Q_FOREACH
+ - BOOST_FOREACH
+IfMacros:
+ - KJ_IF_MAYBE
+IncludeBlocks: Preserve
+IncludeCategories:
+ - Regex: ^"(llvm|llvm-c|clang|clang-c)/
+ Priority: 2
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: ^(<|"(gtest|gmock|isl|json)/)
+ Priority: 3
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: .*
+ Priority: 1
+ SortPriority: 0
+ CaseSensitive: false
+IncludeIsMainRegex: (Test)?$
+IncludeIsMainSourceRegex: ""
+IndentAccessModifiers: false
+IndentCaseBlocks: false
+IndentCaseLabels: false
+IndentExternBlock: AfterExternBlock
+IndentGotoLabels: true
+IndentPPDirectives: AfterHash
+IndentRequiresClause: true
+IndentWidth: 2
+IndentWrappedFunctionNames: false
+InsertBraces: false
+InsertTrailingCommas: None
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+LambdaBodyIndentation: Signature
+Language: Cpp
+MacroBlockBegin: ""
+MacroBlockEnd: ""
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: Inner
+ObjCBinPackProtocolList: Auto
+ObjCBlockIndentWidth: 4
+ObjCBreakBeforeNestedBlockParam: true
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: true
+PPIndentWidth: -1
+PackConstructorInitializers: BinPack
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakOpenParenthesis: 0
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyIndentedWhitespace: 0
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Right
+QualifierAlignment: Leave
+ReferenceAlignment: Pointer
+ReflowComments: true
+RemoveBracesLLVM: false
+RequiresClausePosition: OwnLine
+SeparateDefinitionBlocks: Leave
+ShortNamespaceLines: 1
+SortIncludes: CaseSensitive
+SortJavaStaticImport: Before
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: true
+SpaceAroundPointerQualifiers: Default
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeCpp11BracedList: true
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeParensOptions:
+ AfterControlStatements: true
+ AfterForeachMacros: true
+ AfterFunctionDeclarationName: false
+ AfterFunctionDefinitionName: false
+ AfterIfMacros: true
+ AfterOverloadedOperator: false
+ AfterRequiresInClause: false
+ AfterRequiresInExpression: false
+ BeforeNonEmptyParentheses: false
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
+SpaceInEmptyBlock: true
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: Never
+SpacesInCStyleCastParentheses: false
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: true
+SpacesInLineCommentPrefix:
+ Minimum: 1
+ Maximum: -1
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Latest
+StatementAttributeLikeMacros:
+ - Q_EMIT
+StatementMacros:
+ - Q_UNUSED
+ - QT_REQUIRE_VERSION
+TabWidth: 2
+UseTab: ForIndentation
+WhitespaceSensitiveMacros:
+ - BOOST_PP_STRINGIZE
+ - CF_SWIFT_NAME
+ - NS_SWIFT_NAME
+ - PP_STRINGIZE
+ - STRINGIZE
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f3a17d0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+build
+.cache
+subprojects/fmt-9.1.0
+subprojects/packagecache
+
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..182a08f
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,16 @@
+HolyParser - A parser for HolyC and ZealC with verbose messages.
+Copyright (C) 2023 Slendi
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
diff --git a/holyparser.hpp b/holyparser.hpp
new file mode 100644
index 0000000..a85dd78
--- /dev/null
+++ b/holyparser.hpp
@@ -0,0 +1,585 @@
+#pragma once
+
+#include <memory>
+#include <utility>
+#if defined _WIN32 || defined __CYGWIN__
+# ifdef BUILDING_HOLYPARSER
+# define HOLYPARSER_PUBLIC __declspec(dllexport)
+# else
+# define HOLYPARSER_PUBLIC __declspec(dllimport)
+# endif
+#else
+# ifdef BUILDING_HOLYPARSER
+# define HOLYPARSER_PUBLIC __attribute__((visibility("default")))
+# else
+# define HOLYPARSER_PUBLIC
+# endif
+#endif
+
+#include <cstddef>
+#include <iterator>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <variant>
+#include <vector>
+
+namespace holyparser
+{
+
+using namespace std::literals;
+
+struct HOLYPARSER_PUBLIC TextPosition
+{
+ size_t row = 1, col = 1;
+ std::string pretty();
+};
+
+struct HOLYPARSER_PUBLIC TextRange
+{
+ TextPosition start, end;
+ std::string pretty();
+};
+
+struct HOLYPARSER_PUBLIC Message
+{
+ bool is_error = false;
+ TextRange range;
+ std::string msg;
+};
+
+Message HOLYPARSER_PUBLIC Error(std::string, TextRange);
+Message HOLYPARSER_PUBLIC Warning(std::string, TextRange);
+
+class HOLYPARSER_PUBLIC MessageList : public std::vector<Message>
+{
+public:
+ bool contains_errors();
+};
+
+extern HOLYPARSER_PUBLIC MessageList messages;
+
+enum class TokenType
+{
+ Invalid = -1,
+ EndOfFile,
+ NewLine,
+
+ Identifier,
+ IntegerLiteral,
+ FloatLiteral,
+ StringLiteral,
+ CharLiteral,
+ Preprocessor,
+
+ Comma,
+ Dot,
+ Colon,
+ Semicolon,
+ LParen,
+ RParen,
+ LBracket,
+ RBracket,
+ LSquirly,
+ RSquirly,
+ Range,
+
+ Add,
+ Subtract,
+ Multiply,
+ Divide,
+ Modulo,
+ Pow,
+
+ LeftBitShift,
+ RightBitShift,
+
+ BitwiseAnd,
+ BitwiseOr,
+ BitwiseXOR,
+
+ OnesComplement,
+
+ AddSet,
+ SubtractSet,
+ MultiplySet,
+ DivideSet,
+ ModuloSet,
+
+ LeftBitShiftSet,
+ RightBitShiftSet,
+
+ BitwiseAndSet,
+ BitwiseOrSet,
+ BitwiseXORSet,
+
+ Increment,
+ Decrement,
+
+ Set,
+
+ Not,
+ And,
+ Or,
+ XOR,
+
+ Equals,
+ NotEquals,
+ LessThan,
+ LessThanEquals,
+ GreaterThan,
+ GreaterThanEquals,
+
+ If,
+ Else,
+ For,
+ While,
+ Do,
+ Switch,
+ Case,
+ Start,
+ End,
+
+ Public,
+ Class,
+
+ Sizeof,
+ Goto,
+ Return,
+ Break,
+
+ Comment,
+ CommentMultiline,
+
+ Assembly,
+ AssemblyInstruction,
+};
+
+using Value = std::variant<std::monostate, std::string_view, long long, double, uint64_t>;
+
+struct HOLYPARSER_PUBLIC Token
+{
+ TokenType tt;
+ Value v;
+ TextRange range;
+
+ Token();
+ Token(TokenType tt, Value value = std::monostate());
+
+ char const *name();
+ char const *pretty();
+
+ friend bool operator==(Token const &lhs, Token const &rhs);
+ friend bool operator==(Token const &lhs, TokenType const &rhs);
+};
+
+class HOLYPARSER_PUBLIC HolyLexer
+{
+public:
+ HolyLexer(std::string_view input);
+
+ Token next();
+ size_t position() const { return m_pos; }
+
+private:
+ void skip_whitespace();
+ char peek(size_t n = 0);
+ bool peekc(char test, size_t n = 0);
+ void read_char();
+
+ std::string &scan_string(char delim, TextPosition start_pos);
+ Token scan_preproc();
+ Token scan_identifier(bool ignore_keywords = false);
+ Token scan_number();
+ Token scan_comment(bool multiline, bool skip = true);
+
+ std::string_view m_input;
+ char m_ch = '\0';
+ size_t m_read_pos = 0, m_pos = 0;
+ TextPosition m_tpos;
+
+ std::vector<std::string> m_strings;
+};
+
+class HOLYPARSER_PUBLIC ASTNode
+{
+public:
+ virtual std::string_view node_name() { return "ASTNode"sv; };
+ virtual ~ASTNode() { }
+
+ virtual void print(std::string indent = "");
+};
+
+class HOLYPARSER_PUBLIC LiteralNode : public ASTNode
+{
+public:
+ LiteralNode(Value value)
+ : m_value(std::move(value))
+ { }
+
+ virtual std::string_view node_name() override { return "LiteralNode"sv; };
+ virtual void print(std::string indent = "") override;
+
+ auto value() const { return m_value; }
+
+private:
+ Value const m_value;
+};
+
+class HOLYPARSER_PUBLIC NegationNode : public ASTNode
+{
+public:
+ NegationNode(std::shared_ptr<ASTNode> value)
+ : m_value(std::move(value))
+ { }
+
+ virtual std::string_view node_name() override { return "NegationNode"sv; };
+ virtual void print(std::string indent = "") override;
+
+ auto value() const { return m_value; }
+
+private:
+ std::shared_ptr<ASTNode> const m_value;
+};
+
+class HOLYPARSER_PUBLIC BooleanNegationNode : public ASTNode
+{
+public:
+ BooleanNegationNode(std::shared_ptr<ASTNode> value)
+ : m_value(std::move(value))
+ { }
+
+ virtual std::string_view node_name() override { return "BooleanNegationNode"sv; };
+ virtual void print(std::string indent = "") override;
+
+ auto value() const { return m_value; }
+
+private:
+ std::shared_ptr<ASTNode> const m_value;
+};
+
+class HOLYPARSER_PUBLIC FunctionCallNode : public ASTNode
+{
+public:
+ FunctionCallNode(
+ std::string_view name, std::vector<std::shared_ptr<ASTNode>> &arguments)
+ : m_name(std::move(name))
+ , m_arguments(std::move(arguments))
+ { }
+
+ virtual std::string_view node_name() override { return "FunctionCallNode"sv; };
+ virtual void print(std::string indent = "") override;
+
+ auto arguments() { return m_arguments; }
+
+private:
+ std::string_view const m_name;
+ std::vector<std::shared_ptr<ASTNode>> const m_arguments;
+};
+
+class HOLYPARSER_PUBLIC FunctionCallOrIdentifierNode : public ASTNode
+{
+public:
+ FunctionCallOrIdentifierNode(std::string_view name)
+ : m_name(std::move(name))
+ { }
+
+ virtual std::string_view node_name() override
+ {
+ return "FunctionCallOrIdentifierNode"sv;
+ };
+ virtual void print(std::string indent = "") override;
+
+ auto name() const { return m_name; }
+
+private:
+ std::string_view const m_name;
+};
+
+class HOLYPARSER_PUBLIC AccessNode : public ASTNode
+{
+public:
+ AccessNode(std::shared_ptr<ASTNode> left, std::shared_ptr<ASTNode> right)
+ : m_left(std::move(left))
+ , m_right(std::move(right))
+ { }
+
+ virtual std::string_view node_name() override { return "AccessNode"sv; };
+ virtual void print(std::string indent = "") override;
+
+ auto left() const { return m_left; }
+ auto right() const { return m_right; }
+
+private:
+ std::shared_ptr<ASTNode> m_left, m_right;
+};
+
+class HOLYPARSER_PUBLIC OperationNode : public ASTNode
+{
+public:
+ OperationNode(
+ std::shared_ptr<ASTNode> left, std::shared_ptr<ASTNode> right, TokenType operation)
+ : m_operation(operation)
+ , m_left(std::move(left))
+ , m_right(std::move(right))
+ { }
+ virtual std::string_view node_name() override { return "OperationNode"sv; }
+ virtual void print(std::string indent = "") override;
+
+ auto &left() { return m_left; }
+ auto &right() { return m_right; }
+
+ auto opeartion() const { return m_operation; }
+
+private:
+ TokenType const m_operation;
+ std::shared_ptr<ASTNode> const m_left, m_right;
+};
+
+class HOLYPARSER_PUBLIC SetOperationNode : public ASTNode
+{
+public:
+ SetOperationNode(
+ std::shared_ptr<ASTNode> left, std::shared_ptr<ASTNode> right, TokenType operation)
+ : m_operation(operation)
+ , m_left(std::move(left))
+ , m_right(std::move(right))
+ { }
+ virtual std::string_view node_name() override { return "SetOperationNode"sv; }
+ virtual void print(std::string indent = "") override;
+
+ auto &left() { return m_left; }
+ auto &right() { return m_right; }
+
+ auto opeartion() const { return m_operation; }
+
+private:
+ TokenType const m_operation;
+ std::shared_ptr<ASTNode> const m_left, m_right;
+};
+
+using Definition = std::pair<std::shared_ptr<ASTNode>, std::shared_ptr<ASTNode>>;
+class HOLYPARSER_PUBLIC DefinitionsNode : public ASTNode
+{
+public:
+ DefinitionsNode(std::shared_ptr<ASTNode> type, std::vector<Definition> definitions)
+ : m_type(std::move(type))
+ , m_definitions(std::move(definitions))
+ { }
+
+ virtual std::string_view node_name() override { return "DefinitionsNode"sv; }
+ virtual void print(std::string indent = "") override;
+
+ auto type() const { return m_type; }
+ auto definitions() const { return m_definitions; }
+
+private:
+ std::shared_ptr<ASTNode> m_type;
+ std::vector<Definition> m_definitions;
+};
+
+class HOLYPARSER_PUBLIC ProgramNode : public ASTNode
+{
+public:
+ ProgramNode() { }
+ virtual std::string_view node_name() override { return "ProgramNode"sv; }
+ virtual void print(std::string indent = "") override;
+
+ std::vector<std::shared_ptr<ASTNode>> statements;
+};
+
+class HOLYPARSER_PUBLIC IfElseNode : public ASTNode
+{
+public:
+ IfElseNode(std::shared_ptr<ASTNode> condition, std::shared_ptr<ASTNode> _true = nullptr,
+ std::shared_ptr<ASTNode> _false = nullptr)
+ : m_condition(std::move(condition))
+ , m_true(std::move(_true))
+ , m_false(std::move(_false))
+ { }
+ virtual std::string_view node_name() override { return "IfElseNode"sv; }
+ virtual void print(std::string indent = "") override;
+
+private:
+ std::shared_ptr<ASTNode> m_condition, m_true, m_false;
+};
+
+class HOLYPARSER_PUBLIC LoopNode : public ASTNode
+{
+public:
+ LoopNode(std::shared_ptr<ASTNode> condition, std::shared_ptr<ASTNode> _true = nullptr,
+ bool initial_test = true)
+ : m_condition(condition)
+ , m_true(_true)
+ , m_initial_test(initial_test)
+ { }
+
+ virtual std::string_view node_name() override { return "LoopNode"sv; }
+ virtual void print(std::string indent = "") override;
+
+ auto condition() const { return m_condition; }
+ auto true_node() const { return m_true; }
+ auto initial_test() const { return m_initial_test; }
+
+protected:
+ std::shared_ptr<ASTNode> m_condition, m_true;
+ bool m_initial_test;
+};
+
+class HOLYPARSER_PUBLIC WhileNode : public LoopNode
+{
+public:
+ WhileNode(std::shared_ptr<ASTNode> condition, std::shared_ptr<ASTNode> _true = nullptr,
+ bool initial_test = true)
+ : LoopNode(condition, _true, initial_test)
+ { }
+ virtual std::string_view node_name() override { return "WhileNode"sv; }
+};
+
+class HOLYPARSER_PUBLIC ForNode : public LoopNode
+{
+public:
+ ForNode(std::shared_ptr<ASTNode> set, std::shared_ptr<ASTNode> condition,
+ std::shared_ptr<ASTNode> advance, std::shared_ptr<ASTNode> _true = nullptr,
+ bool initial_test = true)
+ : LoopNode(condition, _true, initial_test)
+ , m_set(std::move(set))
+ , m_advance(std::move(advance))
+ { }
+
+ virtual std::string_view node_name() override { return "ForNode"sv; }
+ virtual void print(std::string indent = "") override;
+
+protected:
+ std::shared_ptr<ASTNode> m_set, m_advance;
+};
+
+class HOLYPARSER_PUBLIC PreExeNode : public ASTNode
+{
+public:
+ PreExeNode(std::shared_ptr<ProgramNode> program)
+ : m_program(std::move(program))
+ { }
+
+ virtual std::string_view node_name() override { return "PreExeNode"sv; }
+ virtual void print(std::string indent = "") override;
+
+private:
+ std::shared_ptr<ProgramNode> m_program;
+};
+
+class HOLYPARSER_PUBLIC PreIfNode : public ASTNode
+{
+public:
+ PreIfNode(std::shared_ptr<ASTNode> condition = nullptr)
+ : m_condition(std::move(condition))
+ { }
+
+ virtual std::string_view node_name() override { return "PreIfNode"sv; }
+ virtual void print(std::string indent = "") override;
+
+private:
+ std::shared_ptr<ASTNode> m_condition;
+};
+
+class HOLYPARSER_PUBLIC PreIfDefNode : public ASTNode
+{
+public:
+ PreIfDefNode(std::shared_ptr<FunctionCallOrIdentifierNode> name = nullptr)
+ : m_name(std::move(name))
+ { }
+
+ virtual std::string_view node_name() override { return "PreIfDefNode"sv; }
+ virtual void print(std::string indent = "") override;
+
+private:
+ std::shared_ptr<FunctionCallOrIdentifierNode> m_name;
+};
+
+class HOLYPARSER_PUBLIC PreIfNDefNode : public ASTNode
+{
+public:
+ PreIfNDefNode(std::shared_ptr<FunctionCallOrIdentifierNode> name = nullptr)
+ : m_name(std::move(name))
+ { }
+
+ virtual std::string_view node_name() override { return "PreIfNDefNode"sv; }
+ virtual void print(std::string indent = "") override;
+
+private:
+ std::shared_ptr<FunctionCallOrIdentifierNode> m_name;
+};
+
+class HOLYPARSER_PUBLIC PreEndIfNode : public ASTNode
+{
+public:
+ PreEndIfNode() { }
+ virtual std::string_view node_name() override { return "PreEndIfNode"sv; }
+};
+
+class HOLYPARSER_PUBLIC PreDefineNode : public ASTNode
+{
+public:
+ PreDefineNode(std::string_view str = ""sv)
+ : m_str(str)
+ { }
+ virtual std::string_view node_name() override { return "PreDefineNode"sv; }
+ virtual void print(std::string indent = "") override;
+
+private:
+ std::string_view m_str;
+};
+
+class HOLYPARSER_PUBLIC HolyParser
+{
+public:
+ HolyParser(HolyLexer &lexer);
+
+ void next();
+ Token prev_next();
+ bool accept(TokenType tt);
+ bool accept(Token tok);
+ bool expect(TokenType tt);
+ bool expect(Token tok);
+
+ std::shared_ptr<ASTNode> const parse() { return parse_program(); }
+ std::shared_ptr<ASTNode> const parse_expression() { return parse_set(); }
+
+protected:
+ // EXPRESSIONS SO MUCH CODE WOW!!!!
+ std::vector<std::shared_ptr<ASTNode>> const parse_expression_list(TokenType end);
+ std::shared_ptr<FunctionCallNode> const parse_function_call();
+ std::shared_ptr<ASTNode> const parse_factor();
+ std::shared_ptr<ASTNode> const parse_dot_access();
+ std::shared_ptr<ASTNode> const parse_bit_shift_pow();
+ std::shared_ptr<ASTNode> const parse_term();
+ std::shared_ptr<ASTNode> const parse_bitwise_and();
+ std::shared_ptr<ASTNode> const parse_bitwise_xor();
+ std::shared_ptr<ASTNode> const parse_bitwise_or();
+ std::shared_ptr<ASTNode> const parse_math_expr();
+ std::shared_ptr<ASTNode> const parse_inequality();
+ std::shared_ptr<ASTNode> const parse_equality();
+ std::shared_ptr<ASTNode> const parse_and();
+ std::shared_ptr<ASTNode> const parse_xor();
+ std::shared_ptr<ASTNode> const parse_or();
+ std::shared_ptr<ASTNode> const parse_set();
+
+ // Statements and other things...
+ std::shared_ptr<ASTNode> const parse_var_def();
+ std::shared_ptr<ASTNode> const parse_type();
+ std::shared_ptr<WhileNode> const parse_while();
+ std::shared_ptr<ForNode> const parse_for();
+ std::shared_ptr<WhileNode> const parse_do();
+ std::shared_ptr<IfElseNode> const parse_if_else();
+ std::shared_ptr<ASTNode> const parse_statement();
+ std::shared_ptr<ProgramNode> const parse_program(TokenType end = TokenType::EndOfFile);
+
+private:
+ // Two look-aheads.
+ Token m_tok, m_next, m_third;
+ bool skip_newline = true, in_class_or_union = false, decl_allowed = true;
+
+ HolyLexer &m_lexer;
+};
+
+} // namespace holyparser
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..0915d92
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,73 @@
+project('HolyParser', 'cpp',
+ version : '0.1',
+ default_options : ['warning_level=3', 'cpp_std=gnu++20'])
+
+# These arguments are only used to build the shared library
+# not the executables that use the library.
+lib_args = ['-DBUILDING_HOLYPARSER']
+
+perfect_hash_template = configure_file(input: 'src/holyasm.gperf',
+ output: 'holyasm.hpp',
+ command: ['gperf', '@INPUT@'],
+ capture: true,
+ )
+
+perfect_hash = custom_target('perfect_hash',
+ input: 'src/holyasm.gperf',
+ output: 'holyasm.hpp',
+ command: ['gperf', '@INPUT@', '--output-file', '@OUTPUT@'],
+ build_by_default: true,
+ )
+
+src = [
+ perfect_hash_template,
+ 'src/holylexer.cpp',
+ 'src/holyparser.cpp',
+ ]
+
+shlib = shared_library('holyparser', src,
+ install : true,
+ cpp_args : lib_args,
+ gnu_symbol_visibility : 'hidden',
+ dependencies : [
+ subproject('fmt').get_variable('fmt_dep'),
+ ],
+)
+
+executable('test_holyparser', 'test_holyparser.cpp',
+ include_directories : include_directories('.'),
+ dependencies : [
+ subproject('fmt').get_variable('fmt_dep'),
+ ],
+ link_with : shlib,
+ )
+
+executable('rpl', 'rpl.cpp',
+ include_directories : include_directories('.'),
+ dependencies : [
+ subproject('fmt').get_variable('fmt_dep'),
+ dependency('readline'),
+ ],
+ link_with : shlib,
+ )
+
+# Make this library usable as a Meson subproject.
+holyparser_dep = declare_dependency(
+ include_directories: include_directories('.'),
+ link_with : shlib,
+ )
+
+# Make this library usable from the system's
+# package manager.
+install_headers('holyparser.hpp', subdir : 'holyparser')
+
+pkg_mod = import('pkgconfig')
+pkg_mod.generate(
+ name : 'HolyParser',
+ filebase : 'holyparser',
+ description : 'A parser for HolyC',
+ subdirs : 'holyparser',
+ libraries : shlib,
+ version : '0.1',
+ )
+
diff --git a/rpl.cpp b/rpl.cpp
new file mode 100644
index 0000000..4284c4d
--- /dev/null
+++ b/rpl.cpp
@@ -0,0 +1,37 @@
+#include <holyparser.hpp>
+
+#include <fmt/std.h>
+#include <readline/readline.h>
+
+#include <iostream>
+#include <variant>
+
+int main(void)
+{
+ char *buf;
+ while ((buf = readline("> ")) != nullptr) {
+ holyparser::HolyLexer lexer(buf);
+ // auto tok = lexer.next();
+ // while (tok != holyparser::TokenType::EndOfFile) {
+ // fmt::print("{} at {}\n", tok.pretty(), tok.range.pretty());
+ // tok = lexer.next();
+ // }
+
+ lexer = holyparser::HolyLexer(buf);
+ auto parser = holyparser::HolyParser(lexer);
+ auto root = parser.parse();
+ if (holyparser::messages.size() > 0) {
+ fmt::print("Issues found: {}\n", holyparser::messages.size());
+ for (auto issue : holyparser::messages) {
+ if (issue.is_error)
+ fmt::print(" - Error: ");
+ else
+ fmt::print(" - Warning: ");
+ fmt::print("`{}` at {}\n", issue.msg, issue.range.pretty());
+ }
+ }
+
+ root->print();
+ holyparser::messages.clear();
+ }
+}
diff --git a/src/holyasm.gperf b/src/holyasm.gperf
new file mode 100644
index 0000000..0c7010c
--- /dev/null
+++ b/src/holyasm.gperf
@@ -0,0 +1,385 @@
+%includes
+%enum
+%pic
+%readonly-tables
+%compare-strncmp
+
+%language=C++
+%define class-name AsmInsHash
+
+%%
+MOV_RAX_CR4
+MOV_CR4_RAX
+MOV_RAX_CR3
+MOV_CR3_RAX
+MOV_RAX_CR2
+MOV_CR2_RAX
+MOV_RAX_CR0
+MOV_CR0_RAX
+MOV_EAX_CR4
+MOV_CR4_EAX
+MOV_EAX_CR3
+MOV_CR3_EAX
+MOV_EAX_CR2
+MOV_CR2_EAX
+MOV_EAX_CR0
+MOV_CR0_EAX
+PAUSE
+RDMSR
+RDTSC
+WRMSR
+CPUID
+INVLPG
+CLFLUSH
+WBINVD
+FXRSTOR
+FXSAVE
+FLDCW
+FSTCW
+FNINIT
+FINIT
+FXAM
+FTST
+FXCH
+FLDZ
+FLDLN2
+FLDLG2
+FLDPI
+FLDL2E
+FLDL2T
+FLD1
+FXTRACT
+FSCALE
+FRNDINT
+FFREE
+FINCSTP
+FDECSTP
+FSTSW
+FNCLEX
+FCLEX
+FCOMI
+FCOMIP
+FSUBR
+FSUBRP
+FSUB
+FSUBP
+FADD
+FADDP
+FPREM
+FDIVR
+FDIVRP
+FDIV
+FDIVP
+FIMUL
+FMUL
+FMULP
+FSQRT
+FPATAN
+FPTAN
+FCOS
+FSIN
+FCHS
+FABS
+F2XM1
+FYL2XP1
+FYL2X
+FSAVE
+FRSTOR
+FST
+FSTP
+FLD
+FISTTP
+FISTP
+FILD
+SAR1
+SAR
+SHR1
+SHR
+SAL1
+SHL1
+SAL
+SHL
+RCR1
+RCR
+RCL1
+RCL
+ROR1
+ROR
+ROL1
+ROL
+XLATB
+XADD
+FWAIT
+WAIT
+VERW
+VERR
+STR
+STOSQ
+STOSD
+STOSW
+STOSB
+STI
+STD
+STC
+SHRD
+SHLD
+SETNLE
+SETG
+SETNG
+SETLE
+SETNL
+SETGE
+SETNGE
+SETL
+SETPO
+SETNP
+SETPE
+SETP
+SETNS
+SETS
+SETNBE
+SETA
+SETNA
+SETBE
+SETNZ
+SETNE
+SETZ
+SETE
+SETNB
+SETNC
+SETAE
+SETNAE
+SETC
+SETB
+SETNO
+SETO
+SEGGS
+SEGFS
+SEGES
+SEGDS
+SEGSS
+SEGCS
+SCASQ
+SCASD
+SCASW
+SCASB
+SAHF
+RSM
+REX2
+REX
+RETF1
+RETF
+RET1
+RET
+REPNE_SCASQ
+REPNE_SCASD
+REPNE_SCASW
+REPNE_SCASB
+REPNE_CMPSQ
+REPNE_CMPSD
+REPNE_CMPSW
+REPNE_CMPSB
+REPE_SCASQ
+REPE_SCASD
+REPE_SCASW
+REPE_SCASB
+REPE_CMPSQ
+REPE_CMPSD
+REPE_CMPSW
+REPE_CMPSB
+REP_STOSQ
+REP_STOSD
+REP_STOSW
+REP_STOSB
+REP_LODSQ
+REP_LODSD
+REP_LODSW
+REP_LODSB
+REP_OUTSD
+REP_OUTSW
+REP_OUTSB
+REP_MOVSQ
+REP_MOVSD
+REP_MOVSW
+REP_MOVSB
+REP_INSD
+REP_INSW
+REP_INSB
+OUTSD
+OUTSW
+OUTSB
+OUT
+MOVZX
+MOVSXD
+MOVSX
+MOVSQ
+MOVSD
+MOVSW
+MOVSB
+LTR
+LSL
+LOOPNZ
+LOOPNE
+LOOPZ
+LOOPE
+LOOP
+LODSQ
+LODSD
+LODSW
+LODSB
+LOCK
+SMSW
+LMSW
+SLDT
+LLDT
+SIDT
+LIDT
+SGDT
+LGDT
+LEAVE
+LEA
+LAR
+LAHF
+IRET
+INVD
+INT
+BPT
+INT3
+INTO
+INSD
+INSW
+INSB
+INS
+IN
+HLT
+ENTER
+DAS
+DAA
+CHPXCHG8B
+CMPXCHG
+CMPSQ
+CMPSD
+CMPSW
+CMPSB
+CMC
+CLTS
+CLI
+CLD
+CLC
+CQO
+CDQ
+CWD
+CDQE
+CWDE
+CBW
+BTS
+BTR
+BTC
+BT
+BSWAP
+BSR
+BSF
+BOUND
+ARPL
+AAS
+AAM
+AAD
+IDIV
+DIV
+IMUL2
+IMUL
+MUL
+NEG
+NOT
+DEC
+INC
+JRCXZ
+JECXZ
+JCXZ
+JNLE
+JG
+JNG
+JLE
+JNL
+JGE
+JNGE
+JL
+JPO
+JNP
+JPE
+JP
+JNS
+JS
+JNBE
+JA
+JNA
+JBE
+JNZ
+JNE
+JZ
+JE
+JNC
+JNB
+JAE
+JNAE
+JC
+JB
+JNO
+JO
+JMP
+CALL
+CMOVNLE
+CMOVG
+CMOVNG
+CMOVLE
+CMOVNL
+CMOVGE
+CMOVNGE
+CMOVL
+CMOVPO
+CMOVNP
+CMOVPE
+CMOVP
+CMOVNS
+CMOVS
+CMOVNBE
+CMOVA
+CMOVNA
+CMOVBE
+CMOVNZ
+CMOVNE
+CMOVZ
+AAA
+CMOVE
+CMOVNC
+CMOVNB
+CMOVAE
+CMOVNAE
+CMOVC
+CMOVB
+CMOVNO
+CMOVO
+XOR
+XCHG
+NOP2
+NOP
+TEST
+SUB
+SBB
+OR
+CMP
+AND
+ADD
+ADC
+MOV
+POPFD
+POPFW
+POPAD
+POPAW
+POP
+PUSHFD
+PUSHFW
+PUSHAD
+PUSHAW
+PUSH
+%%
diff --git a/src/holylexer.cpp b/src/holylexer.cpp
new file mode 100644
index 0000000..2fd6f00
--- /dev/null
+++ b/src/holylexer.cpp
@@ -0,0 +1,492 @@
+#include <holyparser.hpp>
+
+#include <charconv>
+#include <cstring>
+#include <set>
+#include <sstream>
+#include <variant>
+
+#include <fmt/std.h>
+
+#pragma GCC diagnostic push
+#include <holyasm.hpp>
+#pragma GCC diagnostic pop
+
+namespace holyparser
+{
+
+using namespace std::literals;
+
+bool is_asm(std::string_view &ident)
+{
+ return AsmInsHash::in_word_set(ident.data(), ident.length());
+}
+
+std::string TextPosition::pretty()
+{
+ return fmt::format("({}, {})", col, row);
+}
+
+std::string TextRange::pretty()
+{
+ return fmt::format("{} -> {}", start.pretty(), end.pretty());
+}
+
+Token::Token()
+ : tt(TokenType::Invalid)
+{ }
+
+Token::Token(TokenType tt, Value value)
+ : tt(tt)
+ , v(value)
+{ }
+
+char const *Token::name()
+{
+ // clang-format off
+ switch (tt) {
+ case TokenType::Invalid: return "Invalid";
+ case TokenType::EndOfFile: return "EndOfFile";
+ case TokenType::NewLine: return "NewLine";
+ case TokenType::Identifier: return "Identifier";
+ case TokenType::IntegerLiteral: return "IntegerLiteral";
+ case TokenType::FloatLiteral: return "FloatLiteral";
+ case TokenType::StringLiteral: return "StringLiteral";
+ case TokenType::CharLiteral: return "CharLiteral";
+ case TokenType::Comma: return "Comma";
+ case TokenType::Dot: return "Dot";
+ case TokenType::Colon: return "Colon";
+ case TokenType::Semicolon: return "Semicolon";
+ case TokenType::LParen: return "LParen";
+ case TokenType::RParen: return "RParen";
+ case TokenType::LBracket: return "LBracket";
+ case TokenType::RBracket: return "RBracket";
+ case TokenType::LSquirly: return "LSquirly";
+ case TokenType::RSquirly: return "RSquirly";
+ case TokenType::Range: return "Range";
+ case TokenType::Add: return "Add";
+ case TokenType::Subtract: return "Subtract";
+ case TokenType::Multiply: return "Multiply";
+ case TokenType::Divide: return "Divide";
+ case TokenType::Modulo: return "Modulo";
+ case TokenType::Pow: return "Pow";
+ case TokenType::LeftBitShift: return "LeftBitShift";
+ case TokenType::RightBitShift: return "RightBitShift";
+ case TokenType::BitwiseAnd: return "BitwiseAnd";
+ case TokenType::BitwiseOr: return "BitwiseOr";
+ case TokenType::BitwiseXOR: return "BitwiseXOR";
+ case TokenType::OnesComplement: return "OnesComplement";
+ case TokenType::AddSet: return "AddSet";
+ case TokenType::SubtractSet: return "SubtractSet";
+ case TokenType::MultiplySet: return "MultiplySet";
+ case TokenType::DivideSet: return "DivideSet";
+ case TokenType::ModuloSet: return "ModuloSet";
+ case TokenType::LeftBitShiftSet: return "LeftBitShiftSet";
+ case TokenType::RightBitShiftSet: return "RightBitShiftSet";
+ case TokenType::BitwiseAndSet: return "BitwiseAndSet";
+ case TokenType::BitwiseOrSet: return "BitwiseOrSet";
+ case TokenType::BitwiseXORSet: return "BitwiseXORSet";
+ case TokenType::Increment: return "Increment";
+ case TokenType::Decrement: return "Decrement";
+ case TokenType::Set: return "Set";
+ case TokenType::Not: return "Not";
+ case TokenType::And: return "And";
+ case TokenType::Or: return "Or";
+ case TokenType::XOR: return "XOR";
+ case TokenType::Equals: return "Equals";
+ case TokenType::NotEquals: return "NotEquals";
+ case TokenType::LessThan: return "LessThan";
+ case TokenType::LessThanEquals: return "LessThanEquals";
+ case TokenType::GreaterThan: return "GreaterThan";
+ case TokenType::GreaterThanEquals: return "GreaterThanEquals";
+ case TokenType::If: return "If";
+ case TokenType::Else: return "Else";
+ case TokenType::For: return "For";
+ case TokenType::While: return "While";
+ case TokenType::Do: return "Do";
+ case TokenType::Switch: return "Switch";
+ case TokenType::Case: return "Case";
+ case TokenType::Start: return "Start";
+ case TokenType::End: return "End";
+ case TokenType::Public: return "Public";
+ case TokenType::Class: return "Class";
+ case TokenType::Preprocessor: return "Preprocessor";
+ case TokenType::Sizeof: return "Sizeof";
+ case TokenType::Goto: return "Goto";
+ case TokenType::Return: return "Return";
+ case TokenType::Break: return "Break";
+ case TokenType::Comment: return "Comment";
+ case TokenType::CommentMultiline: return "CommentMultiline";
+ case TokenType::Assembly: return "Assembly";
+ case TokenType::AssemblyInstruction: return "AssemblyInstruction";
+ }
+ // clang-format on
+ throw "Invalid token";
+}
+
+char const *Token::pretty()
+{
+ std::stringstream ss;
+ ss << name();
+ if (!std::holds_alternative<std::monostate>(v)) ss << fmt::format("({})", v);
+ return strdup(ss.str().c_str());
+}
+
+bool HOLYPARSER_PUBLIC operator==(Token const &lhs, Token const &rhs)
+{
+ return lhs.v == rhs.v && lhs.tt == rhs.tt;
+}
+
+bool HOLYPARSER_PUBLIC operator==(Token const &lhs, TokenType const &rhs)
+{
+ return lhs.tt == rhs;
+}
+
+HolyLexer::HolyLexer(std::string_view input)
+ : m_input(input)
+{
+ read_char();
+ m_tpos.col = 1;
+ m_tpos.row = 1;
+}
+
+Token HolyLexer::next()
+{
+ Token ret(TokenType::Invalid);
+ skip_whitespace();
+
+ bool should_read = true;
+
+ auto pos = m_tpos;
+ ret.range.start = pos;
+ ret.range.end = m_tpos;
+
+ switch (m_ch) {
+ case '\n': ret.tt = TokenType::NewLine; break;
+ case '.':
+ ret.tt = TokenType::Dot;
+ if (peek() == '.' && peek(1) == '.') {
+ read_char();
+ read_char();
+ ret.tt = TokenType::Range;
+ }
+ break;
+ case ',': ret.tt = TokenType::Comma; break;
+ case ':': ret.tt = TokenType::Colon; break;
+ case ';': ret.tt = TokenType::Semicolon; break;
+ case '(': ret.tt = TokenType::LParen; break;
+ case ')': ret.tt = TokenType::RParen; break;
+ case '[': ret.tt = TokenType::LBracket; break;
+ case ']': ret.tt = TokenType::RBracket; break;
+ case '{': ret.tt = TokenType::LSquirly; break;
+ case '}': ret.tt = TokenType::RSquirly; break;
+ case '+':
+ ret.tt = TokenType::Add;
+ if (peekc('='))
+ ret.tt = TokenType::AddSet;
+ else if (peekc('+'))
+ ret.tt = TokenType::Increment;
+ break;
+ case '-':
+ ret.tt = TokenType::Subtract;
+ if (peekc('='))
+ ret.tt = TokenType::SubtractSet;
+ else if (peekc('-'))
+ ret.tt = TokenType::Decrement;
+ break;
+ case '*':
+ ret.tt = TokenType::Multiply;
+ if (peekc('=')) ret.tt = TokenType::MultiplySet;
+ break;
+ case '/':
+ ret.tt = TokenType::Divide;
+ if (peekc('='))
+ ret.tt = TokenType::DivideSet;
+ else if (peek() == '*') {
+ ret = scan_comment(true);
+ should_read = false;
+ } else if (peek() == '/') {
+ ret = scan_comment(false);
+ should_read = false;
+ }
+ break;
+ case '%':
+ ret.tt = TokenType::Modulo;
+ if (peekc('=')) ret.tt = TokenType::ModuloSet;
+ break;
+ case '=':
+ ret.tt = TokenType::Set;
+ if (peekc('=')) ret.tt = TokenType::Equals;
+ break;
+ case '!':
+ ret.tt = TokenType::Not;
+ if (peekc('=')) ret.tt = TokenType::NotEquals;
+ break;
+ case '<':
+ ret.tt = TokenType::LessThan;
+ if (peekc('='))
+ ret.tt = TokenType::LessThanEquals;
+ else if (peekc('<')) {
+ ret.tt = TokenType::LeftBitShift;
+ if (peekc('=')) { ret.tt = TokenType::LeftBitShiftSet; }
+ }
+ break;
+ case '>':
+ ret.tt = TokenType::GreaterThan;
+ if (peekc('='))
+ ret.tt = TokenType::GreaterThanEquals;
+ else if (peekc('>')) {
+ ret.tt = TokenType::RightBitShift;
+ if (peekc('=')) { ret.tt = TokenType::RightBitShiftSet; }
+ }
+ break;
+ case '&':
+ ret.tt = TokenType::BitwiseAnd;
+ if (peekc('&'))
+ ret.tt = TokenType::And;
+ else if (peekc('='))
+ ret.tt = TokenType::BitwiseAndSet;
+ break;
+ case '|':
+ ret.tt = TokenType::BitwiseOr;
+ if (peekc('|'))
+ ret.tt = TokenType::Or;
+ else if (peekc('='))
+ ret.tt = TokenType::BitwiseOrSet;
+ break;
+ case '^':
+ ret.tt = TokenType::BitwiseXOR;
+ if (peekc('='))
+ ret.tt = TokenType::BitwiseXORSet;
+ else if (peekc('^'))
+ ret.tt = TokenType::XOR;
+ break;
+ case '~': ret.tt = TokenType::OnesComplement; break;
+ case '`': ret.tt = TokenType::Pow; break;
+ case '#':
+ ret = scan_preproc();
+ should_read = false;
+ break;
+ case '"':
+ ret.tt = TokenType::StringLiteral;
+ ret.v = scan_string('"', ret.range.start);
+ break;
+ case '\'':
+ ret.tt = TokenType::CharLiteral;
+ ret.v = scan_string('\'', ret.range.start);
+ break;
+ case '$':
+ read_char();
+ while (m_ch != '$')
+ read_char();
+ read_char();
+ return next();
+ case '\0': ret.tt = TokenType::EndOfFile; break;
+ }
+
+ if (isdigit(m_ch)) {
+ ret = scan_number();
+ should_read = false;
+ }
+ if (isalpha(m_ch)) {
+ ret = scan_identifier();
+ should_read = false;
+ }
+
+ ret.range.start = pos;
+ ret.range.end = m_tpos;
+
+ if (ret.tt == TokenType::IntegerLiteral || ret.tt == TokenType::FloatLiteral
+ || ret.tt == TokenType::Preprocessor || ret.tt == TokenType::CommentMultiline
+ || ret.tt == TokenType::Comment || ret.tt == TokenType::Identifier
+ || ret.tt == TokenType::If || ret.tt == TokenType::Else || ret.tt == TokenType::For
+ || ret.tt == TokenType::While || ret.tt == TokenType::Do
+ || ret.tt == TokenType::Sizeof || ret.tt == TokenType::Switch
+ || ret.tt == TokenType::Case || ret.tt == TokenType::Start
+ || ret.tt == TokenType::End || ret.tt == TokenType::Goto
+ || ret.tt == TokenType::Public || ret.tt == TokenType::Return
+ || ret.tt == TokenType::Break || ret.tt == TokenType::Assembly
+ || ret.tt == TokenType::Class || ret.tt == TokenType::AssemblyInstruction)
+ ret.range.end.col--;
+
+ if (should_read) read_char();
+ return ret;
+}
+
+std::string &HolyLexer::scan_string(char delim, TextPosition start_pos)
+{
+ read_char();
+ std::string final;
+ while (m_ch != delim && m_ch != '\0') {
+ char ch = m_ch;
+ if (ch == '\\') {
+ read_char();
+ ch = m_ch;
+ switch (m_ch) {
+ case '0': ch = '\0'; break;
+ case 'd': ch = '$'; break;
+ case 'n': ch = '\n'; break;
+ case 'r': ch = '\r'; break;
+ case 't': ch = '\t'; break;
+ }
+ }
+ final.push_back(ch);
+ read_char();
+ }
+ if (delim == '\'' && final.length() > 8)
+ messages.push_back(Error("You cannot have more than 8 characters in a U64.",
+ TextRange { start_pos, m_tpos }));
+ m_strings.push_back(final);
+ return m_strings.at(m_strings.size() - 1);
+}
+
+Token HolyLexer::scan_preproc()
+{
+ read_char();
+ auto identifier = scan_identifier(true);
+ identifier.tt = TokenType::Preprocessor;
+ if (std::get<std::string_view>(identifier.v) == "define") {
+ std::string new_str(std::get<std::string_view>(identifier.v));
+ while (peek() != '\n' && peek() != '\0') {
+ new_str.push_back(m_ch);
+ read_char();
+ }
+ new_str.push_back(m_ch);
+ }
+ return identifier;
+}
+
+Token HolyLexer::scan_identifier(bool ignore_keywords)
+{
+ size_t start_pos = m_pos;
+ while (m_ch == '_' || std::isalnum(m_ch))
+ read_char();
+
+ std::string_view slice = m_input.substr(start_pos, m_pos - start_pos);
+ if (ignore_keywords == false) {
+ if (slice == "if")
+ return Token(TokenType::If);
+ else if (slice == "else")
+ return Token(TokenType::Else);
+ else if (slice == "for")
+ return Token(TokenType::For);
+ else if (slice == "while")
+ return Token(TokenType::While);
+ else if (slice == "do")
+ return Token(TokenType::Do);
+ else if (slice == "sizeof")
+ return Token(TokenType::Sizeof);
+ else if (slice == "switch")
+ return Token(TokenType::Switch);
+ else if (slice == "case")
+ return Token(TokenType::Case);
+ else if (slice == "start")
+ return Token(TokenType::Start);
+ else if (slice == "end")
+ return Token(TokenType::End);
+ else if (slice == "goto")
+ return Token(TokenType::Goto);
+ else if (slice == "public")
+ return Token(TokenType::Public);
+ else if (slice == "return")
+ return Token(TokenType::Return);
+ else if (slice == "break")
+ return Token(TokenType::Break);
+ else if (slice == "asm")
+ return Token(TokenType::Assembly);
+ else if (slice == "class")
+ return Token(TokenType::Class);
+ else if (is_asm(slice)) {
+ std::string str(slice);
+ str.append(std::get<std::string_view>(scan_comment(false, false).v));
+ m_strings.push_back(str);
+ return Token(TokenType::AssemblyInstruction, slice);
+ }
+ }
+
+ return Token(TokenType::Identifier, slice);
+}
+
+Token HolyLexer::scan_number()
+{
+ size_t start_pos = m_pos;
+ while (m_ch == '.' || std::isdigit(m_ch))
+ read_char();
+
+ std::string_view slice = m_input.substr(start_pos, m_pos - start_pos);
+
+ Token ret(TokenType::IntegerLiteral);
+ if (slice.find('.') != std::string::npos) {
+ ret.tt = TokenType::FloatLiteral;
+ double v;
+ std::from_chars(slice.data(), slice.data() + slice.size(), v);
+ ret.v = v;
+ } else {
+ long long v;
+ std::from_chars(slice.data(), slice.data() + slice.size(), v);
+ ret.v = v;
+ }
+
+ return ret;
+}
+
+Token HolyLexer::scan_comment(bool multiline, bool skip)
+{
+ if (skip) {
+ read_char(); // first slash
+ read_char(); // second slash or asterisk
+ }
+
+ size_t start_pos = m_pos;
+
+ while (m_ch) {
+ if (multiline) {
+ if (m_ch == '*' && peek() == '/') break;
+ } else if (m_ch == '\n' || m_ch == '\r')
+ break;
+ read_char();
+ }
+ size_t end_pos = m_pos;
+ if (multiline) {
+ read_char();
+ read_char();
+ return Token(
+ TokenType::CommentMultiline, m_input.substr(start_pos, end_pos - start_pos));
+ }
+
+ return Token(TokenType::Comment, m_input.substr(start_pos, end_pos - start_pos));
+}
+
+char HolyLexer::peek(size_t n)
+{
+ return (m_read_pos + n) >= m_input.length() ? '\0' : m_input.at(m_read_pos + n);
+}
+
+bool HolyLexer::peekc(char test, size_t n)
+{
+ if (peek(n) == test) {
+ read_char();
+ return true;
+ }
+ return false;
+}
+
+void HolyLexer::read_char()
+{
+ m_ch = peek();
+ m_pos = m_read_pos++;
+
+ m_tpos.col++;
+ if (m_ch == '\n') {
+ m_tpos.row++;
+ m_tpos.col = 1;
+ }
+}
+
+void HolyLexer::skip_whitespace()
+{
+ while (isspace(m_ch) && m_ch != '\n')
+ read_char();
+}
+
+}
diff --git a/src/holyparser.cpp b/src/holyparser.cpp
new file mode 100644
index 0000000..9741537
--- /dev/null
+++ b/src/holyparser.cpp
@@ -0,0 +1,796 @@
+#include "fmt/core.h"
+#include <holyparser.hpp>
+
+#include <fmt/std.h>
+#include <memory>
+#include <string_view>
+
+#define INDENT " "
+
+namespace holyparser
+{
+
+MessageList messages;
+
+Message Error(std::string msg, TextRange range)
+{
+ return { .is_error = true, .range = range, .msg = msg };
+}
+
+Message Warning(std::string msg, TextRange range)
+{
+ return { .is_error = false, .range = range, .msg = msg };
+}
+
+bool MessageList::contains_errors()
+{
+ for (auto i : *this)
+ if (i.is_error) fmt::print("Error: {} {}\n", i.msg, i.range.pretty());
+ for (auto i : *this)
+ if (i.is_error) return true;
+ return false;
+}
+
+void ASTNode::print(std::string indent)
+{
+ fmt::print("{} {}\n", indent, node_name());
+}
+
+void LiteralNode::print(std::string indent)
+{
+ fmt::print("{} {}: {}\n", indent, node_name(), m_value);
+}
+
+void NegationNode::print(std::string indent)
+{
+ fmt::print("{} {}\n", indent, node_name());
+ if (m_value != nullptr) m_value->print(indent + INDENT);
+}
+
+void BooleanNegationNode::print(std::string indent)
+{
+ fmt::print("{} {}\n", indent, node_name());
+ if (m_value != nullptr) m_value->print(indent + INDENT);
+}
+
+void FunctionCallNode::print(std::string indent)
+{
+ fmt::print("{} {}: \"{}\", {} arguments. If any:\n", indent, node_name(), m_name,
+ m_arguments.size());
+ for (auto i : m_arguments) {
+ if (i == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ i->print(indent + INDENT);
+ }
+}
+
+void FunctionCallOrIdentifierNode::print(std::string indent)
+{
+ fmt::print("{} {}: {}\n", indent, node_name(), m_name);
+}
+
+void AccessNode::print(std::string indent)
+{
+ fmt::print("{} {}\n", indent, node_name());
+ if (m_left == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_left->print(indent + INDENT);
+
+ if (m_right == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_right->print(indent + INDENT);
+}
+
+void OperationNode::print(std::string indent)
+{
+ fmt::print("{} {}: {}\n", indent, node_name(), Token(m_operation).name());
+ if (m_left == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_left->print(indent + INDENT);
+
+ if (m_right == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_right->print(indent + INDENT);
+}
+
+void SetOperationNode::print(std::string indent)
+{
+ fmt::print("{} {}: {}\n", indent, node_name(), Token(m_operation).name());
+ if (m_left == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_left->print(indent + INDENT);
+
+ if (m_right == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_right->print(indent + INDENT);
+}
+
+void DefinitionsNode::print(std::string indent)
+{
+ fmt::print(
+ "{} {}: {} definitions. If any:\n", indent, node_name(), m_definitions.size());
+
+ if (m_type == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_type->print(indent + INDENT);
+
+ for (auto definition : m_definitions) {
+ if (definition.first == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT + INDENT);
+ else
+ definition.first->print(indent + INDENT + INDENT);
+
+ if (definition.second == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT + INDENT + INDENT);
+ else
+ definition.second->print(indent + INDENT + INDENT + INDENT);
+ }
+}
+
+void ProgramNode::print(std::string indent)
+{
+ fmt::print("{} {}: {} statements. If any:\n", indent, node_name(), statements.size());
+
+ for (auto statement : statements) {
+ if (statement == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ statement->print(indent + INDENT);
+ }
+}
+
+void IfElseNode::print(std::string indent)
+{
+ fmt::print("{} {}\n", indent, node_name());
+ if (m_condition == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_condition->print(indent + INDENT);
+
+ if (m_true == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_true->print(indent + INDENT);
+
+ if (m_false == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_false->print(indent + INDENT);
+}
+
+void LoopNode::print(std::string indent)
+{
+ fmt::print("{} {}, initial test: {}\n", indent, node_name(), m_initial_test);
+ if (m_condition == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_condition->print(indent + INDENT);
+
+ if (m_true == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_true->print(indent + INDENT);
+}
+
+void ForNode::print(std::string indent)
+{
+ fmt::print("{} {}, initial test: {}\n", indent, node_name(), m_initial_test);
+ if (m_set == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_set->print(indent + INDENT);
+
+ if (m_condition == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_condition->print(indent + INDENT);
+
+ if (m_advance == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_advance->print(indent + INDENT);
+
+ if (m_true == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_true->print(indent + INDENT);
+}
+
+void PreExeNode::print(std::string indent)
+{
+ fmt::print("{} {}\n", indent, node_name());
+
+ if (m_program == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_program->print(indent + INDENT);
+}
+
+void PreIfNode::print(std::string indent)
+{
+ fmt::print("{} {}\n", indent, node_name());
+
+ if (m_condition == nullptr)
+ fmt::print("{}nullptr\n", indent + INDENT);
+ else
+ m_condition->print(indent + INDENT);
+}
+
+void PreIfDefNode::print(std::string indent)
+{
+ fmt::print("{} {}: ", indent, node_name());
+
+ if (m_name == nullptr)
+ fmt::print("nullptr\n");
+ else
+ fmt::print("{}\n", m_name->name());
+}
+
+void PreIfNDefNode::print(std::string indent)
+{
+ fmt::print("{} {}: ", indent, node_name());
+
+ if (m_name == nullptr)
+ fmt::print("nullptr\n");
+ else
+ fmt::print("{}\n", m_name->name());
+}
+
+void PreDefineNode::print(std::string indent)
+{
+ fmt::print("{} {}: {}\n", indent, node_name(), m_str);
+}
+
+HolyParser::HolyParser(HolyLexer &lexer)
+ : m_lexer(lexer)
+{
+ next();
+ next();
+ next();
+}
+
+void HolyParser::next()
+{
+ m_tok = m_next;
+ m_next = m_third;
+ m_third = m_lexer.next();
+ if (m_tok == TokenType::NewLine && skip_newline) next();
+}
+
+Token HolyParser::prev_next()
+{
+ auto old = m_tok;
+ next();
+ return old;
+}
+
+bool HolyParser::accept(TokenType tt)
+{
+ if (m_tok == tt) {
+ next();
+ return true;
+ }
+ return false;
+}
+
+bool HolyParser::accept(Token tok)
+{
+ if (m_tok == tok) {
+ next();
+ return true;
+ }
+ return false;
+}
+
+bool HolyParser::expect(TokenType tt)
+{
+ if (accept(tt)) return true;
+ messages.push_back(
+ Error(fmt::format("Expected {}, got {}.", Token(tt).name(), m_tok.pretty()),
+ m_tok.range));
+ return false;
+}
+
+bool HolyParser::expect(Token tok)
+{
+ if (accept(tok)) return true;
+ messages.push_back(Error(
+ fmt::format("Expected {}, got {}.", tok.pretty(), m_tok.pretty()), m_tok.range));
+ return false;
+}
+
+std::vector<std::shared_ptr<ASTNode>> const HolyParser::parse_expression_list(
+ TokenType end)
+{
+ std::vector<std::shared_ptr<ASTNode>> arguments;
+ if (m_tok == end) return arguments;
+
+ for (;;) {
+ if (accept(TokenType::Comma)) { // HolyC allows empty default arguments
+ arguments.push_back(nullptr);
+ continue;
+ }
+ std::shared_ptr<ASTNode> node = parse_expression();
+ arguments.push_back(node);
+ if (m_tok == end) break;
+ expect(TokenType::Comma);
+ }
+
+ return arguments;
+}
+
+std::shared_ptr<FunctionCallNode> const HolyParser::parse_function_call()
+{
+ auto name = std::get<std::string_view>(prev_next().v);
+ expect(TokenType::LParen);
+
+ std::vector<std::shared_ptr<ASTNode>> arguments
+ = parse_expression_list(TokenType::RParen);
+ expect(TokenType::RParen);
+ return std::make_shared<FunctionCallNode>(FunctionCallNode(name, arguments));
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_factor()
+{
+ std::shared_ptr<ASTNode> final = nullptr;
+ if (m_tok == TokenType::Identifier) {
+ if (m_next == TokenType::LParen) {
+ final = parse_function_call();
+ } else {
+ final = std::make_shared<FunctionCallOrIdentifierNode>(
+ FunctionCallOrIdentifierNode(std::get<std::string_view>(prev_next().v)));
+ }
+ } else if (m_tok == TokenType::IntegerLiteral || m_tok == TokenType::FloatLiteral
+ || m_tok == TokenType::StringLiteral || m_tok == TokenType::CharLiteral) {
+ final = std::make_shared<LiteralNode>(LiteralNode(prev_next().v));
+ } else if (accept(TokenType::LParen)) {
+ final = parse_expression();
+ expect(TokenType::RParen);
+ } else {
+ messages.push_back(
+ Error(fmt::format("Unknown factor token: {}", m_tok.pretty()), m_tok.range));
+ }
+ return final;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_dot_access()
+{
+ auto start = m_tok.range.start;
+ auto node = parse_factor();
+ while (accept(TokenType::Dot)) {
+ auto right = parse_factor();
+ if (right == nullptr) break;
+
+ if (right->node_name() == "FunctionCallOrIdentifierNode")
+ node = std::make_shared<AccessNode>(AccessNode(node, right));
+ else {
+ messages.push_back(Error(
+ fmt::format("Dot access cannot have right anything other than an identifier"),
+ TextRange { start, m_tok.range.end }));
+ }
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_bit_shift_pow()
+{
+ std::shared_ptr<ASTNode> node = nullptr;
+ if (accept(TokenType::Not))
+ return std::make_shared<BooleanNegationNode>(
+ BooleanNegationNode(parse_bit_shift_pow()));
+ else if (accept(TokenType::Subtract))
+ return std::make_shared<NegationNode>(NegationNode(parse_bit_shift_pow()));
+ else
+ node = parse_dot_access();
+ while (m_tok == TokenType::LeftBitShift || m_tok == TokenType::RightBitShift
+ || m_tok == TokenType::Pow) {
+ auto set_type = prev_next().tt;
+ auto right = parse_dot_access();
+ node = std::make_shared<OperationNode>(OperationNode(node, right, set_type));
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_term()
+{
+ auto node = parse_bit_shift_pow();
+ while (m_tok == TokenType::Multiply || m_tok == TokenType::Divide
+ || m_tok == TokenType::Modulo) {
+ auto set_type = prev_next().tt;
+ auto right = parse_bit_shift_pow();
+ node = std::make_shared<OperationNode>(OperationNode(node, right, set_type));
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_bitwise_and()
+{
+ auto node = parse_term();
+ while (m_tok == TokenType::BitwiseAnd) {
+ auto set_type = prev_next().tt;
+ auto right = parse_term();
+ node = std::make_shared<OperationNode>(OperationNode(node, right, set_type));
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_bitwise_xor()
+{
+ auto node = parse_bitwise_and();
+ while (m_tok == TokenType::BitwiseXOR) {
+ auto set_type = prev_next().tt;
+ auto right = parse_bitwise_and();
+ node = std::make_shared<OperationNode>(OperationNode(node, right, set_type));
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_bitwise_or()
+{
+ auto node = parse_bitwise_xor();
+ while (m_tok == TokenType::BitwiseOr) {
+ auto set_type = prev_next().tt;
+ auto right = parse_bitwise_xor();
+ node = std::make_shared<OperationNode>(OperationNode(node, right, set_type));
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_math_expr()
+{
+ auto node = parse_bitwise_or();
+ while (m_tok == TokenType::Add || m_tok == TokenType::Subtract) {
+ auto set_type = prev_next().tt;
+ auto right = parse_bitwise_or();
+ node = std::make_shared<OperationNode>(OperationNode(node, right, set_type));
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_inequality()
+{
+ auto node = parse_math_expr();
+ while (m_tok == TokenType::LessThan || m_tok == TokenType::LessThanEquals
+ || m_tok == TokenType::GreaterThan || m_tok == TokenType::GreaterThanEquals) {
+ auto set_type = prev_next().tt;
+ auto right = parse_math_expr();
+ node = std::make_shared<OperationNode>(OperationNode(node, right, set_type));
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_equality()
+{
+ auto node = parse_inequality();
+ while (m_tok == TokenType::Equals || m_tok == TokenType::NotEquals) {
+ auto set_type = prev_next().tt;
+ auto right = parse_inequality();
+ node = std::make_shared<OperationNode>(OperationNode(node, right, set_type));
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_and()
+{
+ auto node = parse_equality();
+ while (m_tok == TokenType::And) {
+ auto set_type = prev_next().tt;
+ auto right = parse_equality();
+ node = std::make_shared<OperationNode>(OperationNode(node, right, set_type));
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_xor()
+{
+ auto node = parse_and();
+ while (m_tok == TokenType::XOR) {
+ auto set_type = prev_next().tt;
+ auto right = parse_and();
+ node = std::make_shared<OperationNode>(OperationNode(node, right, set_type));
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_or()
+{
+ auto node = parse_xor();
+ while (m_tok == TokenType::Or) {
+ auto set_type = prev_next().tt;
+ auto right = parse_xor();
+ node = std::make_shared<OperationNode>(OperationNode(node, right, set_type));
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_set()
+{
+ auto node = parse_or();
+ while (m_tok == TokenType::Set || m_tok == TokenType::AddSet
+ || m_tok == TokenType::SubtractSet || m_tok == TokenType::MultiplySet
+ || m_tok == TokenType::DivideSet || m_tok == TokenType::ModuloSet
+ || m_tok == TokenType::LeftBitShiftSet || m_tok == TokenType::RightBitShiftSet
+ || m_tok == TokenType::BitwiseAndSet || m_tok == TokenType::BitwiseOrSet
+ || m_tok == TokenType::BitwiseXORSet) {
+ auto set_type = prev_next().tt;
+ auto right = parse_or();
+ node = std::make_shared<SetOperationNode>(SetOperationNode(node, right, set_type));
+ }
+ return node;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_var_def()
+{
+ TextPosition start = m_tok.range.start;
+ std::shared_ptr<ASTNode> fin = nullptr;
+ auto type = parse_type();
+ std::vector<Definition> definitions;
+ while (m_tok == TokenType::Identifier) {
+ Definition def;
+ auto def_start = m_tok.range.start;
+ def.first = parse_factor();
+ def.second = nullptr;
+ // TODO: Add support for expression list (struct init)
+ if (accept(TokenType::Set)) {
+ def.second = parse_expression();
+ if (in_class_or_union)
+ messages.push_back(Error("Class or union members cannot have default value.",
+ TextRange { def_start, m_tok.range.end }));
+ }
+ definitions.push_back(def);
+ if (m_tok == TokenType::Semicolon) break;
+ if (!expect(TokenType::Comma)) break;
+ }
+ fin = std::make_shared<DefinitionsNode>(DefinitionsNode(type, definitions));
+ if (!decl_allowed)
+ messages.push_back(Warning("Variable(s) will be defined at root or function scope .",
+ TextRange { start, m_tok.range.end }));
+ return fin;
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_type()
+{
+ std::shared_ptr<ASTNode> type = nullptr;
+ if (accept(TokenType::Class)) {
+ auto class_name_tok = m_tok;
+ std::string_view class_name = std::get<std::string_view>(class_name_tok.v);
+ if (expect(TokenType::Identifier)) class_name = std::get<std::string_view>(m_tok.v);
+ expect(TokenType::LBracket);
+ // FIXME: Parse class defs
+ expect(TokenType::RBracket);
+ } else if (m_tok == TokenType::Identifier) {
+ return std::make_shared<FunctionCallOrIdentifierNode>(
+ FunctionCallOrIdentifierNode(std::get<std::string_view>(prev_next().v)));
+ }
+
+ return type;
+}
+
+std::shared_ptr<WhileNode> const HolyParser::parse_while()
+{
+ expect(TokenType::While);
+ expect(TokenType::LParen);
+ auto condition = parse_expression();
+ expect(TokenType::RParen);
+ std::shared_ptr<ASTNode> statement;
+ bool prev_d = decl_allowed;
+ decl_allowed = false;
+ if (!accept(TokenType::Semicolon)) statement = parse_statement();
+ decl_allowed = prev_d;
+ return std::make_shared<WhileNode>(WhileNode(condition, statement));
+}
+
+std::shared_ptr<ForNode> const HolyParser::parse_for()
+{
+ expect(TokenType::While);
+ expect(TokenType::LParen);
+ std::shared_ptr<ASTNode> set = nullptr;
+ if (!accept(TokenType::Semicolon)) {
+ set = parse_expression();
+ expect(TokenType::Semicolon);
+ }
+ std::shared_ptr<ASTNode> condition = nullptr;
+ if (!accept(TokenType::Semicolon)) {
+ condition = parse_expression();
+ expect(TokenType::Semicolon);
+ }
+ std::shared_ptr<ASTNode> advance = nullptr;
+ if (!accept(TokenType::RParen)) {
+ advance = parse_expression();
+ expect(TokenType::RParen);
+ }
+ std::shared_ptr<ASTNode> statement;
+ bool prev_d = decl_allowed;
+ decl_allowed = false;
+ if (!accept(TokenType::Semicolon)) statement = parse_statement();
+ decl_allowed = prev_d;
+ return std::make_shared<ForNode>(ForNode(set, condition, advance, statement));
+}
+
+std::shared_ptr<WhileNode> const HolyParser::parse_do()
+{
+ bool prev_d = decl_allowed;
+ expect(TokenType::Do);
+ decl_allowed = false;
+ auto statement = parse_statement();
+ decl_allowed = prev_d;
+ expect(TokenType::While);
+ expect(TokenType::LParen);
+ auto condition = parse_expression();
+ expect(TokenType::RParen);
+ return std::make_shared<WhileNode>(WhileNode(condition, statement, false));
+}
+
+std::shared_ptr<IfElseNode> const HolyParser::parse_if_else()
+{
+ expect(TokenType::If);
+ expect(TokenType::LParen);
+ auto condition = parse_expression();
+ expect(TokenType::RParen);
+ bool prev_d = decl_allowed;
+ decl_allowed = false;
+ auto statement = parse_statement();
+ std::shared_ptr<ASTNode> _false = nullptr;
+ decl_allowed = false;
+ if (accept(TokenType::Else)) _false = parse_statement();
+ decl_allowed = prev_d;
+ return std::make_shared<IfElseNode>(IfElseNode(condition, statement, _false));
+}
+
+std::shared_ptr<ASTNode> const HolyParser::parse_statement()
+{
+ std::shared_ptr<ASTNode> fin = nullptr;
+ TextPosition start = m_tok.range.start;
+ auto should_expect_semicolon = true;
+
+ if ((m_tok == TokenType::Identifier || m_tok == TokenType::Class)
+ && m_next == TokenType::Identifier) { // Variable declarations.
+ fin = parse_var_def();
+ } else if ((m_tok == TokenType::StringLiteral || m_tok == TokenType::CharLiteral)
+ && (m_next == TokenType::Semicolon || m_next == TokenType::Comma)) {
+ std::vector<std::shared_ptr<ASTNode>> arguments
+ = parse_expression_list(TokenType::Semicolon);
+ fin = std::make_shared<FunctionCallNode>(FunctionCallNode("Print", arguments));
+ } else if (accept(TokenType::LSquirly)) {
+ if (accept(TokenType::RSquirly)) { return nullptr; }
+ bool prev_d = decl_allowed;
+ decl_allowed = false;
+ fin = parse_program(TokenType::RSquirly);
+ decl_allowed = prev_d;
+ expect(TokenType::RSquirly);
+ should_expect_semicolon = false;
+ } else if (m_tok == TokenType::While) {
+ fin = parse_while();
+ should_expect_semicolon = false;
+ } else if (m_tok == TokenType::If) {
+ fin = parse_if_else();
+ should_expect_semicolon = false;
+ } else if (m_tok == TokenType::Do) {
+ fin = parse_do();
+ should_expect_semicolon = false;
+ } else if (m_tok == TokenType::Preprocessor) {
+ auto name = std::get<std::string_view>(m_tok.v);
+ should_expect_semicolon = false;
+ if (name == "exe") {
+ next();
+ if (expect(TokenType::LSquirly)) {
+ bool prev_d = decl_allowed;
+ decl_allowed = true;
+ fin = std::make_shared<PreExeNode>(
+ PreExeNode(parse_program(TokenType::RSquirly)));
+ decl_allowed = prev_d;
+ }
+ } else if (name == "if") {
+ skip_newline = false;
+ next();
+
+ if (accept(TokenType::NewLine) || accept(TokenType::EndOfFile))
+ fin = std::make_shared<PreIfNode>(PreIfNode());
+ else {
+ auto condition = parse_expression();
+ fin = std::make_shared<PreIfNode>(PreIfNode(condition));
+ if (!accept(TokenType::NewLine) && !accept(TokenType::EndOfFile))
+ messages.push_back(Error("Expected newline.", { start, m_tok.range.end }));
+ }
+ skip_newline = true;
+ } else if (name == "ifdef") {
+ skip_newline = false;
+ next();
+
+ if (accept(TokenType::NewLine) || accept(TokenType::EndOfFile))
+ fin = std::make_shared<PreIfDefNode>(PreIfDefNode());
+ else {
+ auto factor = parse_factor();
+ if (factor->node_name() == "FunctionCallOrIdentifierNode") {
+ std::shared_ptr<FunctionCallOrIdentifierNode> name
+ = std::dynamic_pointer_cast<FunctionCallOrIdentifierNode>(factor);
+ fin = std::make_shared<PreIfDefNode>(PreIfDefNode(name));
+ if (!accept(TokenType::NewLine) && !accept(TokenType::EndOfFile))
+ messages.push_back(Error("Expected newline.", { start, m_tok.range.end }));
+ } else {
+ // FIXME: Incorrect range
+ messages.push_back(
+ Error("Expected an identifier.", { start, m_tok.range.end }));
+ }
+ }
+ skip_newline = true;
+ } else if (name == "ifndef") {
+ skip_newline = false;
+ next();
+
+ if (accept(TokenType::NewLine) || accept(TokenType::EndOfFile))
+ fin = std::make_shared<PreIfNDefNode>(PreIfNDefNode());
+ else {
+ auto factor = parse_factor();
+ if (factor->node_name() == "FunctionCallOrIdentifierNode") {
+ std::shared_ptr<FunctionCallOrIdentifierNode> name
+ = std::dynamic_pointer_cast<FunctionCallOrIdentifierNode>(factor);
+ fin = std::make_shared<PreIfNDefNode>(PreIfNDefNode(name));
+ if (!accept(TokenType::NewLine) && !accept(TokenType::EndOfFile))
+ messages.push_back(Error("Expected newline.", { start, m_tok.range.end }));
+ } else {
+ // FIXME: Incorrect range
+ messages.push_back(
+ Error("Expected an identifier.", { start, m_tok.range.end }));
+ }
+ }
+ skip_newline = true;
+ } else if (name == "endif") {
+ skip_newline = false;
+ next();
+
+ if (!accept(TokenType::NewLine) && !accept(TokenType::EndOfFile))
+ messages.push_back(Error("Expected newline.", { start, m_tok.range.end }));
+ fin = std::make_shared<PreEndIfNode>(PreEndIfNode());
+ skip_newline = true;
+ } else if (name.starts_with("define")) { // lol
+ skip_newline = false;
+ next();
+
+ if (name.find(' ') < name.length()) {
+ fin = std::make_shared<PreDefineNode>(
+ PreDefineNode(name.substr(name.find(' '), name.length() - 1)));
+ } else
+ fin = std::make_shared<PreDefineNode>(PreDefineNode());
+ if (!accept(TokenType::NewLine) && !accept(TokenType::EndOfFile))
+ messages.push_back(Error("Expected newline.", { start, m_tok.range.end }));
+ skip_newline = true;
+ } else {
+ messages.push_back(Error("Unknown preprocessor derivative", m_tok.range));
+ next();
+ }
+ } else
+ fin = parse_expression(); // FIXME: Replace with expression list
+
+ if (should_expect_semicolon) expect(TokenType::Semicolon);
+
+ return fin;
+}
+
+std::shared_ptr<ProgramNode> const HolyParser::parse_program(TokenType end)
+{
+ ProgramNode program;
+ bool da = decl_allowed;
+
+ for (;;) {
+ while (accept(TokenType::Semicolon)) // We don't care about trailing semicolons.
+ ;
+ if (accept(end)) break;
+
+ decl_allowed = da;
+ auto statement = parse_statement();
+ if (statement != nullptr) program.statements.push_back(statement);
+ }
+
+ return std::make_shared<ProgramNode>(program);
+}
+
+} // namespace holyparser
diff --git a/subprojects/fmt.wrap b/subprojects/fmt.wrap
new file mode 100644
index 0000000..9efe101
--- /dev/null
+++ b/subprojects/fmt.wrap
@@ -0,0 +1,13 @@
+[wrap-file]
+directory = fmt-9.1.0
+source_url = https://github.com/fmtlib/fmt/archive/9.1.0.tar.gz
+source_filename = fmt-9.1.0.tar.gz
+source_hash = 5dea48d1fcddc3ec571ce2058e13910a0d4a6bab4cc09a809d8b1dd1c88ae6f2
+patch_filename = fmt_9.1.0-2_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/fmt_9.1.0-2/get_patch
+patch_hash = 23e8c4829f3e63f509b5643fe6bb87cbed39eae9594c451b338475d14d051967
+source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/fmt_9.1.0-2/fmt-9.1.0.tar.gz
+wrapdb_version = 9.1.0-2
+
+[provide]
+fmt = fmt_dep
diff --git a/subprojects/wrapdb.json b/subprojects/wrapdb.json
new file mode 100644
index 0000000..9fa01d2
--- /dev/null
+++ b/subprojects/wrapdb.json
@@ -0,0 +1,2880 @@
+{
+ "abseil-cpp": {
+ "dependency_names": [
+ "absl_base",
+ "absl_container",
+ "absl_crc",
+ "absl_debugging",
+ "absl_flags",
+ "absl_hash",
+ "absl_log",
+ "absl_numeric",
+ "absl_profiling",
+ "absl_random",
+ "absl_status",
+ "absl_strings",
+ "absl_synchronization",
+ "absl_time",
+ "absl_types",
+ "absl_bad_any_cast_impl",
+ "absl_bad_optional_access",
+ "absl_bad_variant_access",
+ "absl_city",
+ "absl_civil_time",
+ "absl_cord",
+ "absl_cord_internal",
+ "absl_cordz_functions",
+ "absl_cordz_handle",
+ "absl_cordz_info",
+ "absl_cordz_sample_token",
+ "absl_debugging_internal",
+ "absl_demangle_internal",
+ "absl_examine_stack",
+ "absl_exponential_biased",
+ "absl_failure_signal_handler",
+ "absl_flags_commandlineflag",
+ "absl_flags_commandlineflag_internal",
+ "absl_flags_config",
+ "absl_flags_internal",
+ "absl_flags_marshalling",
+ "absl_flags_parse",
+ "absl_flags_private_handle_accessor",
+ "absl_flags_program_name",
+ "absl_flags_reflection",
+ "absl_flags_usage",
+ "absl_flags_usage_internal",
+ "absl_graphcycles_internal",
+ "absl_hashtablez_sampler",
+ "absl_int128",
+ "absl_leak_check",
+ "absl_log_severity",
+ "absl_low_level_hash",
+ "absl_periodic_sampler",
+ "absl_random_distributions",
+ "absl_random_internal_distribution_test_util",
+ "absl_random_internal_platform",
+ "absl_random_internal_pool_urbg",
+ "absl_random_internal_randen",
+ "absl_random_internal_randen_hwaes",
+ "absl_random_internal_randen_hwaes_impl",
+ "absl_random_internal_randen_slow",
+ "absl_random_internal_seed_material",
+ "absl_random_seed_gen_exception",
+ "absl_random_seed_sequences",
+ "absl_raw_hash_set",
+ "absl_raw_logging_internal",
+ "absl_scoped_set_env",
+ "absl_spinlock_wait",
+ "absl_stacktrace",
+ "absl_statusor",
+ "absl_strerror",
+ "absl_str_format_internal",
+ "absl_strings_internal",
+ "absl_symbolize",
+ "absl_throw_delegate",
+ "absl_time_zone"
+ ],
+ "versions": [
+ "20230125.1-4",
+ "20230125.1-3",
+ "20230125.1-2",
+ "20230125.1-1",
+ "20220623.0-2",
+ "20220623.0-1",
+ "20211102.0-3",
+ "20211102.0-2",
+ "20211102.0-1",
+ "20210324.2-4",
+ "20210324.2-3",
+ "20210324.2-2",
+ "20210324.2-1",
+ "20210324.1-4",
+ "20210324.1-3",
+ "20210324.1-2",
+ "20210324.1-1",
+ "20200923.2-1",
+ "20200225.2-3",
+ "20200225.2-2",
+ "20200225.2-1"
+ ]
+ },
+ "arduinocore-avr": {
+ "versions": [
+ "1.8.2-1",
+ "1.6.20-1"
+ ]
+ },
+ "argparse": {
+ "dependency_names": [
+ "argparse"
+ ],
+ "versions": [
+ "2.9-1",
+ "2.6-1",
+ "2.5-1",
+ "2.4-1",
+ "2.2-1"
+ ]
+ },
+ "asio": {
+ "dependency_names": [
+ "asio"
+ ],
+ "versions": [
+ "1.24.0-1"
+ ]
+ },
+ "backward-cpp": {
+ "dependency_names": [
+ "backward-cpp"
+ ],
+ "versions": [
+ "1.6-2",
+ "1.6-1"
+ ]
+ },
+ "bdwgc": {
+ "dependency_names": [
+ "gc"
+ ],
+ "versions": [
+ "8.2.2-1",
+ "8.2.0-1",
+ "7.6.8-1"
+ ]
+ },
+ "box2d": {
+ "dependency_names": [
+ "box2d"
+ ],
+ "versions": [
+ "2.4.1-3",
+ "2.4.1-2",
+ "2.4.1-1",
+ "2.3.1-7",
+ "2.3.1-5",
+ "2.3.1-4",
+ "2.3.1-2"
+ ]
+ },
+ "bshoshany-thread-pool": {
+ "dependency_names": [
+ "bshoshany-thread-pool"
+ ],
+ "versions": [
+ "3.5.0-1",
+ "3.4.0-1",
+ "3.3.0-1"
+ ]
+ },
+ "c-flags": {
+ "dependency_names": [
+ "c-flags"
+ ],
+ "versions": [
+ "1.5.4-1"
+ ]
+ },
+ "cairo": {
+ "dependency_names": [
+ "cairo",
+ "cairo-gobject"
+ ],
+ "versions": [
+ "1.17.8-1"
+ ]
+ },
+ "catch": {
+ "versions": [
+ "2.2.2-1",
+ "2.2.1-2",
+ "2.2.1-1"
+ ]
+ },
+ "catch2": {
+ "dependency_names": [
+ "catch2",
+ "catch2-with-main"
+ ],
+ "versions": [
+ "3.3.2-1",
+ "3.2.0-1",
+ "3.1.0-1",
+ "2.13.8-1",
+ "2.13.7-1",
+ "2.13.3-2",
+ "2.13.3-1",
+ "2.11.3-1",
+ "2.11.1-1",
+ "2.9.0-1",
+ "2.8.0-1",
+ "2.7.2-1",
+ "2.5.0-1",
+ "2.4.1-1"
+ ]
+ },
+ "catchorg-clara": {
+ "versions": [
+ "1.1.5-1"
+ ]
+ },
+ "centurion": {
+ "dependency_names": [
+ "centurion"
+ ],
+ "versions": [
+ "7.3.0-1",
+ "7.2.0-1"
+ ]
+ },
+ "cereal": {
+ "dependency_names": [
+ "cereal"
+ ],
+ "versions": [
+ "1.3.2-1",
+ "1.3.0-1",
+ "1.2.2-1"
+ ]
+ },
+ "cexception": {
+ "dependency_names": [
+ "cexception"
+ ],
+ "versions": [
+ "1.3.3-1"
+ ]
+ },
+ "check": {
+ "dependency_names": [
+ "check"
+ ],
+ "versions": [
+ "0.15.2-3",
+ "0.15.2-2",
+ "0.15.2-1",
+ "0.14.0-1"
+ ]
+ },
+ "chipmunk": {
+ "dependency_names": [
+ "chipmunk"
+ ],
+ "versions": [
+ "7.0.3-1",
+ "6.2.2-2",
+ "6.2.2-1"
+ ]
+ },
+ "cjson": {
+ "dependency_names": [
+ "libcjson",
+ "libcjson_utils"
+ ],
+ "versions": [
+ "1.7.15-6",
+ "1.7.15-5",
+ "1.7.15-4",
+ "1.7.15-3",
+ "1.7.15-2",
+ "1.7.15-1",
+ "1.7.14-1"
+ ]
+ },
+ "cli11": {
+ "dependency_names": [
+ "cli11"
+ ],
+ "versions": [
+ "2.3.2-1",
+ "2.2.0-1",
+ "2.1.2-1",
+ "1.9.1-1"
+ ]
+ },
+ "cmark-gfm": {
+ "dependency_names": [
+ "libcmark-gfm"
+ ],
+ "versions": [
+ "0.29.0.gfm.10-1",
+ "0.29.0.gfm.6-1"
+ ]
+ },
+ "cmock": {
+ "dependency_names": [
+ "cmock"
+ ],
+ "versions": [
+ "2.5.3-1"
+ ]
+ },
+ "cmocka": {
+ "dependency_names": [
+ "cmocka"
+ ],
+ "versions": [
+ "1.1.7-1",
+ "1.1.5-5",
+ "1.1.5-4",
+ "1.1.5-3",
+ "1.1.5-2",
+ "1.1.5-1",
+ "1.1.2-1"
+ ]
+ },
+ "concurrentqueue": {
+ "dependency_names": [
+ "concurrentqueue"
+ ],
+ "versions": [
+ "1.0.3-1"
+ ]
+ },
+ "cpp-httplib": {
+ "dependency_names": [
+ "cpp-httplib"
+ ],
+ "versions": [
+ "0.13.1-1",
+ "0.11.2-1",
+ "0.8.9-2",
+ "0.8.9-1"
+ ]
+ },
+ "cpputest": {
+ "dependency_names": [
+ "cpputest"
+ ],
+ "versions": [
+ "4.0-2",
+ "4.0-1"
+ ]
+ },
+ "cppzmq": {
+ "dependency_names": [
+ "cppzmq"
+ ],
+ "versions": [
+ "4.9.0-1",
+ "4.8.1-2",
+ "4.8.1-1"
+ ]
+ },
+ "cpr": {
+ "dependency_names": [
+ "cpr"
+ ],
+ "versions": [
+ "1.9.3-1",
+ "1.9.2-2",
+ "1.9.2-1",
+ "1.7.2-1",
+ "1.5.0-1",
+ "1.3.0-1"
+ ]
+ },
+ "croaring": {
+ "dependency_names": [
+ "croaring"
+ ],
+ "versions": [
+ "1.3.0-1"
+ ]
+ },
+ "cxxopts": {
+ "dependency_names": [
+ "cxxopts"
+ ],
+ "versions": [
+ "3.1.1-1",
+ "3.0.0-1",
+ "2.2.1-1",
+ "2.2.0-2",
+ "2.2.0-1"
+ ]
+ },
+ "dlfcn-win32": {
+ "dependency_names": [
+ "dl"
+ ],
+ "versions": [
+ "1.3.1-1"
+ ]
+ },
+ "docopt": {
+ "dependency_names": [
+ "docopt"
+ ],
+ "versions": [
+ "0.6.3-3",
+ "0.6.3-2",
+ "0.6.3-1"
+ ]
+ },
+ "doctest": {
+ "dependency_names": [
+ "doctest"
+ ],
+ "versions": [
+ "2.4.11-1",
+ "2.4.9-1",
+ "2.4.8-1"
+ ]
+ },
+ "dragonbox": {
+ "dependency_names": [
+ "dragonbox"
+ ],
+ "versions": [
+ "1.1.2-1"
+ ]
+ },
+ "eigen": {
+ "dependency_names": [
+ "eigen3"
+ ],
+ "versions": [
+ "3.4.0-2",
+ "3.4.0-1",
+ "3.3.9-1",
+ "3.3.8-1",
+ "3.3.7-3",
+ "3.3.7-2",
+ "3.3.7-1",
+ "3.3.5-1",
+ "3.3.4-1"
+ ]
+ },
+ "emilk-loguru": {
+ "dependency_names": [
+ "loguru"
+ ],
+ "versions": [
+ "2.1.0-8",
+ "2.1.0-7",
+ "2.1.0-6",
+ "2.1.0-5",
+ "2.1.0-4",
+ "2.1.0-3",
+ "2.1.0-2",
+ "2.1.0-1"
+ ]
+ },
+ "enet": {
+ "dependency_names": [
+ "enet"
+ ],
+ "versions": [
+ "1.3.17-2",
+ "1.3.17-1",
+ "1.3.13-4",
+ "1.3.13-2"
+ ]
+ },
+ "entt": {
+ "dependency_names": [
+ "entt"
+ ],
+ "versions": [
+ "3.11.0-2",
+ "3.11.0-1"
+ ]
+ },
+ "epoxy": {
+ "dependency_names": [
+ "epoxy"
+ ],
+ "versions": [
+ "1.5.10-2",
+ "1.5.10-1",
+ "1.5.9-1"
+ ]
+ },
+ "exiv2": {
+ "dependency_names": [
+ "exiv2"
+ ],
+ "versions": [
+ "0.28.0-1"
+ ]
+ },
+ "expat": {
+ "dependency_names": [
+ "expat"
+ ],
+ "versions": [
+ "2.5.0-3",
+ "2.5.0-2",
+ "2.5.0-1",
+ "2.4.9-1",
+ "2.4.8-2",
+ "2.4.8-1",
+ "2.2.9-4",
+ "2.2.9-3",
+ "2.2.9-2",
+ "2.2.9-1",
+ "2.2.6-1",
+ "2.2.5-5",
+ "2.2.5-4",
+ "2.2.5-3",
+ "2.2.5-1"
+ ]
+ },
+ "facil": {
+ "dependency_names": [
+ "facil"
+ ],
+ "versions": [
+ "0.7.6-2",
+ "0.7.6-1",
+ "0.7.5-1"
+ ]
+ },
+ "fdk-aac": {
+ "dependency_names": [
+ "fdk-aac"
+ ],
+ "versions": [
+ "2.0.2-0"
+ ]
+ },
+ "ff-nvcodec-headers": {
+ "dependency_names": [
+ "ffnvcodec"
+ ],
+ "versions": [
+ "11.1.5.1-0"
+ ]
+ },
+ "flac": {
+ "dependency_names": [
+ "flac"
+ ],
+ "versions": [
+ "1.4.3-1",
+ "1.4.2-2",
+ "1.4.2-1",
+ "1.4.1-1",
+ "1.4.0-2",
+ "1.4.0-1",
+ "1.3.4-4",
+ "1.3.4-3",
+ "1.3.4-2",
+ "1.3.4-1",
+ "1.3.3-2",
+ "1.3.3-1"
+ ]
+ },
+ "flatbuffers": {
+ "dependency_names": [
+ "flatbuffers"
+ ],
+ "program_names": [
+ "flatc",
+ "flathash"
+ ],
+ "versions": [
+ "23.3.3-1",
+ "23.1.21-1",
+ "22.11.23-1",
+ "2.0.8-1",
+ "2.0.6-2",
+ "2.0.6-1",
+ "1.11.0-1"
+ ]
+ },
+ "fluidsynth": {
+ "dependency_names": [
+ "fluidsynth"
+ ],
+ "versions": [
+ "2.3.3-1",
+ "2.3.2-1",
+ "2.3.0-1",
+ "2.2.8-1",
+ "2.2.6-1",
+ "2.2.4-3",
+ "2.2.4-2",
+ "2.2.4-1",
+ "2.2.3-2",
+ "2.2.3-1",
+ "2.2.0-1",
+ "2.1.8-1",
+ "2.1.7-1"
+ ]
+ },
+ "fmt": {
+ "dependency_names": [
+ "fmt"
+ ],
+ "versions": [
+ "9.1.0-2",
+ "9.1.0-1",
+ "9.0.0-1",
+ "8.1.1-2",
+ "8.1.1-1",
+ "8.0.1-1",
+ "7.1.3-1",
+ "7.0.1-1",
+ "6.2.0-2",
+ "6.2.0-1",
+ "6.0.0-1",
+ "5.3.0-1",
+ "5.2.1-1",
+ "5.2.0-1",
+ "4.1.0-1"
+ ]
+ },
+ "fontconfig": {
+ "dependency_names": [
+ "fontconfig"
+ ],
+ "versions": [
+ "2.14.2-1"
+ ]
+ },
+ "freetype2": {
+ "dependency_names": [
+ "freetype2",
+ "freetype"
+ ],
+ "versions": [
+ "2.13.1-1",
+ "2.13.0-1",
+ "2.12.1-2",
+ "2.12.1-1",
+ "2.12.0-1",
+ "2.11.1-1",
+ "2.11.0-1",
+ "2.9.1-2",
+ "2.9.1-1"
+ ]
+ },
+ "fribidi": {
+ "dependency_names": [
+ "fribidi"
+ ],
+ "versions": [
+ "1.0.13-1"
+ ]
+ },
+ "frozen": {
+ "dependency_names": [
+ "frozen"
+ ],
+ "versions": [
+ "1.0.1-2",
+ "1.0.1-1"
+ ]
+ },
+ "ftxui": {
+ "dependency_names": [
+ "ftxui-screen",
+ "ftxui-dom",
+ "ftxui-component"
+ ],
+ "versions": [
+ "4.0.0-1",
+ "3.0.0-2",
+ "3.0.0-1",
+ "2.0.0-3",
+ "2.0.0-2",
+ "2.0.0-1"
+ ]
+ },
+ "fuse": {
+ "dependency_names": [
+ "fuse"
+ ],
+ "versions": [
+ "2.9.9-3",
+ "2.9.9-2",
+ "2.9.9-1"
+ ]
+ },
+ "gdbm": {
+ "dependency_names": [
+ "gdbm"
+ ],
+ "versions": [
+ "1.23-2",
+ "1.23-1",
+ "1.14.1-2",
+ "1.14.1-1"
+ ]
+ },
+ "glbinding": {
+ "dependency_names": [
+ "glbinding",
+ "glbinding-aux"
+ ],
+ "versions": [
+ "3.3.0-1"
+ ]
+ },
+ "glew": {
+ "dependency_names": [
+ "glew"
+ ],
+ "versions": [
+ "2.2.0-2",
+ "2.2.0-1",
+ "2.1.0-4",
+ "2.1.0-3",
+ "2.1.0-2",
+ "2.1.0-1"
+ ]
+ },
+ "glfw": {
+ "dependency_names": [
+ "glfw3"
+ ],
+ "versions": [
+ "3.3.8-2",
+ "3.3.8-1",
+ "3.3.7-1"
+ ]
+ },
+ "glib": {
+ "dependency_names": [
+ "gthread-2.0",
+ "gobject-2.0",
+ "gmodule-no-export-2.0",
+ "gmodule-export-2.0",
+ "gmodule-2.0",
+ "glib-2.0",
+ "gio-2.0",
+ "gio-windows-2.0",
+ "gio-unix-2.0"
+ ],
+ "program_names": [
+ "glib-genmarshal",
+ "glib-mkenums",
+ "glib-compile-schemas",
+ "glib-compile-resources",
+ "gio-querymodules",
+ "gdbus-codegen"
+ ],
+ "versions": [
+ "2.76.3-1",
+ "2.76.1-1",
+ "2.74.4-1",
+ "2.74.1-1",
+ "2.74.0-2",
+ "2.74.0-1",
+ "2.72.2-1",
+ "2.72.1-1",
+ "2.70.4-1",
+ "2.70.2-1",
+ "2.70.1-1",
+ "2.70.0-1",
+ "2.68.1-1",
+ "2.66.7-1"
+ ]
+ },
+ "glm": {
+ "dependency_names": [
+ "glm"
+ ],
+ "versions": [
+ "0.9.9.8-2",
+ "0.9.9.8-1"
+ ]
+ },
+ "google-benchmark": {
+ "dependency_names": [
+ "benchmark"
+ ],
+ "versions": [
+ "1.7.1-2",
+ "1.7.1-1",
+ "1.7.0-1",
+ "1.6.0-1",
+ "1.5.2-1",
+ "1.4.1-1"
+ ]
+ },
+ "google-brotli": {
+ "dependency_names": [
+ "libbrotlicommon",
+ "libbrotlienc",
+ "libbrotlidec"
+ ],
+ "versions": [
+ "1.0.9-2",
+ "1.0.9-1",
+ "1.0.7-1"
+ ]
+ },
+ "google-snappy": {
+ "dependency_names": [
+ "snappy"
+ ],
+ "versions": [
+ "1.1.9-1",
+ "1.1.7-2",
+ "1.1.7-1"
+ ]
+ },
+ "google-woff2": {
+ "dependency_names": [
+ "libwoff2common",
+ "libwoff2dec",
+ "libwoff2enc"
+ ],
+ "program_names": [
+ "woff2_decompress",
+ "woff2_compress",
+ "woff2_info"
+ ],
+ "versions": [
+ "1.0.2-2",
+ "1.0.2-1"
+ ]
+ },
+ "graphite2": {
+ "dependency_names": [
+ "graphite2"
+ ],
+ "versions": [
+ "1.3.14-1"
+ ]
+ },
+ "harfbuzz": {
+ "dependency_names": [
+ "harfbuzz",
+ "harfbuzz-icu",
+ "harfbuzz-subset",
+ "harfbuzz-gobject"
+ ],
+ "versions": [
+ "5.2.0-1",
+ "4.4.1-1"
+ ]
+ },
+ "hedley": {
+ "dependency_names": [
+ "hedley"
+ ],
+ "versions": [
+ "15-1",
+ "11-1"
+ ]
+ },
+ "hinnant-date": {
+ "dependency_names": [
+ "date",
+ "tz"
+ ],
+ "versions": [
+ "3.0.1-2",
+ "3.0.1-1",
+ "3.0.0-1",
+ "2.4.1-1"
+ ]
+ },
+ "htslib": {
+ "dependency_names": [
+ "htslib"
+ ],
+ "versions": [
+ "1.17-2",
+ "1.17-1",
+ "1.16-3",
+ "1.16-2",
+ "1.16-1",
+ "1.15-1",
+ "1.14-1",
+ "1.11-1",
+ "1.10.2-1",
+ "1.9-1"
+ ]
+ },
+ "icu": {
+ "dependency_names": [
+ "icu-uc",
+ "icu-io",
+ "icu-i18n"
+ ],
+ "program_names": [
+ "genbrk",
+ "genccode",
+ "gencmn"
+ ],
+ "versions": [
+ "73.1-1",
+ "72.1-5",
+ "72.1-4",
+ "72.1-3",
+ "72.1-2",
+ "72.1-1",
+ "71.1-1",
+ "70.1-2",
+ "70.1-1",
+ "67.1-4",
+ "67.1-3",
+ "67.1-2",
+ "67.1-1",
+ "55.2-1"
+ ]
+ },
+ "iir": {
+ "dependency_names": [
+ "iir"
+ ],
+ "versions": [
+ "1.9.3-1",
+ "1.9.2-2",
+ "1.9.2-1"
+ ]
+ },
+ "imgui": {
+ "dependency_names": [
+ "imgui"
+ ],
+ "versions": [
+ "1.89.3-1",
+ "1.89.2-1",
+ "1.88-2",
+ "1.88-1",
+ "1.87-5",
+ "1.87-4",
+ "1.87-3",
+ "1.87-2",
+ "1.87-1",
+ "1.86-1",
+ "1.85-1",
+ "1.81-1",
+ "1.80-1",
+ "1.79-2",
+ "1.79-1",
+ "1.78-2",
+ "1.78-1",
+ "1.76-2",
+ "1.76-1"
+ ]
+ },
+ "imgui-sfml": {
+ "dependency_names": [
+ "imgui-sfml"
+ ],
+ "versions": [
+ "2.5-4",
+ "2.5-3",
+ "2.5-2",
+ "2.5-1",
+ "2.3-2",
+ "2.3-1",
+ "2.1-1"
+ ]
+ },
+ "imguizmo": {
+ "dependency_names": [
+ "imguizmo"
+ ],
+ "versions": [
+ "1.83-1"
+ ]
+ },
+ "indicators": {
+ "dependency_names": [
+ "indicators"
+ ],
+ "versions": [
+ "2.2-2",
+ "2.2-1"
+ ]
+ },
+ "inih": {
+ "dependency_names": [
+ "inih",
+ "inireader"
+ ],
+ "versions": [
+ "r57-1",
+ "r56-1",
+ "r54-1",
+ "r53-1",
+ "r52-1",
+ "r51-1"
+ ]
+ },
+ "irepeat": {
+ "dependency_names": [
+ "irepeat"
+ ],
+ "versions": [
+ "0.6-1"
+ ]
+ },
+ "jansson": {
+ "dependency_names": [
+ "jansson"
+ ],
+ "versions": [
+ "2.14-1",
+ "2.13-1",
+ "2.11-3",
+ "2.11-2",
+ "2.11-1"
+ ]
+ },
+ "jbigkit": {
+ "versions": [
+ "2.1-2",
+ "2.1-1"
+ ],
+ "dependency_names": [
+ "libjbig",
+ "libjbig85"
+ ],
+ "program_names": [
+ "jbgtopbm",
+ "pbmtojbg",
+ "jbgtopbm85",
+ "pbmtojbg85"
+ ]
+ },
+ "json": {
+ "versions": [
+ "3.2.0-1",
+ "2.1.1-1",
+ "2.0.5-1",
+ "2.0.3-1"
+ ]
+ },
+ "json-c": {
+ "versions": [
+ "0.16-4",
+ "0.16-3",
+ "0.16-2",
+ "0.16-1",
+ "0.15-2",
+ "0.15-1",
+ "0.13.1-1"
+ ],
+ "dependency_names": [
+ "json-c"
+ ]
+ },
+ "json-glib": {
+ "dependency_names": [
+ "json-glib-1.0"
+ ],
+ "versions": [
+ "1.6.6-2",
+ "1.6.6-1"
+ ]
+ },
+ "jsoncpp": {
+ "dependency_names": [
+ "jsoncpp"
+ ],
+ "versions": [
+ "1.9.5-2",
+ "1.9.5-1",
+ "1.8.4-1"
+ ]
+ },
+ "lame": {
+ "dependency_names": [
+ "mp3lame",
+ "mpglib"
+ ],
+ "versions": [
+ "3.100-9",
+ "3.100-8",
+ "3.100-7",
+ "3.100-6",
+ "3.100-5",
+ "3.100-4",
+ "3.100-3",
+ "3.100-2",
+ "3.100-1",
+ "3.99.5-1"
+ ]
+ },
+ "lcms2": {
+ "dependency_names": [
+ "lcms2"
+ ],
+ "versions": [
+ "2.15-1",
+ "2.13.1-1",
+ "2.12-2",
+ "2.12-1"
+ ]
+ },
+ "libarchive": {
+ "dependency_names": [
+ "libarchive"
+ ],
+ "versions": [
+ "3.6.2-3",
+ "3.6.2-2",
+ "3.6.2-1"
+ ]
+ },
+ "libccp4c": {
+ "dependency_names": [
+ "libccp4c"
+ ],
+ "versions": [
+ "8.0.0-1",
+ "6.5.1-2",
+ "6.5.1-1"
+ ]
+ },
+ "libdrm": {
+ "dependency_names": [
+ "libdrm",
+ "libdrm_amdgpu",
+ "libdrm_etnaviv",
+ "libdrm_exynos",
+ "libdrm_freedreno",
+ "libdrm_intel",
+ "libdrm_nouveau",
+ "libdrm_omap",
+ "libdrm_radeon",
+ "libdrm_tegra"
+ ],
+ "versions": [
+ "2.4.114-1",
+ "2.4.111-1",
+ "2.4.110-1"
+ ]
+ },
+ "libebml": {
+ "dependency_names": [
+ "libebml"
+ ],
+ "versions": [
+ "1.4.4-2",
+ "1.4.4-1",
+ "1.4.3-1",
+ "1.4.2-1"
+ ]
+ },
+ "libexif": {
+ "dependency_names": [
+ "libexif"
+ ],
+ "versions": [
+ "0.6.24-5",
+ "0.6.24-4",
+ "0.6.24-3",
+ "0.6.24-2",
+ "0.6.24-1",
+ "0.6.22-1"
+ ]
+ },
+ "libffi": {
+ "dependency_names": [
+ "libffi"
+ ],
+ "versions": [
+ "3.4.4-2",
+ "3.4.4-1"
+ ]
+ },
+ "libffmpegthumbnailer": {
+ "dependency_names": [
+ "libffmpegthumbnailer"
+ ],
+ "versions": [
+ "2.2.2-2",
+ "2.2.2-1"
+ ]
+ },
+ "libgpiod": {
+ "versions": [
+ "1.6.3-1"
+ ],
+ "dependency_names": [
+ "libgpiod",
+ "libgpiodcxx"
+ ]
+ },
+ "libjpeg-turbo": {
+ "dependency_names": [
+ "libjpeg"
+ ],
+ "versions": [
+ "3.0.0-1",
+ "2.1.5.1-1",
+ "2.1.4-1",
+ "2.1.3-1",
+ "2.1.2-2",
+ "2.1.2-1",
+ "2.1.0-2",
+ "2.1.0-1"
+ ]
+ },
+ "libkqueue": {
+ "dependency_names": [
+ "libkqueue"
+ ],
+ "versions": [
+ "2.6.2-1",
+ "2.6.1-2",
+ "2.6.1-1"
+ ]
+ },
+ "liblangtag": {
+ "dependency_names": [
+ "liblangtag"
+ ],
+ "versions": [
+ "0.6.4-2",
+ "0.6.4-1",
+ "0.6.3-1"
+ ]
+ },
+ "liblastfm": {
+ "versions": [
+ "1.0.1-1"
+ ],
+ "dependency_names": [
+ "liblastfm"
+ ]
+ },
+ "liblbfgs": {
+ "dependency_names": [
+ "liblbfgs"
+ ],
+ "versions": [
+ "1.10-2",
+ "1.10-1"
+ ]
+ },
+ "libliftoff": {
+ "dependency_names": [
+ "libliftoff"
+ ],
+ "versions": [
+ "0.3.0-1"
+ ]
+ },
+ "liblzma": {
+ "dependency_names": [
+ "liblzma"
+ ],
+ "versions": [
+ "5.2.11-2",
+ "5.2.11-1",
+ "5.2.10-1",
+ "5.2.8-2",
+ "5.2.8-1",
+ "5.2.7-1",
+ "5.2.6-3",
+ "5.2.6-2",
+ "5.2.6-1",
+ "5.2.5-2",
+ "5.2.5-1",
+ "5.2.1-6",
+ "5.2.1-5",
+ "5.2.1-4",
+ "5.2.1-2"
+ ]
+ },
+ "libmatroska": {
+ "dependency_names": [
+ "libmatroska"
+ ],
+ "versions": [
+ "1.7.1-1",
+ "1.7.0-1",
+ "1.6.3-1"
+ ]
+ },
+ "libmicrohttpd": {
+ "dependency_names": [
+ "libmicrohttpd"
+ ],
+ "versions": [
+ "0.9.77-1",
+ "0.9.76-3",
+ "0.9.76-2",
+ "0.9.76-1"
+ ]
+ },
+ "libnpupnp": {
+ "dependency_names": [
+ "libnpupnp"
+ ],
+ "versions": [
+ "5.0.1-1",
+ "5.0.0-2",
+ "5.0.0-1",
+ "4.2.2-2",
+ "4.2.2-1",
+ "4.2.1-2",
+ "4.2.1-1"
+ ]
+ },
+ "libobsd": {
+ "dependency_names": [
+ "libbsd-overlay",
+ "libobsd"
+ ],
+ "versions": [
+ "1.1.0-1",
+ "1.0.0-1"
+ ]
+ },
+ "libopenjp2": {
+ "dependency_names": [
+ "libopenjp2"
+ ],
+ "versions": [
+ "2.5.0-1",
+ "2.3.1-9",
+ "2.3.1-8",
+ "2.3.1-7",
+ "2.3.1-6",
+ "2.3.1-5",
+ "2.3.1-4",
+ "2.3.1-3",
+ "2.3.1-1"
+ ]
+ },
+ "libpng": {
+ "dependency_names": [
+ "libpng"
+ ],
+ "versions": [
+ "1.6.40-1",
+ "1.6.39-3",
+ "1.6.39-2",
+ "1.6.39-1",
+ "1.6.37-5",
+ "1.6.37-4",
+ "1.6.37-3",
+ "1.6.37-2",
+ "1.6.37-1",
+ "1.6.35-6",
+ "1.6.35-5",
+ "1.6.35-4",
+ "1.6.34-3",
+ "1.6.34-2",
+ "1.6.34-1",
+ "1.6.17-8",
+ "1.6.17-7",
+ "1.6.17-6",
+ "1.6.17-5",
+ "1.6.17-4",
+ "1.6.17-2"
+ ]
+ },
+ "libsndfile": {
+ "dependency_names": [
+ "sndfile"
+ ],
+ "versions": [
+ "1.2.0-1",
+ "1.1.0-6",
+ "1.1.0-5",
+ "1.1.0-4",
+ "1.1.0-3",
+ "1.1.0-2",
+ "1.1.0-1"
+ ]
+ },
+ "libsrtp2": {
+ "dependency_names": [
+ "libsrtp2"
+ ],
+ "versions": [
+ "2.5.0-1",
+ "2.4.2-1",
+ "2.4.0-1",
+ "2.2.0-1"
+ ]
+ },
+ "libssh2": {
+ "dependency_names": [
+ "libssh2"
+ ],
+ "versions": [
+ "1.10.0-5",
+ "1.10.0-4",
+ "1.10.0-3",
+ "1.10.0-2",
+ "1.10.0-1"
+ ]
+ },
+ "libtiff": {
+ "dependency_names": [
+ "libtiff-4"
+ ],
+ "versions": [
+ "4.5.1-1",
+ "4.5.0-3",
+ "4.5.0-2",
+ "4.5.0-1",
+ "4.4.0-3",
+ "4.4.0-2",
+ "4.4.0-1",
+ "4.1.0-5",
+ "4.1.0-4",
+ "4.1.0-3",
+ "4.1.0-2",
+ "4.1.0-1"
+ ]
+ },
+ "libtirpc": {
+ "dependency_names": [
+ "libtirpc"
+ ],
+ "versions": [
+ "1.3.3-1"
+ ]
+ },
+ "libtomcrypt": {
+ "dependency_names": [
+ "libtomcrypt"
+ ],
+ "versions": [
+ "1.18.2-1",
+ "1.17-1"
+ ]
+ },
+ "libupnp": {
+ "dependency_names": [
+ "libupnp"
+ ],
+ "versions": [
+ "1.14.17-1",
+ "1.14.15-1",
+ "1.14.14-2",
+ "1.14.14-1",
+ "1.14.13-1",
+ "1.14.12-2",
+ "1.14.12-1"
+ ]
+ },
+ "liburing": {
+ "dependency_names": [
+ "liburing"
+ ],
+ "versions": [
+ "2.3-3",
+ "2.3-2",
+ "2.3-1",
+ "2.2-2",
+ "2.2-1",
+ "2.1-1",
+ "2.0-1"
+ ]
+ },
+ "libusb": {
+ "dependency_names": [
+ "libusb-1.0"
+ ],
+ "versions": [
+ "1.0.26-3",
+ "1.0.26-2",
+ "1.0.26-1"
+ ]
+ },
+ "libuv": {
+ "dependency_names": [
+ "libuv"
+ ],
+ "versions": [
+ "1.44.2-2",
+ "1.44.2-1",
+ "1.44.1-1",
+ "1.43.0-1",
+ "1.42.0-1",
+ "1.41.0-1",
+ "1.18.0-3",
+ "1.18.0-2",
+ "1.18.0-1"
+ ]
+ },
+ "libwebsockets": {
+ "dependency_names": [
+ "libwebsockets"
+ ],
+ "versions": [
+ "4.3.2-3",
+ "4.3.2-2",
+ "4.3.2-1",
+ "4.0.21-2",
+ "4.0.21-1",
+ "4.0.13-1"
+ ]
+ },
+ "libxcursor": {
+ "dependency_names": [
+ "xcursor"
+ ],
+ "versions": [
+ "1.2.1-1"
+ ]
+ },
+ "libxext": {
+ "dependency_names": [
+ "xext"
+ ],
+ "versions": [
+ "1.3.4-1"
+ ]
+ },
+ "libxinerama": {
+ "dependency_names": [
+ "xinerama"
+ ],
+ "versions": [
+ "1.1.4-1"
+ ]
+ },
+ "libxml2": {
+ "dependency_names": [
+ "libxml-2.0"
+ ],
+ "versions": [
+ "2.11.4-1",
+ "2.11.1-1",
+ "2.10.4-1",
+ "2.10.3-4",
+ "2.10.3-3",
+ "2.10.3-2",
+ "2.10.3-1",
+ "2.10.2-2",
+ "2.10.2-1",
+ "2.9.14-1",
+ "2.9.7-14",
+ "2.9.7-13",
+ "2.9.7-12",
+ "2.9.7-11",
+ "2.9.7-10",
+ "2.9.7-9",
+ "2.9.7-8",
+ "2.9.7-7",
+ "2.9.7-6",
+ "2.9.7-5",
+ "2.9.7-4",
+ "2.9.7-3",
+ "2.9.7-2",
+ "2.9.7-1",
+ "2.9.2-5",
+ "2.9.2-4",
+ "2.9.2-2"
+ ]
+ },
+ "libxmlpp": {
+ "dependency_names": [
+ "libxml++"
+ ],
+ "versions": [
+ "5.0.3-1",
+ "5.0.2-2",
+ "5.0.2-1",
+ "5.0.1-1",
+ "3.0.1-2",
+ "3.0.1-1"
+ ]
+ },
+ "libxrandr": {
+ "dependency_names": [
+ "xrandr"
+ ],
+ "versions": [
+ "1.5.2-1"
+ ]
+ },
+ "libxrender": {
+ "dependency_names": [
+ "xrender"
+ ],
+ "versions": [
+ "0.9.10-1"
+ ]
+ },
+ "libxslt": {
+ "dependency_names": [
+ "libxslt",
+ "libexslt"
+ ],
+ "program_names": [
+ "xsltproc"
+ ],
+ "versions": [
+ "1.1.38-1",
+ "1.1.37-4",
+ "1.1.37-3",
+ "1.1.37-2",
+ "1.1.37-1",
+ "1.1.36-1",
+ "1.1.35-1",
+ "1.1.34-1"
+ ]
+ },
+ "libxv": {
+ "dependency_names": [
+ "xv"
+ ],
+ "versions": [
+ "1.0.11-1"
+ ]
+ },
+ "libxxf86vm": {
+ "dependency_names": [
+ "xxf86vm"
+ ],
+ "versions": [
+ "1.1.4-1"
+ ]
+ },
+ "libyaml": {
+ "dependency_names": [
+ "yaml-0.1"
+ ],
+ "versions": [
+ "0.2.5-1"
+ ]
+ },
+ "lmdb": {
+ "dependency_names": [
+ "lmdb"
+ ],
+ "versions": [
+ "0.9.29-3",
+ "0.9.29-2",
+ "0.9.29-1"
+ ],
+ "program_names": [
+ "mdb_stat",
+ "mdb_copy",
+ "mdb_dump",
+ "mdb_load"
+ ]
+ },
+ "lua": {
+ "dependency_names": [
+ "lua-5.4",
+ "lua"
+ ],
+ "versions": [
+ "5.4.6-1",
+ "5.4.4-1",
+ "5.4.3-2",
+ "5.4.3-1",
+ "5.3.6-2",
+ "5.3.6-1",
+ "5.3.0-6",
+ "5.3.0-5",
+ "5.3.0-4",
+ "5.3.0-2"
+ ]
+ },
+ "ludocode-mpack": {
+ "dependency_names": [
+ "ludocode-mpack"
+ ],
+ "versions": [
+ "1.1-1",
+ "1.0-1"
+ ]
+ },
+ "lz4": {
+ "dependency_names": [
+ "liblz4"
+ ],
+ "versions": [
+ "1.9.4-2",
+ "1.9.4-1",
+ "1.9.3-1",
+ "1.9.2-1"
+ ]
+ },
+ "lzo2": {
+ "dependency_names": [
+ "lzo2"
+ ],
+ "versions": [
+ "2.10-4",
+ "2.10-3",
+ "2.10-2",
+ "2.10-1"
+ ]
+ },
+ "m4": {
+ "versions": [
+ "1.4.19-1"
+ ],
+ "program_names": [
+ "m4"
+ ]
+ },
+ "magic_enum": {
+ "versions": [
+ "0.8.2-1",
+ "0.8.1-1"
+ ],
+ "dependency_names": [
+ "magic_enum"
+ ]
+ },
+ "mdds": {
+ "dependency_names": [
+ "mdds-2.0"
+ ],
+ "versions": [
+ "2.0.1-1",
+ "1.6.0-2",
+ "1.6.0-1"
+ ]
+ },
+ "microsoft-gsl": {
+ "dependency_names": [
+ "microsoft_gsl"
+ ],
+ "versions": [
+ "4.0.0-1",
+ "3.1.0-1",
+ "2.0.0-1"
+ ]
+ },
+ "miniz": {
+ "dependency_names": [
+ "miniz"
+ ],
+ "versions": [
+ "3.0.2-1",
+ "3.0.1-1",
+ "2.2.0-1",
+ "2.1.0-2",
+ "2.1.0-1"
+ ]
+ },
+ "minizip-ng": {
+ "dependency_names": [
+ "minizip"
+ ],
+ "versions": [
+ "4.0.0-2",
+ "4.0.0-1",
+ "3.0.10-1",
+ "3.0.8-1",
+ "3.0.7-1",
+ "3.0.6-1"
+ ]
+ },
+ "mocklibc": {
+ "versions": [
+ "1.0-2"
+ ]
+ },
+ "mpdecimal": {
+ "dependency_names": [
+ "mpdec",
+ "mpdecpp"
+ ],
+ "versions": [
+ "2.5.1-3",
+ "2.5.1-2",
+ "2.5.1-1",
+ "2.5.0-2",
+ "2.5.0-1"
+ ]
+ },
+ "msgpackc-cxx": {
+ "dependency_names": [
+ "msgpackc-cxx"
+ ],
+ "versions": [
+ "5.0.0-1"
+ ]
+ },
+ "mt32emu": {
+ "dependency_names": [
+ "mt32emu"
+ ],
+ "versions": [
+ "2.7.0-1",
+ "2.6.1-1",
+ "2.5.3-1",
+ "2.5.0-1",
+ "2.4.2-2",
+ "2.4.2-1"
+ ]
+ },
+ "muellan-clipp": {
+ "versions": [
+ "1.2.3-1"
+ ]
+ },
+ "netstring-c": {
+ "dependency_names": [
+ "netstring-c"
+ ],
+ "versions": [
+ "0.0.0-3",
+ "0.0.0-2",
+ "0.0.0-1"
+ ]
+ },
+ "nlohmann_json": {
+ "dependency_names": [
+ "nlohmann_json"
+ ],
+ "versions": [
+ "3.11.2-1",
+ "3.10.5-1",
+ "3.9.1-1",
+ "3.7.0-1",
+ "3.4.0-2",
+ "3.4.0-1",
+ "3.3.0-1"
+ ]
+ },
+ "nng": {
+ "dependency_names": [
+ "nng"
+ ],
+ "versions": [
+ "1.5.2-2",
+ "1.5.2-1",
+ "1.3.2-2",
+ "1.3.2-1"
+ ]
+ },
+ "nonstd-any-lite": {
+ "versions": [
+ "0.2.0-1"
+ ]
+ },
+ "nonstd-byte-lite": {
+ "versions": [
+ "0.2.0-1"
+ ]
+ },
+ "nonstd-expected-lite": {
+ "dependency_names": [
+ "expected-lite"
+ ],
+ "versions": [
+ "0.3.0-2",
+ "0.3.0-1"
+ ]
+ },
+ "nonstd-observer-ptr-lite": {
+ "versions": [
+ "0.4.0-1"
+ ]
+ },
+ "nonstd-optional-lite": {
+ "versions": [
+ "3.2.0-1"
+ ]
+ },
+ "nonstd-span-lite": {
+ "versions": [
+ "0.5.0-1"
+ ]
+ },
+ "nonstd-status-value-lite": {
+ "versions": [
+ "1.1.0-1"
+ ]
+ },
+ "nonstd-string-view-lite": {
+ "versions": [
+ "1.3.0-1"
+ ]
+ },
+ "nowide": {
+ "dependency_names": [
+ "nowide"
+ ],
+ "versions": [
+ "11.2.0-1"
+ ]
+ },
+ "oatpp": {
+ "dependency_names": [
+ "oatpp",
+ "oatpp-test"
+ ],
+ "versions": [
+ "1.3.0-2",
+ "1.3.0-1"
+ ]
+ },
+ "oatpp-openssl": {
+ "dependency_names": [
+ "oatpp-openssl"
+ ],
+ "versions": [
+ "1.3.0-1"
+ ]
+ },
+ "oatpp-sqlite": {
+ "dependency_names": [
+ "oatpp-sqlite"
+ ],
+ "versions": [
+ "1.3.0-1"
+ ]
+ },
+ "oatpp-swagger": {
+ "dependency_names": [
+ "oatpp-swagger"
+ ],
+ "versions": [
+ "1.3.0-1"
+ ]
+ },
+ "oatpp-websocket": {
+ "dependency_names": [
+ "oatpp-websocket"
+ ],
+ "versions": [
+ "1.3.0-1"
+ ]
+ },
+ "ogg": {
+ "dependency_names": [
+ "ogg"
+ ],
+ "versions": [
+ "1.3.5-5",
+ "1.3.5-4",
+ "1.3.5-3",
+ "1.3.5-2",
+ "1.3.5-1",
+ "1.3.2-7",
+ "1.3.2-6",
+ "1.3.2-5",
+ "1.3.2-4",
+ "1.3.2-2"
+ ]
+ },
+ "onqtam-doctest": {
+ "versions": [
+ "2.4.0-1",
+ "2.3.7-1"
+ ]
+ },
+ "openal-soft": {
+ "dependency_names": [
+ "openal"
+ ],
+ "versions": [
+ "1.23.0-1",
+ "1.22.2-8",
+ "1.22.2-7",
+ "1.22.2-6",
+ "1.22.2-5",
+ "1.22.2-4",
+ "1.22.2-3",
+ "1.22.2-2",
+ "1.22.2-1",
+ "1.21.0-1"
+ ]
+ },
+ "opencl-headers": {
+ "dependency_names": [
+ "opencl-headers"
+ ],
+ "versions": [
+ "2023.04.17-1",
+ "2022.05.18-1",
+ "2021.06.30-1"
+ ]
+ },
+ "openh264": {
+ "dependency_names": [
+ "openh264"
+ ],
+ "versions": [
+ "2.3.1-1",
+ "1.7.0-1"
+ ]
+ },
+ "openssl": {
+ "dependency_names": [
+ "libcrypto",
+ "libssl",
+ "openssl"
+ ],
+ "versions": [
+ "3.0.8-1",
+ "3.0.7-2",
+ "3.0.7-1",
+ "3.0.2-1",
+ "1.1.1l-3",
+ "1.1.1l-2",
+ "1.1.1l-1",
+ "1.1.1k-2",
+ "1.1.1k-1"
+ ]
+ },
+ "opus": {
+ "dependency_names": [
+ "opus"
+ ],
+ "versions": [
+ "1.4-1"
+ ]
+ },
+ "orcus": {
+ "dependency_names": [
+ "liborcus-0.17"
+ ],
+ "versions": [
+ "0.17.2-3",
+ "0.17.2-2",
+ "0.17.2-1"
+ ]
+ },
+ "orocos_kdl": {
+ "dependency_names": [
+ "orocos-kdl"
+ ],
+ "versions": [
+ "1.5.1-1"
+ ]
+ },
+ "pcg": {
+ "versions": [
+ "0.98.1-2",
+ "0.98.1-1"
+ ]
+ },
+ "pcre": {
+ "dependency_names": [
+ "libpcre"
+ ],
+ "versions": [
+ "8.45-3",
+ "8.45-2",
+ "8.45-1",
+ "8.37-4",
+ "8.37-3",
+ "8.37-2",
+ "8.37-1"
+ ]
+ },
+ "pcre2": {
+ "dependency_names": [
+ "libpcre2-8",
+ "libpcre2-16",
+ "libpcre2-32",
+ "libpcre2-posix"
+ ],
+ "versions": [
+ "10.42-5",
+ "10.42-4",
+ "10.42-3",
+ "10.42-2",
+ "10.42-1",
+ "10.40-3",
+ "10.40-2",
+ "10.40-1",
+ "10.39-3",
+ "10.39-2",
+ "10.39-1",
+ "10.23-1"
+ ]
+ },
+ "physfs": {
+ "dependency_names": [
+ "physfs"
+ ],
+ "versions": [
+ "3.2.0-2",
+ "3.2.0-1"
+ ]
+ },
+ "pixman": {
+ "dependency_names": [
+ "pixman-1"
+ ],
+ "versions": [
+ "0.42.2-1"
+ ]
+ },
+ "pkgconf": {
+ "dependency_names": [
+ "libpkgconf"
+ ],
+ "versions": [
+ "1.9.3-2",
+ "1.9.3-1",
+ "1.9.2-1",
+ "1.9.0-1"
+ ]
+ },
+ "protobuf": {
+ "dependency_names": [
+ "protobuf-lite",
+ "protobuf",
+ "protoc"
+ ],
+ "program_names": [
+ "protoc"
+ ],
+ "versions": [
+ "3.21.12-4",
+ "3.21.12-3",
+ "3.21.12-2",
+ "3.21.12-1",
+ "3.21.9-1",
+ "3.20.1-1",
+ "3.20.0-1",
+ "3.12.2-2",
+ "3.12.2-1",
+ "3.5.1-3",
+ "3.5.1-2",
+ "3.5.0-4",
+ "3.5.0-3",
+ "3.5.0-2"
+ ]
+ },
+ "protobuf-c": {
+ "dependency_names": [
+ "libprotobuf-c"
+ ],
+ "versions": [
+ "1.4.1-3",
+ "1.4.1-2",
+ "1.4.1-1",
+ "1.3.0-1"
+ ]
+ },
+ "pugixml": {
+ "dependency_names": [
+ "pugixml"
+ ],
+ "versions": [
+ "1.13-3",
+ "1.13-2",
+ "1.13-1",
+ "1.12.1-1",
+ "1.12-1",
+ "1.11.4-1"
+ ]
+ },
+ "pybind11": {
+ "dependency_names": [
+ "pybind11"
+ ],
+ "versions": [
+ "2.10.4-1",
+ "2.10.3-1",
+ "2.10.0-1",
+ "2.9.0-1",
+ "2.6.1-1",
+ "2.6.0-1",
+ "2.3.0-2",
+ "2.3.0-1",
+ "2.2.4-1",
+ "2.2.3-1",
+ "2.2.2-1"
+ ]
+ },
+ "qarchive": {
+ "dependency_names": [
+ "qarchive"
+ ],
+ "versions": [
+ "2.2.6-1",
+ "2.2.4-1",
+ "2.2.3-1",
+ "2.2.2-1",
+ "2.2.1-2",
+ "2.2.1-1",
+ "2.2.0-1",
+ "2.0.2-1"
+ ]
+ },
+ "quazip": {
+ "dependency_names": [
+ "quazip"
+ ],
+ "versions": [
+ "1.3-1",
+ "0.7.3-1"
+ ]
+ },
+ "rang": {
+ "dependency_names": [
+ "rang"
+ ],
+ "versions": [
+ "3.2-1",
+ "2.0-1"
+ ]
+ },
+ "range-v3": {
+ "dependency_names": [
+ "range-v3"
+ ],
+ "versions": [
+ "0.12.0-2",
+ "0.12.0-1",
+ "0.11.0-1",
+ "0.10.0-1",
+ "0.3.6-1"
+ ]
+ },
+ "rapidjson": {
+ "dependency_names": [
+ "rapidjson"
+ ],
+ "versions": [
+ "1.1.0-2",
+ "1.1.0-1"
+ ]
+ },
+ "rdkafka": {
+ "dependency_names": [
+ "rdkafka",
+ "rdkafka++"
+ ],
+ "versions": [
+ "2.1.0-1",
+ "1.9.2-5",
+ "1.9.2-4",
+ "1.9.2-3",
+ "1.9.2-2",
+ "1.9.2-1",
+ "1.9.0-2",
+ "1.9.0-1",
+ "1.8.2-1",
+ "1.7.0-1",
+ "1.5.2-1",
+ "1.5.0-1",
+ "1.4.4-1",
+ "1.4.0-1"
+ ]
+ },
+ "re2": {
+ "dependency_names": [
+ "re2"
+ ],
+ "versions": [
+ "20220401-1",
+ "20201101-1"
+ ]
+ },
+ "reflex": {
+ "dependency_names": [
+ "reflex"
+ ],
+ "program_names": [
+ "reflex"
+ ],
+ "versions": [
+ "3.2.11-1",
+ "3.2.7-1",
+ "3.2.3-1",
+ "3.0.1-2",
+ "3.0.1-1"
+ ]
+ },
+ "robin-map": {
+ "dependency_names": [
+ "robin-map"
+ ],
+ "versions": [
+ "1.2.1-1"
+ ]
+ },
+ "rtaudio": {
+ "dependency_names": [
+ "rtaudio"
+ ],
+ "versions": [
+ "5.2.0-1"
+ ]
+ },
+ "rubberband": {
+ "dependency_names": [
+ "rubberband"
+ ],
+ "versions": [
+ "2.0.2-1"
+ ]
+ },
+ "rxcpp": {
+ "dependency_names": [
+ "rxcpp"
+ ],
+ "versions": [
+ "4.1.1-1",
+ "4.1.0-1"
+ ]
+ },
+ "sdl2": {
+ "dependency_names": [
+ "sdl2",
+ "sdl2main",
+ "sdl2_test"
+ ],
+ "versions": [
+ "2.26.5-5",
+ "2.26.5-4",
+ "2.26.5-3",
+ "2.26.5-2",
+ "2.26.5-1",
+ "2.26.0-2",
+ "2.26.0-1",
+ "2.24.2-1",
+ "2.24.1-4",
+ "2.24.1-3",
+ "2.24.1-2",
+ "2.24.1-1",
+ "2.24.0-5",
+ "2.24.0-4",
+ "2.24.0-3",
+ "2.24.0-2",
+ "2.24.0-1",
+ "2.0.20-6",
+ "2.0.20-5",
+ "2.0.20-4",
+ "2.0.20-3",
+ "2.0.20-2",
+ "2.0.20-1",
+ "2.0.18-2",
+ "2.0.18-1",
+ "2.0.12-3",
+ "2.0.12-2",
+ "2.0.12-1",
+ "2.0.3-6",
+ "2.0.3-5",
+ "2.0.3-4"
+ ]
+ },
+ "sdl2_image": {
+ "dependency_names": [
+ "sdl2_image"
+ ],
+ "versions": [
+ "2.6.3-2",
+ "2.6.3-1",
+ "2.6.2-1",
+ "2.0.5-3",
+ "2.0.5-2",
+ "2.0.5-1"
+ ]
+ },
+ "sdl2_mixer": {
+ "dependency_names": [
+ "sdl2_mixer"
+ ],
+ "versions": [
+ "2.6.2-3",
+ "2.6.2-2",
+ "2.6.2-1",
+ "2.0.4-3",
+ "2.0.4-2",
+ "2.0.4-1"
+ ]
+ },
+ "sdl2_net": {
+ "dependency_names": [
+ "sdl2_net"
+ ],
+ "versions": [
+ "2.2.0-1",
+ "2.0.1-4",
+ "2.0.1-3",
+ "2.0.1-2",
+ "2.0.1-1"
+ ]
+ },
+ "sdl2_ttf": {
+ "dependency_names": [
+ "sdl2_ttf"
+ ],
+ "versions": [
+ "2.20.1-2",
+ "2.20.1-1",
+ "2.0.12-3",
+ "2.0.12-2",
+ "2.0.12-1"
+ ]
+ },
+ "sds": {
+ "dependency_names": [
+ "sds"
+ ],
+ "versions": [
+ "2.0.0-2",
+ "2.0.0-1"
+ ]
+ },
+ "sergiusthebest-plog": {
+ "versions": [
+ "1.1.4-1"
+ ]
+ },
+ "sfml": {
+ "dependency_names": [
+ "sfml"
+ ],
+ "versions": [
+ "2.5.1-4",
+ "2.5.1-3",
+ "2.5.1-2",
+ "2.5.1-1"
+ ]
+ },
+ "simdjson": {
+ "dependency_names": [
+ "simdjson"
+ ],
+ "versions": [
+ "3.1.1-1"
+ ]
+ },
+ "slirp": {
+ "dependency_names": [
+ "slirp"
+ ],
+ "versions": [
+ "4.7.0-1",
+ "4.6.1-2",
+ "4.6.1-1"
+ ]
+ },
+ "spdlog": {
+ "dependency_names": [
+ "spdlog"
+ ],
+ "versions": [
+ "1.11.0-2",
+ "1.11.0-1",
+ "1.10.0-3",
+ "1.10.0-2",
+ "1.10.0-1",
+ "1.9.2-1",
+ "1.8.5-1",
+ "1.8.2-1",
+ "1.8.1-1",
+ "1.8.0-1",
+ "1.4.2-1",
+ "1.3.1-1",
+ "1.1.0-1",
+ "0.17.0-2",
+ "0.17.0-1",
+ "0.16.3-1",
+ "0.11.0-1"
+ ]
+ },
+ "speexdsp": {
+ "dependency_names": [
+ "speexdsp"
+ ],
+ "versions": [
+ "1.2.1-7",
+ "1.2.1-6",
+ "1.2.1-5",
+ "1.2.1-4",
+ "1.2.1-3",
+ "1.2.1-2",
+ "1.2.1-1",
+ "1.2.0-1"
+ ]
+ },
+ "spng": {
+ "dependency_names": [
+ "spng"
+ ],
+ "versions": [
+ "0.7.4-1",
+ "0.7.2-1",
+ "0.7.0-1",
+ "0.5.0-1",
+ "0.4.5-1",
+ "0.4.4-1",
+ "0.4.3-1",
+ "0.4.2-2",
+ "0.4.2-1"
+ ]
+ },
+ "sqlite3": {
+ "dependency_names": [
+ "sqlite3"
+ ],
+ "versions": [
+ "3.42.0-1",
+ "3.41.2-2",
+ "3.41.2-1",
+ "3.41.1-1",
+ "3.41.0-1",
+ "3.40.0-1",
+ "3.39.4-2",
+ "3.39.4-1",
+ "3.39.3-1",
+ "3.38.0-1",
+ "3.34.1-1"
+ ]
+ },
+ "stduuid": {
+ "dependency_names": [
+ "stduuid"
+ ],
+ "versions": [
+ "1.2.3-1"
+ ]
+ },
+ "tabulate": {
+ "dependency_names": [
+ "tabulate"
+ ],
+ "versions": [
+ "1.4-2",
+ "1.4-1"
+ ]
+ },
+ "taglib": {
+ "dependency_names": [
+ "taglib"
+ ],
+ "versions": [
+ "1.13-3",
+ "1.13-2",
+ "1.13-1",
+ "1.12-3",
+ "1.12-2",
+ "1.12-1"
+ ]
+ },
+ "tclap": {
+ "dependency_names": [
+ "tclap"
+ ],
+ "versions": [
+ "1.2.4-1",
+ "1.2.2-1",
+ "1.2.1-1"
+ ]
+ },
+ "termbox": {
+ "dependency_names": [
+ "termbox"
+ ],
+ "versions": [
+ "1.1.2-1"
+ ]
+ },
+ "theora": {
+ "dependency_names": [
+ "theoraenc",
+ "theoradec",
+ "theora"
+ ],
+ "versions": [
+ "1.1.1-4",
+ "1.1.1-3",
+ "1.1.1-2",
+ "1.1.1-1"
+ ]
+ },
+ "tinyfsm": {
+ "dependency_names": [
+ "tinyfsm"
+ ],
+ "versions": [
+ "0.3.3-1"
+ ]
+ },
+ "tinyply": {
+ "dependency_names": [
+ "tinyply"
+ ],
+ "versions": [
+ "2.3.4-1",
+ "2.2-2",
+ "2.2-1",
+ "2.1-2",
+ "2.1-1",
+ "2.0-1"
+ ]
+ },
+ "tinyxml2": {
+ "dependency_names": [
+ "tinyxml2"
+ ],
+ "versions": [
+ "9.0.0-1",
+ "7.0.1-1"
+ ]
+ },
+ "tl-expected": {
+ "dependency_names": [
+ "tl-expected"
+ ],
+ "versions": [
+ "1.0.0-1"
+ ]
+ },
+ "tl-optional": {
+ "dependency_names": [
+ "tl-optional"
+ ],
+ "versions": [
+ "1.0.0-1"
+ ]
+ },
+ "tomlplusplus": {
+ "dependency_names": [
+ "tomlplusplus"
+ ],
+ "versions": [
+ "3.3.0-1",
+ "3.2.0-1",
+ "3.1.0-1",
+ "3.0.0-1",
+ "2.5.0-1"
+ ]
+ },
+ "tracy": {
+ "dependency_names": [
+ "tracy"
+ ],
+ "versions": [
+ "0.9.1-1",
+ "0.9-1",
+ "0.8.2.1-1",
+ "0.8.1-1"
+ ]
+ },
+ "trompeloeil": {
+ "versions": [
+ "39-1",
+ "38-1"
+ ]
+ },
+ "tronkko-dirent": {
+ "versions": [
+ "1.23.2-1"
+ ]
+ },
+ "turtle": {
+ "versions": [
+ "1.3.2-1",
+ "1.3.1-1"
+ ]
+ },
+ "uchardet": {
+ "dependency_names": [
+ "uchardet"
+ ],
+ "versions": [
+ "0.0.8-1",
+ "0.0.7-3",
+ "0.0.7-2",
+ "0.0.7-1"
+ ]
+ },
+ "unit-system": {
+ "dependency_names": [
+ "unit-system"
+ ],
+ "versions": [
+ "0.7.1-1",
+ "0.7.0-1",
+ "0.6.1-1",
+ "0.5.2-1",
+ "0.5.0-1"
+ ]
+ },
+ "unittest-cpp": {
+ "dependency_names": [
+ "unittest-cpp"
+ ],
+ "versions": [
+ "2.0.0-2",
+ "2.0.0-1"
+ ]
+ },
+ "unity": {
+ "dependency_names": [
+ "unity"
+ ],
+ "versions": [
+ "2.5.2-1"
+ ]
+ },
+ "utf8proc": {
+ "dependency_names": [
+ "libutf8proc"
+ ],
+ "versions": [
+ "2.8.0-1",
+ "2.7.0-1",
+ "2.6.0-1"
+ ]
+ },
+ "utfcpp": {
+ "dependency_names": [
+ "utfcpp"
+ ],
+ "versions": [
+ "3.2.3-1",
+ "3.2.2-1",
+ "3.2.1-1",
+ "2.3.5-1"
+ ]
+ },
+ "uthash": {
+ "dependency_names": [
+ "uthash"
+ ],
+ "versions": [
+ "2.3.0-1"
+ ]
+ },
+ "vorbis": {
+ "dependency_names": [
+ "vorbis",
+ "vorbisfile",
+ "vorbisenc"
+ ],
+ "versions": [
+ "1.3.7-4",
+ "1.3.7-3",
+ "1.3.7-2",
+ "1.3.7-1",
+ "1.3.7-0",
+ "1.3.5-8",
+ "1.3.5-7",
+ "1.3.5-6",
+ "1.3.5-5",
+ "1.3.5-4",
+ "1.3.5-2"
+ ]
+ },
+ "vulkan-headers": {
+ "versions": [
+ "1.2.203-1",
+ "1.2.158-2",
+ "1.2.158-1",
+ "1.2.142-1"
+ ]
+ },
+ "vulkan-validationlayers": {
+ "versions": [
+ "1.2.158-2",
+ "1.2.158-1"
+ ]
+ },
+ "wayland": {
+ "dependency_names": [
+ "wayland-client",
+ "wayland-cursor",
+ "wayland-egl",
+ "wayland-server"
+ ],
+ "versions": [
+ "1.20.0-1"
+ ]
+ },
+ "wayland-protocols": {
+ "dependency_names": [
+ "wayland-protocols"
+ ],
+ "versions": [
+ "1.24-1"
+ ]
+ },
+ "websocketpp": {
+ "dependency_names": [
+ "websocketpp"
+ ],
+ "versions": [
+ "0.8.2-1"
+ ]
+ },
+ "wren": {
+ "dependency_names": [
+ "wren"
+ ],
+ "versions": [
+ "0.4.0-1",
+ "0.3.0-1"
+ ]
+ },
+ "xtensor": {
+ "dependency_names": [
+ "xtensor"
+ ],
+ "versions": [
+ "0.21.5-1"
+ ]
+ },
+ "xtl": {
+ "dependency_names": [
+ "xtl"
+ ],
+ "versions": [
+ "0.6.12-1"
+ ]
+ },
+ "xxhash": {
+ "dependency_names": [
+ "libxxhash"
+ ],
+ "versions": [
+ "0.8.1-2",
+ "0.8.1-1",
+ "0.8.0-2",
+ "0.8.0-1",
+ "0.6.5-1"
+ ]
+ },
+ "yajl": {
+ "dependency_names": [
+ "yajl"
+ ],
+ "versions": [
+ "2.1.0-5",
+ "2.1.0-4",
+ "2.1.0-3",
+ "2.1.0-2",
+ "2.1.0-1"
+ ]
+ },
+ "zlib": {
+ "dependency_names": [
+ "zlib"
+ ],
+ "versions": [
+ "1.2.13-4",
+ "1.2.13-3",
+ "1.2.13-2",
+ "1.2.13-1",
+ "1.2.12-1",
+ "1.2.11-6",
+ "1.2.11-5",
+ "1.2.11-4",
+ "1.2.11-3",
+ "1.2.11-2",
+ "1.2.11-1",
+ "1.2.8-8",
+ "1.2.8-7",
+ "1.2.8-6",
+ "1.2.8-4",
+ "1.2.8-2"
+ ]
+ },
+ "zstd": {
+ "dependency_names": [
+ "libzstd"
+ ],
+ "versions": [
+ "1.5.4-1",
+ "1.4.5-1",
+ "1.3.3-2",
+ "1.3.3-1"
+ ]
+ }
+}
diff --git a/test_holyparser.cpp b/test_holyparser.cpp
new file mode 100644
index 0000000..4d2ae38
--- /dev/null
+++ b/test_holyparser.cpp
@@ -0,0 +1,325 @@
+#include <holyparser.hpp>
+
+#include <fmt/core.h>
+#include <fmt/std.h>
+
+#include <chrono>
+#include <functional>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#define ANSI_RESET "\033[0m"
+#define ANSI_CYAN "\033[36m"
+#define ANSI_GREEN "\033[32m"
+#define ANSI_RED "\033[31m"
+
+using namespace holyparser;
+using namespace std::literals;
+
+// clang-format off
+#define TEST(Suite, Name) { #Suite ": " #Name, []() -> std::string {
+#define TEST_END return "";}},
+// clang-format on
+
+#define ASSERT_EQ(a, b) \
+ if ((a) != (b)) return fmt::format("ASSERT_EQ: {} != {}, line {}", #a, #b, __LINE__)
+#define ASSERT_EQS(a, b) \
+ if ((a) != (b)) return fmt::format("ASSERT_EQ: {} != {}, line {}", a, b, __LINE__)
+#define ASSERT_NEQ(a, b) \
+ if ((a) == (b)) return fmt::format("ASSERT_EQ: {} != {}, line {}", #a, #b, __LINE__)
+#define ASSERT_TRUE(a) \
+ if (!(a)) return fmt::format("ASSERT_TRUE: {}, line {}", #a, __LINE__)
+
+std::vector<std::pair<char const *, std::function<std::string(void)>>> const tests {
+
+ TEST(Lexer, Operators) {
+ HolyLexer lexer("+-*/ + - * / % ` << >>&|^~ < <= >= > || && ^^ ! == != ++ --");
+Token const tokens[] = {
+ Token(TokenType::Add),
+ Token(TokenType::Subtract),
+ Token(TokenType::Multiply),
+ Token(TokenType::Divide),
+ Token(TokenType::Add),
+ Token(TokenType::Subtract),
+ Token(TokenType::Multiply),
+ Token(TokenType::Divide),
+ Token(TokenType::Modulo),
+ Token(TokenType::Pow),
+ Token(TokenType::LeftBitShift),
+ Token(TokenType::RightBitShift),
+ Token(TokenType::BitwiseAnd),
+ Token(TokenType::BitwiseOr),
+ Token(TokenType::BitwiseXOR),
+ Token(TokenType::OnesComplement),
+ Token(TokenType::LessThan),
+ Token(TokenType::LessThanEquals),
+ Token(TokenType::GreaterThanEquals),
+ Token(TokenType::GreaterThan),
+ Token(TokenType::Or),
+ Token(TokenType::And),
+ Token(TokenType::XOR),
+ Token(TokenType::Not),
+ Token(TokenType::Equals),
+ Token(TokenType::NotEquals),
+ Token(TokenType::Increment),
+ Token(TokenType::Decrement),
+ Token(TokenType::EndOfFile),
+};
+Token cur = lexer.next();
+for (auto tok : tokens) {
+ ASSERT_EQ(messages.contains_errors(), false);
+ if (tok != cur)
+ return fmt::format("Expected token {}, got {}", tok.pretty(), cur.pretty());
+ cur = lexer.next();
+}
+}
+TEST_END
+
+TEST(Lexer, Literals)
+{
+ HolyLexer lexer("identifier 123 123.456 $BK$ #include \"Main.HC\" 'asdf' PUSHFD"sv);
+ Token const tokens[] = {
+ Token(TokenType::Identifier, "identifier"),
+ Token(TokenType::IntegerLiteral, 123),
+ Token(TokenType::FloatLiteral, 123.456),
+ Token(TokenType::Preprocessor, "include"),
+ Token(TokenType::StringLiteral, "Main.HC"),
+ Token(TokenType::CharLiteral, "asdf"),
+ Token(TokenType::AssemblyInstruction, "PUSHFD"),
+ };
+
+ Token cur = lexer.next();
+ for (auto tok : tokens) {
+ ASSERT_EQ(messages.contains_errors(), false);
+ if (tok != cur)
+ return fmt::format("Expected token {}, got {}", tok.pretty(), cur.pretty());
+ cur = lexer.next();
+ }
+}
+TEST_END
+
+TEST(Lexer, Symbols)
+{
+ HolyLexer lexer(",.:;(){}[]..."sv);
+
+ Token const tokens[] = {
+ Token(TokenType::Comma),
+ Token(TokenType::Dot),
+ Token(TokenType::Colon),
+ Token(TokenType::Semicolon),
+ Token(TokenType::LParen),
+ Token(TokenType::RParen),
+ Token(TokenType::LSquirly),
+ Token(TokenType::RSquirly),
+ Token(TokenType::LBracket),
+ Token(TokenType::RBracket),
+ Token(TokenType::Range),
+ Token(TokenType::EndOfFile),
+ };
+
+ Token cur = lexer.next();
+ for (auto tok : tokens) {
+ ASSERT_EQ(messages.contains_errors(), false);
+ if (tok != cur)
+ return fmt::format("Expected token {}, got {}", tok.pretty(), cur.pretty());
+ cur = lexer.next();
+ }
+}
+TEST_END
+
+TEST(Lexer, Keywords)
+{
+ HolyLexer lexer(
+ "if else for while do switch case start end public class sizeof goto asm return break"sv);
+
+ Token const tokens[] = {
+ Token(TokenType::If),
+ Token(TokenType::Else),
+ Token(TokenType::For),
+ Token(TokenType::While),
+ Token(TokenType::Do),
+ Token(TokenType::Switch),
+ Token(TokenType::Case),
+ Token(TokenType::Start),
+ Token(TokenType::End),
+ Token(TokenType::Public),
+ Token(TokenType::Class),
+ Token(TokenType::Sizeof),
+ Token(TokenType::Goto),
+ Token(TokenType::Assembly),
+ Token(TokenType::Return),
+ Token(TokenType::Break),
+ Token(TokenType::EndOfFile),
+ };
+
+ Token cur = lexer.next();
+ for (auto tok : tokens) {
+ ASSERT_EQ(messages.contains_errors(), false);
+ if (tok != cur)
+ return fmt::format("Expected token {}, got {}", tok.pretty(), cur.pretty());
+ cur = lexer.next();
+ }
+}
+TEST_END
+
+TEST(Lexer, Full)
+{
+ HolyLexer lexer("U0 Add(U64 a=1, b) {\n"
+ " U64 i = 123;\n"
+ " return a + b + i;\n"
+ "}\n"
+ "\"%d\\\n\", Add(,2);"sv);
+
+ Token const tokens[] = {
+ Token(TokenType::Identifier, "U0"), // Line 1
+ Token(TokenType::Identifier, "Add"),
+ Token(TokenType::LParen),
+ Token(TokenType::Identifier, "U64"),
+ Token(TokenType::Identifier, "a"),
+ Token(TokenType::Set),
+ Token(TokenType::IntegerLiteral, 1),
+ Token(TokenType::Comma),
+ Token(TokenType::Identifier, "b"),
+ Token(TokenType::RParen),
+ Token(TokenType::LSquirly),
+ Token(TokenType::NewLine),
+ Token(TokenType::Identifier, "U64"), // Line 2
+ Token(TokenType::Identifier, "i"),
+ Token(TokenType::Set),
+ Token(TokenType::IntegerLiteral, 123),
+ Token(TokenType::Semicolon),
+ Token(TokenType::NewLine),
+ Token(TokenType::Return), // Line 3
+ Token(TokenType::Identifier, "a"),
+ Token(TokenType::Add),
+ Token(TokenType::Identifier, "b"),
+ Token(TokenType::Add),
+ Token(TokenType::Identifier, "i"),
+ Token(TokenType::Semicolon),
+ Token(TokenType::NewLine),
+ Token(TokenType::RSquirly), // Line 4
+ Token(TokenType::NewLine),
+ Token(TokenType::StringLiteral, "%d\n"), // Line 5
+ Token(TokenType::Comma),
+ Token(TokenType::Identifier, "Add"),
+ Token(TokenType::LParen),
+ Token(TokenType::Comma),
+ Token(TokenType::IntegerLiteral, 2),
+ Token(TokenType::RParen),
+ Token(TokenType::Semicolon),
+
+ Token(TokenType::EndOfFile),
+ };
+
+ Token cur = lexer.next();
+ for (auto tok : tokens) {
+ ASSERT_EQ(messages.contains_errors(), false);
+ if (tok != cur)
+ return fmt::format("Expected token {}, got {}", tok.pretty(), cur.pretty());
+ cur = lexer.next();
+ }
+}
+TEST_END
+
+// I know this is hard to read but I do not want to write recursion.
+TEST(Parser, Factor)
+{
+ HolyLexer lexer("funny"sv);
+ HolyParser parser(lexer);
+ auto node = parser.parse_expression();
+ ASSERT_EQ(messages.contains_errors(), false);
+ ASSERT_NEQ(node, nullptr);
+ ASSERT_EQS(node->node_name(), "FunctionCallOrIdentifierNode");
+
+ lexer = HolyLexer(HolyLexer("func()"sv));
+ HolyParser parser2(lexer);
+ node = parser2.parse_expression();
+ ASSERT_EQ(messages.contains_errors(), false);
+ ASSERT_NEQ(node, nullptr);
+ ASSERT_EQS(node->node_name(), "FunctionCallNode");
+
+ lexer = HolyLexer(HolyLexer("func2(,123)"sv));
+ HolyParser parser3(lexer);
+ node = parser3.parse_expression();
+ ASSERT_EQ(messages.contains_errors(), false);
+ ASSERT_TRUE(node != nullptr);
+ ASSERT_EQS(node->node_name(), "FunctionCallNode");
+ ASSERT_EQ(dynamic_cast<FunctionCallNode *>(node.get())->arguments().size(), 2);
+ ASSERT_EQ(dynamic_cast<FunctionCallNode *>(node.get())->arguments().at(0), nullptr);
+ ASSERT_NEQ(dynamic_cast<FunctionCallNode *>(node.get())->arguments().at(1), nullptr);
+ ASSERT_EQS(dynamic_cast<FunctionCallNode *>(node.get())->arguments().at(1)->node_name(),
+ "LiteralNode");
+}
+TEST_END
+
+TEST(Parser, DotAccess)
+{
+ HolyLexer lexer("a.b");
+ HolyParser parser(lexer);
+ auto node = parser.parse_expression();
+ ASSERT_EQ(messages.contains_errors(), false);
+ ASSERT_NEQ(node, nullptr);
+ ASSERT_EQS(node->node_name(), "AccessNode");
+ ASSERT_NEQ(dynamic_cast<AccessNode *>(node.get())->left(), nullptr);
+ ASSERT_NEQ(dynamic_cast<AccessNode *>(node.get())->right(), nullptr);
+ ASSERT_EQS(dynamic_cast<AccessNode *>(node.get())->left()->node_name(),
+ "FunctionCallOrIdentifierNode");
+ ASSERT_EQS(dynamic_cast<AccessNode *>(node.get())->right()->node_name(),
+ "FunctionCallOrIdentifierNode");
+
+ lexer = HolyLexer("(a.b).c");
+ HolyParser parser2(lexer);
+ node = parser2.parse_expression();
+ ASSERT_EQ(messages.contains_errors(), false);
+ ASSERT_NEQ(node, nullptr);
+ ASSERT_EQS(node->node_name(), "AccessNode");
+ ASSERT_NEQ(dynamic_cast<AccessNode *>(node.get())->left(), nullptr);
+ ASSERT_NEQ(dynamic_cast<AccessNode *>(node.get())->right(), nullptr);
+ ASSERT_EQS(dynamic_cast<AccessNode *>(node.get())->left()->node_name(), "AccessNode");
+ ASSERT_EQS(dynamic_cast<AccessNode *>(node.get())->right()->node_name(),
+ "FunctionCallOrIdentifierNode");
+}
+TEST_END
+
+// clang-format off
+};
+// clang-format on
+
+int main(void)
+{
+ int ret = 0;
+ puts("Running test suite...");
+
+ using namespace std::chrono;
+ auto start = high_resolution_clock::now();
+
+ for (auto test : tests) {
+ fmt::print(ANSI_CYAN "{}", test.first);
+ std::string res;
+ try {
+ res = test.second();
+ } catch (const std::exception &e) {
+ res = e.what();
+ } catch (char const *e) {
+ res = e;
+ }
+ if (res.empty())
+ printf(ANSI_RESET "\033[30G[ " ANSI_GREEN "OK " ANSI_RESET "]\n");
+ else {
+ fmt::print(
+ ANSI_RESET "\033[30G[" ANSI_RED "FAIL" ANSI_RESET "]\nReason: {}\n", res);
+ ret++;
+ }
+ }
+
+ auto end = high_resolution_clock::now();
+ auto duration = duration_cast<microseconds>(end - start);
+
+ fmt::print("Tests: {}/{} {}\n", tests.size() - ret, tests.size(),
+ ret == 0 ? ANSI_GREEN "\033[30GPASSED" ANSI_RESET
+ : ANSI_RED "\033[30GFAILED" ANSI_RESET);
+ fmt::print("Took: {}μs\n", duration.count());
+
+ return ret;
+}