diff options
author | Slendi <slendi@socopon.com> | 2023-07-31 00:08:51 +0300 |
---|---|---|
committer | Slendi <slendi@socopon.com> | 2023-07-31 00:11:16 +0300 |
commit | 86cbf9cb889107c6fd6caea7a4fe791f06ecfc66 (patch) | |
tree | 878fab6988833f84dba74a64ccb5773721d0bf28 |
Initial commit
Signed-off-by: Slendi <slendi@socopon.com>
-rw-r--r-- | .clang-format | 207 | ||||
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | LICENSE.md | 16 | ||||
-rw-r--r-- | holyparser.hpp | 585 | ||||
-rw-r--r-- | meson.build | 73 | ||||
-rw-r--r-- | rpl.cpp | 37 | ||||
-rw-r--r-- | src/holyasm.gperf | 385 | ||||
-rw-r--r-- | src/holylexer.cpp | 492 | ||||
-rw-r--r-- | src/holyparser.cpp | 796 | ||||
-rw-r--r-- | subprojects/fmt.wrap | 13 | ||||
-rw-r--r-- | subprojects/wrapdb.json | 2880 | ||||
-rw-r--r-- | test_holyparser.cpp | 325 |
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', + ) + @@ -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; +} |