From e70d96e4e7df3bc17c66de94948a9ecf31ae045f Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 2 Jun 2024 20:44:05 +0200 Subject: [PATCH] Everywhere: Remove a lot more things we don't need --- .github/CODEOWNERS | 5 - AK/FixedStringBuffer.h | 121 - AK/UBSanitizer.h | 162 - AK/Userspace.h | 79 - Kernel/FileSystem/CustodyBase.cpp | 23 - Kernel/FileSystem/CustodyBase.h | 47 - Kernel/Memory/VirtualAddress.h | 61 - Meta/CMake/code_generators.cmake | 16 - Meta/CMake/libgl_generators.cmake | 14 - Meta/Lagom/CMakeLists.txt | 30 - Meta/Lagom/Contrib/MacPDF/AppDelegate.h | 15 - Meta/Lagom/Contrib/MacPDF/AppDelegate.mm | 47 - Meta/Lagom/Contrib/MacPDF/CMakeLists.txt | 58 - Meta/Lagom/Contrib/MacPDF/CocoaWrapper.h | 12 - Meta/Lagom/Contrib/MacPDF/Info.plist | 41 - Meta/Lagom/Contrib/MacPDF/MacPDFDocument.h | 22 - Meta/Lagom/Contrib/MacPDF/MacPDFDocument.mm | 148 - .../MacPDF/MacPDFOutlineViewDataSource.h | 29 - .../MacPDF/MacPDFOutlineViewDataSource.mm | 121 - Meta/Lagom/Contrib/MacPDF/MacPDFView.h | 36 - Meta/Lagom/Contrib/MacPDF/MacPDFView.mm | 292 -- .../Contrib/MacPDF/MacPDFWindowController.h | 36 - .../Contrib/MacPDF/MacPDFWindowController.mm | 296 -- Meta/Lagom/Contrib/MacPDF/MainMenu.xib | 747 --- Meta/Lagom/Contrib/MacPDF/main.mm | 12 - Meta/Lagom/Fuzzers/FuzzELF.cpp | 16 - Meta/Lagom/Fuzzers/FuzzPDF.cpp | 26 - Meta/Lagom/Fuzzers/fuzzers.cmake | 3 - .../Lagom/Tools/CodeGenerators/CMakeLists.txt | 5 - .../CodeGenerators/GMLCompiler/CMakeLists.txt | 5 - .../Tools/CodeGenerators/GMLCompiler/main.cpp | 446 -- .../CodeGenerators/JSSpecCompiler/AST/AST.cpp | 157 - .../CodeGenerators/JSSpecCompiler/AST/AST.h | 580 --- .../JSSpecCompiler/AST/ASTPrinting.cpp | 198 - .../JSSpecCompiler/CMakeLists.txt | 35 - .../JSSpecCompiler/CompilationPipeline.h | 47 - .../JSSpecCompiler/Compiler/CompilerPass.cpp | 20 - .../JSSpecCompiler/Compiler/CompilerPass.h | 46 - .../Compiler/ControlFlowGraph.cpp | 39 - .../Compiler/ControlFlowGraph.h | 63 - .../Compiler/EnableGraphPointers.h | 69 - .../Compiler/GenericASTPass.cpp | 61 - .../JSSpecCompiler/Compiler/GenericASTPass.h | 45 - .../Compiler/Passes/CFGBuildingPass.cpp | 107 - .../Compiler/Passes/CFGBuildingPass.h | 39 - .../Compiler/Passes/CFGSimplificationPass.cpp | 85 - .../Compiler/Passes/CFGSimplificationPass.h | 39 - .../Passes/DeadCodeEliminationPass.cpp | 84 - .../Compiler/Passes/DeadCodeEliminationPass.h | 45 - .../Compiler/Passes/IfBranchMergingPass.cpp | 97 - .../Compiler/Passes/IfBranchMergingPass.h | 38 - .../Passes/ReferenceResolvingPass.cpp | 61 - .../Compiler/Passes/ReferenceResolvingPass.h | 27 - .../Compiler/Passes/SSABuildingPass.cpp | 454 -- .../Compiler/Passes/SSABuildingPass.h | 91 - .../Compiler/StronglyConnectedComponents.h | 86 - .../JSSpecCompiler/DiagnosticEngine.cpp | 74 - .../JSSpecCompiler/DiagnosticEngine.h | 90 - .../CodeGenerators/JSSpecCompiler/Forward.h | 92 - .../JSSpecCompiler/Function.cpp | 98 - .../CodeGenerators/JSSpecCompiler/Function.h | 162 - .../JSSpecCompiler/Parser/Algorithm.cpp | 53 - .../JSSpecCompiler/Parser/AlgorithmStep.cpp | 60 - .../Parser/AlgorithmStepList.cpp | 87 - .../JSSpecCompiler/Parser/CppASTConverter.cpp | 263 - .../JSSpecCompiler/Parser/CppASTConverter.h | 48 - .../JSSpecCompiler/Parser/Lexer.cpp | 256 - .../JSSpecCompiler/Parser/Lexer.h | 43 - .../JSSpecCompiler/Parser/Specification.cpp | 54 - .../Parser/SpecificationClause.cpp | 127 - .../Parser/SpecificationFunction.cpp | 86 - .../Parser/SpecificationParsing.h | 187 - .../Parser/SpecificationParsingContext.cpp | 46 - .../Parser/SpecificationParsingStep.cpp | 69 - .../JSSpecCompiler/Parser/TextParser.cpp | 868 ---- .../JSSpecCompiler/Parser/TextParser.h | 118 - .../JSSpecCompiler/Parser/Token.h | 124 - .../JSSpecCompiler/Parser/XMLUtils.cpp | 59 - .../JSSpecCompiler/Parser/XMLUtils.h | 22 - .../CodeGenerators/JSSpecCompiler/Printer.h | 48 - .../JSSpecCompiler/Runtime/Cell.h | 30 - .../JSSpecCompiler/Runtime/Object.cpp | 69 - .../JSSpecCompiler/Runtime/Object.h | 151 - .../JSSpecCompiler/Runtime/ObjectType.cpp | 16 - .../JSSpecCompiler/Runtime/ObjectType.h | 31 - .../JSSpecCompiler/Runtime/Realm.cpp | 18 - .../JSSpecCompiler/Runtime/Realm.h | 38 - .../JSSpecCompiler/Tests/simple.cpp | 18 - .../Tests/simple.cpp.expectation | 360 -- .../JSSpecCompiler/Tests/spec-headers.xml | 17 - .../Tests/spec-headers.xml.expectation | 16 - .../Tests/spec-no-new-line-after-dot.xml | 19 - ...spec-no-new-line-after-dot.xml.expectation | 8 - .../Tests/spec-optional-arguments.xml | 12 - .../spec-optional-arguments.xml.expectation | 11 - .../JSSpecCompiler/Tests/spec-parsing.xml | 85 - .../Tests/spec-parsing.xml.expectation | 107 - .../Tests/spec-single-function-simple.xml | 35 - ...pec-single-function-simple.xml.expectation | 23 - .../CodeGenerators/JSSpecCompiler/main.cpp | 173 - .../Tools/CodeGenerators/LibGL/CMakeLists.txt | 1 - .../LibGL/GenerateGLAPIWrapper.cpp | 569 --- Meta/check-newlines-at-eof.py | 6 - Meta/check-style.py | 9 - Meta/gn/secondary/AK/BUILD.gn | 1 - Meta/gn/secondary/Kernel/BUILD.gn | 863 ---- Meta/gn/secondary/Kernel/Prekernel/BUILD.gn | 51 - .../Kernel/generate_version_header.py | 28 - .../secondary/Kernel/post_process_kernel.py | 60 - Meta/gn/secondary/Ladybird/BUILD.gn | 12 - .../Meta/Lagom/Contrib/MacPDF/BUILD.gn | 108 - .../Userland/Libraries/LibC/BUILD.gn | 21 - .../Userland/Libraries/LibC/libc_headers.gni | 118 - .../Userland/Libraries/LibELF/BUILD.gn | 22 - .../Userland/Libraries/LibGL/BUILD.gn | 58 - .../Userland/Libraries/LibGLSL/BUILD.gn | 13 - .../Userland/Libraries/LibGPU/BUILD.gn | 18 - .../Userland/Libraries/LibGUI/BUILD.gn | 24 - .../Userland/Libraries/LibJIT/BUILD.gn | 18 - .../Userland/Libraries/LibPDF/BUILD.gn | 38 - .../Userland/Libraries/LibSoftGPU/BUILD.gn | 21 - .../Userland/Libraries/LibWeb/BUILD.gn | 3 - .../Userland/Libraries/LibX86/BUILD.gn | 16 - Meta/test_pdf.py | 151 - Tests/CMakeLists.txt | 11 - Tests/JSSpecCompiler/CMakeLists.txt | 6 - Tests/JSSpecCompiler/test-runner.cpp | 198 - Tests/LibCpp/CMakeLists.txt | 8 - Tests/LibCpp/test-cpp-parser.cpp | 77 - Tests/LibCpp/test-cpp-preprocessor.cpp | 51 - Tests/LibELF/CMakeLists.txt | 104 - Tests/LibELF/Dynlib.cpp | 15 - Tests/LibELF/TLSDef.cpp | 21 - Tests/LibELF/TLSUse.cpp | 48 - Tests/LibELF/TestDlOpen.cpp | 46 - Tests/LibELF/TestOrder.cpp | 58 - Tests/LibELF/TestOrderExe.cpp | 20 - Tests/LibELF/TestOrderLib1.cpp | 18 - Tests/LibELF/TestOrderLib2.cpp | 18 - Tests/LibELF/TestTLS.cpp | 39 - Tests/LibELF/TestWeakSymbolResolution.cpp | 16 - Tests/LibELF/TestWeakSymbolResolution1.cpp | 10 - Tests/LibELF/TestWeakSymbolResolution2.cpp | 8 - Tests/LibELF/test-elf.cpp | 291 -- Tests/LibGL/CMakeLists.txt | 11 - Tests/LibGL/TestAPI.cpp | 111 - Tests/LibGL/TestRender.cpp | 378 -- Tests/LibGL/TestShaders.cpp | 79 - .../reference-images/0001_simple_triangle.qoi | Bin 277 -> 0 bytes .../0002_quad_color_interpolation.qoi | Bin 8342 -> 0 bytes .../0003_rect_w_coordinate_regression.qoi | Bin 344 -> 0 bytes Tests/LibGL/reference-images/0004_points.qoi | Bin 170 -> 0 bytes Tests/LibGL/reference-images/0005_lines.qoi | Bin 2166 -> 0 bytes .../0006_test_rgb565_texture.qoi | Bin 433 -> 0 bytes .../0007_test_rgba_to_rgb_texture.qoi | Bin 277 -> 0 bytes .../0008_test_pop_matrix_regression.qoi | Bin 184 -> 0 bytes ...009_test_draw_elements_in_display_list.qoi | Bin 184 -> 0 bytes .../0010_test_store_data_in_buffer.qoi | Bin 184 -> 0 bytes ...11_tex_env_combine_with_constant_color.qoi | Bin 93 -> 0 bytes .../reference-images/0012_blend_equations.qoi | Bin 1961 -> 0 bytes Tests/LibGLSL/CMakeLists.txt | 7 - Tests/LibGLSL/test-parser.cpp | 61 - Tests/LibPDF/BenchmarkPDF.cpp | 75 - Tests/LibPDF/CMakeLists.txt | 26 - Tests/LibPDF/TestPDF.cpp | 344 -- Tests/LibPDF/colorspaces.pdf | 96 - Tests/LibPDF/complex.pdf | 93 - Tests/LibPDF/encoding.pdf | 73 - Tests/LibPDF/encryption_nocopy.pdf | Bin 70599 -> 0 bytes Tests/LibPDF/jbig2-globals.pdf | Bin 1090 -> 0 bytes Tests/LibPDF/linearized.pdf | Bin 3908 -> 0 bytes Tests/LibPDF/non-linearized.pdf | Bin 13264 -> 0 bytes Tests/LibPDF/oss-fuzz-testcase-62065.pdf | 1 - Tests/LibPDF/password-is-sup.pdf | Bin 12731 -> 0 bytes Tests/LibPDF/pattern.pdf | 126 - Tests/LibPDF/rotate.pdf | 53 - Tests/LibPDF/standard-14-fonts.pdf | 288 -- Tests/LibPDF/text.pdf | 61 - Tests/LibPDF/type1.pdf | Bin 34754 -> 0 bytes Tests/LibPDF/type3.pdf | 95 - Tests/LibPDF/wide-gamut-only.pdf | Bin 721914 -> 0 bytes Tests/Spreadsheet/CMakeLists.txt | 2 - Tests/Spreadsheet/test-spreadsheet.cpp | 44 - Tests/Utilities/CMakeLists.txt | 9 - Tests/Utilities/TestPatch.cpp | 315 -- Tests/Utilities/TestSed.cpp | 54 - Tests/Utilities/TestUniq.cpp | 100 - Userland/Libraries/CMakeLists.txt | 24 - .../LibCodeComprehension/CMakeLists.txt | 9 - .../CodeComprehensionEngine.cpp | 42 - .../CodeComprehensionEngine.h | 57 - .../LibCodeComprehension/Cpp/CMakeLists.txt | 20 - .../Cpp/ConnectionFromClient.h | 32 - .../Cpp/CppComprehensionEngine.cpp | 1009 ---- .../Cpp/CppComprehensionEngine.h | 204 - .../LibCodeComprehension/Cpp/Tests.cpp | 270 - .../LibCodeComprehension/Cpp/Tests.h | 9 - .../Cpp/Tests/.clang-format | 4 - .../Cpp/Tests/complete_includes.cpp | 5 - .../Cpp/Tests/complete_local_args.cpp | 4 - .../Cpp/Tests/complete_local_vars.cpp | 5 - .../Cpp/Tests/complete_type.cpp | 7 - .../Tests/find_array_variable_declaration.cpp | 11 - .../Cpp/Tests/find_variable_declaration.cpp | 4 - .../Cpp/Tests/parameters_hint1.cpp | 8 - .../Cpp/Tests/sample_header.h | 3 - .../Libraries/LibCodeComprehension/FileDB.cpp | 22 - .../Libraries/LibCodeComprehension/FileDB.h | 39 - .../LibCodeComprehension/Shell/CMakeLists.txt | 6 - .../Shell/ConnectionFromClient.h | 32 - .../Shell/ShellComprehensionEngine.cpp | 237 - .../Shell/ShellComprehensionEngine.h | 57 - .../LibCodeComprehension/Shell/main.cpp | 25 - .../Libraries/LibCodeComprehension/Types.h | 118 - Userland/Libraries/LibCpp/AST.cpp | 695 --- Userland/Libraries/LibCpp/AST.h | 1067 ---- Userland/Libraries/LibCpp/CMakeLists.txt | 12 - Userland/Libraries/LibCpp/Lexer.cpp | 810 --- Userland/Libraries/LibCpp/Lexer.h | 46 - Userland/Libraries/LibCpp/Parser.cpp | 1864 ------- Userland/Libraries/LibCpp/Parser.h | 204 - Userland/Libraries/LibCpp/Preprocessor.cpp | 414 -- Userland/Libraries/LibCpp/Preprocessor.h | 102 - .../LibCpp/SemanticSyntaxHighlighter.cpp | 181 - .../LibCpp/SemanticSyntaxHighlighter.h | 52 - .../Libraries/LibCpp/SyntaxHighlighter.cpp | 114 - Userland/Libraries/LibCpp/SyntaxHighlighter.h | 35 - Userland/Libraries/LibCpp/Tests/.clang-format | 4 - .../Tests/parser/array-initialization.ast | 19 - .../Tests/parser/array-initialization.cpp | 3 - .../Libraries/LibCpp/Tests/parser/class.ast | 28 - .../Libraries/LibCpp/Tests/parser/class.cpp | 11 - .../LibCpp/Tests/parser/function-decl.ast | 10 - .../LibCpp/Tests/parser/function-decl.cpp | 3 - .../Libraries/LibCpp/Tests/parser/if-else.ast | 33 - .../Libraries/LibCpp/Tests/parser/if-else.cpp | 8 - .../LibCpp/Tests/parser/inheritance.ast | 14 - .../LibCpp/Tests/parser/inheritance.cpp | 4 - .../LibCpp/Tests/parser/local-vars.ast | 33 - .../LibCpp/Tests/parser/local-vars.cpp | 8 - .../LibCpp/Tests/parser/out-of-line.ast | 22 - .../LibCpp/Tests/parser/out-of-line.cpp | 10 - .../Libraries/LibCpp/Tests/parser/strace.ast | 923 ---- .../Libraries/LibCpp/Tests/parser/strace.cpp | 151 - .../Libraries/LibCpp/Tests/parser/struct.ast | 42 - .../Libraries/LibCpp/Tests/parser/struct.cpp | 13 - .../LibCpp/Tests/parser/using-namespace.ast | 3 - .../LibCpp/Tests/parser/using-namespace.cpp | 2 - .../LibCpp/Tests/preprocessor/macro1.cpp | 2 - .../LibCpp/Tests/preprocessor/macro1.txt | 5 - .../LibCpp/Tests/preprocessor/macro2.cpp | 3 - .../LibCpp/Tests/preprocessor/macro2.txt | 9 - .../LibCpp/Tests/preprocessor/macro3.cpp | 4 - .../LibCpp/Tests/preprocessor/macro3.txt | 12 - .../Tests/preprocessor/simple_define.cpp | 2 - .../Tests/preprocessor/simple_define.txt | 6 - Userland/Libraries/LibCpp/Token.cpp | 39 - Userland/Libraries/LibCpp/Token.h | 139 - .../Arch/GenericDynamicRelocationType.h | 19 - .../aarch64/GenericDynamicRelocationType.h | 30 - .../Libraries/LibELF/Arch/aarch64/entry.S | 12 - .../LibELF/Arch/aarch64/plt_trampoline.S | 71 - Userland/Libraries/LibELF/Arch/aarch64/tls.S | 65 - .../Libraries/LibELF/Arch/aarch64/tls.cpp | 16 - Userland/Libraries/LibELF/Arch/aarch64/tls.h | 67 - .../riscv64/GenericDynamicRelocationType.h | 30 - .../Libraries/LibELF/Arch/riscv64/entry.S | 11 - .../LibELF/Arch/riscv64/plt_trampoline.S | 85 - .../Libraries/LibELF/Arch/riscv64/tls.cpp | 16 - Userland/Libraries/LibELF/Arch/riscv64/tls.h | 62 - Userland/Libraries/LibELF/Arch/tls.h | 26 - .../x86_64/GenericDynamicRelocationType.h | 30 - Userland/Libraries/LibELF/Arch/x86_64/entry.S | 16 - .../LibELF/Arch/x86_64/plt_trampoline.S | 72 - Userland/Libraries/LibELF/Arch/x86_64/tls.cpp | 19 - Userland/Libraries/LibELF/Arch/x86_64/tls.h | 62 - Userland/Libraries/LibELF/AuxiliaryVector.h | 67 - Userland/Libraries/LibELF/CMakeLists.txt | 35 - Userland/Libraries/LibELF/Core.h | 86 - Userland/Libraries/LibELF/DynamicLinker.cpp | 773 --- Userland/Libraries/LibELF/DynamicLinker.h | 30 - Userland/Libraries/LibELF/DynamicLoader.cpp | 845 --- Userland/Libraries/LibELF/DynamicLoader.h | 200 - Userland/Libraries/LibELF/DynamicObject.cpp | 574 --- Userland/Libraries/LibELF/DynamicObject.h | 504 -- Userland/Libraries/LibELF/ELFABI.h | 908 ---- Userland/Libraries/LibELF/ELFBuild.cpp | 136 - Userland/Libraries/LibELF/ELFBuild.h | 178 - Userland/Libraries/LibELF/Hashes.h | 44 - Userland/Libraries/LibELF/Image.cpp | 470 -- Userland/Libraries/LibELF/Image.h | 348 -- Userland/Libraries/LibELF/Relocation.cpp | 100 - Userland/Libraries/LibELF/Relocation.h | 15 - Userland/Libraries/LibELF/Validation.cpp | 354 -- Userland/Libraries/LibELF/Validation.h | 17 - Userland/Libraries/LibGL/Blending.cpp | 156 - Userland/Libraries/LibGL/Buffer.cpp | 108 - Userland/Libraries/LibGL/Buffer/Buffer.cpp | 41 - Userland/Libraries/LibGL/Buffer/Buffer.h | 29 - Userland/Libraries/LibGL/CMakeLists.txt | 39 - Userland/Libraries/LibGL/ClipPlane.cpp | 56 - Userland/Libraries/LibGL/ContextParameter.cpp | 653 --- Userland/Libraries/LibGL/GL/gl.h | 648 --- Userland/Libraries/LibGL/GL/glext.h | 14 - Userland/Libraries/LibGL/GL/glplatform.h | 44 - Userland/Libraries/LibGL/GLAPI.json | 1246 ----- Userland/Libraries/LibGL/GLContext.cpp | 905 ---- Userland/Libraries/LibGL/GLContext.h | 619 --- Userland/Libraries/LibGL/Image.cpp | 297 -- Userland/Libraries/LibGL/Image.h | 21 - Userland/Libraries/LibGL/Lighting.cpp | 557 -- Userland/Libraries/LibGL/List.cpp | 166 - Userland/Libraries/LibGL/Matrix.cpp | 183 - Userland/Libraries/LibGL/NameAllocator.cpp | 35 - Userland/Libraries/LibGL/NameAllocator.h | 27 - Userland/Libraries/LibGL/Shader.cpp | 214 - Userland/Libraries/LibGL/Shaders/Program.cpp | 105 - Userland/Libraries/LibGL/Shaders/Program.h | 44 - Userland/Libraries/LibGL/Shaders/Shader.cpp | 68 - Userland/Libraries/LibGL/Shaders/Shader.h | 50 - Userland/Libraries/LibGL/Stencil.cpp | 159 - Userland/Libraries/LibGL/Tex/Sampler2D.h | 37 - Userland/Libraries/LibGL/Tex/Texture.h | 37 - Userland/Libraries/LibGL/Tex/Texture2D.cpp | 54 - Userland/Libraries/LibGL/Tex/Texture2D.h | 43 - Userland/Libraries/LibGL/Tex/TextureUnit.h | 85 - Userland/Libraries/LibGL/Texture.cpp | 1015 ---- Userland/Libraries/LibGL/Vertex.cpp | 319 -- Userland/Libraries/LibGLSL/AST.cpp | 517 -- Userland/Libraries/LibGLSL/AST.h | 715 --- Userland/Libraries/LibGLSL/CMakeLists.txt | 14 - Userland/Libraries/LibGLSL/Compiler.cpp | 18 - Userland/Libraries/LibGLSL/Compiler.h | 27 - Userland/Libraries/LibGLSL/Lexer.cpp | 819 --- Userland/Libraries/LibGLSL/Lexer.h | 46 - Userland/Libraries/LibGLSL/LinkedShader.h | 33 - Userland/Libraries/LibGLSL/Linker.cpp | 32 - Userland/Libraries/LibGLSL/Linker.h | 28 - Userland/Libraries/LibGLSL/ObjectFile.h | 16 - Userland/Libraries/LibGLSL/Parser.cpp | 1142 ----- Userland/Libraries/LibGLSL/Parser.h | 153 - Userland/Libraries/LibGLSL/Preprocessor.cpp | 416 -- Userland/Libraries/LibGLSL/Preprocessor.h | 103 - .../LibGLSL/Tests/parser/discard.ast | 11 - .../LibGLSL/Tests/parser/discard.glsl | 5 - .../LibGLSL/Tests/parser/expression.ast | 63 - .../LibGLSL/Tests/parser/expression.glsl | 5 - .../LibGLSL/Tests/parser/for-statement.ast | 37 - .../LibGLSL/Tests/parser/for-statement.glsl | 7 - .../Tests/parser/function-declaration.ast | 15 - .../Tests/parser/function-declaration.glsl | 2 - .../Tests/parser/function-definition.ast | 13 - .../Tests/parser/function-definition.glsl | 5 - .../LibGLSL/Tests/parser/if-else.ast | 26 - .../LibGLSL/Tests/parser/if-else.glsl | 8 - .../Libraries/LibGLSL/Tests/parser/return.ast | 23 - .../LibGLSL/Tests/parser/return.glsl | 10 - .../Libraries/LibGLSL/Tests/parser/struct.ast | 7 - .../LibGLSL/Tests/parser/struct.glsl | 5 - .../LibGLSL/Tests/parser/unary-expression.ast | 32 - .../Tests/parser/unary-expression.glsl | 6 - .../Tests/parser/variable-declaration.ast | 13 - .../Tests/parser/variable-declaration.glsl | 4 - Userland/Libraries/LibGLSL/Token.cpp | 44 - Userland/Libraries/LibGLSL/Token.h | 133 - Userland/Libraries/LibGPU/CMakeLists.txt | 13 - Userland/Libraries/LibGPU/Config.h | 23 - Userland/Libraries/LibGPU/Device.h | 82 - Userland/Libraries/LibGPU/DeviceInfo.h | 27 - Userland/Libraries/LibGPU/Driver.cpp | 72 - Userland/Libraries/LibGPU/Driver.h | 42 - Userland/Libraries/LibGPU/Enums.h | 153 - Userland/Libraries/LibGPU/IR.h | 81 - Userland/Libraries/LibGPU/Image.cpp | 33 - Userland/Libraries/LibGPU/Image.h | 45 - Userland/Libraries/LibGPU/ImageDataLayout.h | 51 - Userland/Libraries/LibGPU/ImageFormat.h | 178 - Userland/Libraries/LibGPU/Light.h | 33 - .../Libraries/LibGPU/LightModelParameters.h | 21 - Userland/Libraries/LibGPU/Material.h | 24 - Userland/Libraries/LibGPU/RasterPosition.h | 23 - Userland/Libraries/LibGPU/RasterizerOptions.h | 64 - Userland/Libraries/LibGPU/SamplerConfig.h | 98 - Userland/Libraries/LibGPU/Shader.h | 29 - .../Libraries/LibGPU/StencilConfiguration.h | 25 - .../LibGPU/TextureUnitConfiguration.h | 30 - Userland/Libraries/LibGPU/Vertex.h | 27 - Userland/Libraries/LibGUI/AboutDialog.cpp | 73 - Userland/Libraries/LibGUI/AboutDialog.gml | 83 - Userland/Libraries/LibGUI/AboutDialog.h | 31 - Userland/Libraries/LibGUI/AboutDialogWidget.h | 23 - Userland/Libraries/LibGUI/AbstractButton.cpp | 272 - Userland/Libraries/LibGUI/AbstractButton.h | 84 - .../LibGUI/AbstractScrollableWidget.cpp | 380 -- .../LibGUI/AbstractScrollableWidget.h | 132 - Userland/Libraries/LibGUI/AbstractSlider.cpp | 65 - Userland/Libraries/LibGUI/AbstractSlider.h | 68 - .../Libraries/LibGUI/AbstractTableView.cpp | 527 -- Userland/Libraries/LibGUI/AbstractTableView.h | 134 - .../Libraries/LibGUI/AbstractThemePreview.cpp | 192 - .../Libraries/LibGUI/AbstractThemePreview.h | 89 - Userland/Libraries/LibGUI/AbstractView.cpp | 841 --- Userland/Libraries/LibGUI/AbstractView.h | 216 - .../LibGUI/AbstractZoomPanWidget.cpp | 211 - .../Libraries/LibGUI/AbstractZoomPanWidget.h | 84 - Userland/Libraries/LibGUI/Action.cpp | 329 -- Userland/Libraries/LibGUI/Action.h | 170 - Userland/Libraries/LibGUI/ActionGroup.cpp | 24 - Userland/Libraries/LibGUI/ActionGroup.h | 45 - Userland/Libraries/LibGUI/Application.cpp | 408 -- Userland/Libraries/LibGUI/Application.h | 135 - .../Libraries/LibGUI/AutocompleteProvider.cpp | 207 - .../Libraries/LibGUI/AutocompleteProvider.h | 62 - Userland/Libraries/LibGUI/BoxLayout.cpp | 406 -- Userland/Libraries/LibGUI/BoxLayout.h | 57 - Userland/Libraries/LibGUI/Breadcrumbbar.cpp | 210 - Userland/Libraries/LibGUI/Breadcrumbbar.h | 64 - Userland/Libraries/LibGUI/Button.cpp | 304 -- Userland/Libraries/LibGUI/Button.h | 105 - Userland/Libraries/LibGUI/CMakeLists.txt | 160 - Userland/Libraries/LibGUI/Calendar.cpp | 897 ---- Userland/Libraries/LibGUI/Calendar.h | 200 - Userland/Libraries/LibGUI/CheckBox.cpp | 115 - Userland/Libraries/LibGUI/CheckBox.h | 54 - Userland/Libraries/LibGUI/Clipboard.cpp | 202 - Userland/Libraries/LibGUI/Clipboard.h | 67 - Userland/Libraries/LibGUI/ColorFilterer.h | 22 - Userland/Libraries/LibGUI/ColorInput.cpp | 109 - Userland/Libraries/LibGUI/ColorInput.h | 50 - Userland/Libraries/LibGUI/ColorPicker.cpp | 797 --- Userland/Libraries/LibGUI/ColorPicker.h | 56 - Userland/Libraries/LibGUI/ColumnsView.cpp | 484 -- Userland/Libraries/LibGUI/ColumnsView.h | 70 - Userland/Libraries/LibGUI/ComboBox.cpp | 331 -- Userland/Libraries/LibGUI/ComboBox.h | 72 - Userland/Libraries/LibGUI/Command.h | 28 - Userland/Libraries/LibGUI/CommandPalette.cpp | 296 -- Userland/Libraries/LibGUI/CommandPalette.h | 38 - Userland/Libraries/LibGUI/CommonActions.cpp | 222 - .../LibGUI/CommonLocationsProvider.cpp | 79 - .../LibGUI/CommonLocationsProvider.h | 27 - Userland/Libraries/LibGUI/CommonMenus.cpp | 78 - .../ConnectionToWindowManagerServer.cpp | 97 - .../LibGUI/ConnectionToWindowManagerServer.h | 45 - .../LibGUI/ConnectionToWindowServer.cpp | 399 -- .../LibGUI/ConnectionToWindowServer.h | 67 - Userland/Libraries/LibGUI/DatePicker.cpp | 83 - Userland/Libraries/LibGUI/DatePicker.h | 33 - .../Libraries/LibGUI/DatePickerDialog.gml | 57 - Userland/Libraries/LibGUI/Desktop.cpp | 78 - Userland/Libraries/LibGUI/Desktop.h | 69 - Userland/Libraries/LibGUI/Dialog.cpp | 82 - Userland/Libraries/LibGUI/Dialog.h | 62 - Userland/Libraries/LibGUI/DisplayLink.cpp | 69 - Userland/Libraries/LibGUI/DisplayLink.h | 22 - Userland/Libraries/LibGUI/DragOperation.cpp | 96 - Userland/Libraries/LibGUI/DragOperation.h | 51 - .../LibGUI/DynamicWidgetContainer.cpp | 460 -- .../Libraries/LibGUI/DynamicWidgetContainer.h | 99 - .../LibGUI/DynamicWidgetContainerControls.gml | 36 - .../LibGUI/DynamicWidgetContainerControls.h | 45 - Userland/Libraries/LibGUI/EditingEngine.cpp | 502 -- Userland/Libraries/LibGUI/EditingEngine.h | 110 - .../Libraries/LibGUI/EmojiInputDialog.cpp | 214 - .../Libraries/LibGUI/EmojiInputDialog.gml | 31 - Userland/Libraries/LibGUI/EmojiInputDialog.h | 46 - .../Libraries/LibGUI/EmojiInputDialogWidget.h | 24 - Userland/Libraries/LibGUI/Event.cpp | 56 - Userland/Libraries/LibGUI/Event.h | 611 --- .../Libraries/LibGUI/FileIconProvider.cpp | 316 -- Userland/Libraries/LibGUI/FileIconProvider.h | 31 - Userland/Libraries/LibGUI/FilePicker.cpp | 378 -- Userland/Libraries/LibGUI/FilePicker.h | 94 - .../Libraries/LibGUI/FilePickerDialog.gml | 95 - .../Libraries/LibGUI/FilePickerDialogWidget.h | 24 - Userland/Libraries/LibGUI/FileSystemModel.cpp | 930 ---- Userland/Libraries/LibGUI/FileSystemModel.h | 187 - Userland/Libraries/LibGUI/FileTypeFilter.h | 63 - .../Libraries/LibGUI/FilteringProxyModel.cpp | 128 - .../Libraries/LibGUI/FilteringProxyModel.h | 77 - Userland/Libraries/LibGUI/FocusPolicy.h | 28 - Userland/Libraries/LibGUI/FocusSource.h | 17 - Userland/Libraries/LibGUI/FontPicker.cpp | 217 - Userland/Libraries/LibGUI/FontPicker.h | 50 - .../Libraries/LibGUI/FontPickerDialog.gml | 87 - .../Libraries/LibGUI/FontPickerDialogWidget.h | 23 - Userland/Libraries/LibGUI/Forward.h | 108 - Userland/Libraries/LibGUI/Frame.cpp | 73 - Userland/Libraries/LibGUI/Frame.h | 40 - Userland/Libraries/LibGUI/GML/AST.h | 373 -- .../LibGUI/GML/AutocompleteProvider.cpp | 245 - .../LibGUI/GML/AutocompleteProvider.h | 28 - Userland/Libraries/LibGUI/GML/Formatter.h | 21 - Userland/Libraries/LibGUI/GML/Lexer.cpp | 154 - Userland/Libraries/LibGUI/GML/Lexer.h | 71 - Userland/Libraries/LibGUI/GML/Parser.cpp | 134 - Userland/Libraries/LibGUI/GML/Parser.h | 17 - .../LibGUI/GML/SyntaxHighlighter.cpp | 98 - .../Libraries/LibGUI/GML/SyntaxHighlighter.h | 31 - Userland/Libraries/LibGUI/GitCommitLexer.cpp | 82 - Userland/Libraries/LibGUI/GitCommitLexer.h | 64 - .../LibGUI/GitCommitSyntaxHighlighter.cpp | 54 - .../LibGUI/GitCommitSyntaxHighlighter.h | 29 - Userland/Libraries/LibGUI/GlyphMapWidget.cpp | 620 --- Userland/Libraries/LibGUI/GlyphMapWidget.h | 124 - Userland/Libraries/LibGUI/GroupBox.cpp | 72 - Userland/Libraries/LibGUI/GroupBox.h | 33 - Userland/Libraries/LibGUI/HeaderView.cpp | 453 -- Userland/Libraries/LibGUI/HeaderView.h | 116 - Userland/Libraries/LibGUI/HorizontalSlider.h | 27 - Userland/Libraries/LibGUI/INILexer.cpp | 137 - Userland/Libraries/LibGUI/INILexer.h | 70 - .../Libraries/LibGUI/INISyntaxHighlighter.cpp | 113 - .../Libraries/LibGUI/INISyntaxHighlighter.h | 31 - Userland/Libraries/LibGUI/Icon.cpp | 98 - Userland/Libraries/LibGUI/Icon.h | 63 - Userland/Libraries/LibGUI/IconView.cpp | 832 --- Userland/Libraries/LibGUI/IconView.h | 181 - Userland/Libraries/LibGUI/ImageWidget.cpp | 132 - Userland/Libraries/LibGUI/ImageWidget.h | 57 - .../LibGUI/IncrementalSearchBanner.cpp | 141 - .../LibGUI/IncrementalSearchBanner.gml | 81 - .../LibGUI/IncrementalSearchBanner.h | 49 - Userland/Libraries/LibGUI/InputBox.cpp | 209 - Userland/Libraries/LibGUI/InputBox.h | 64 - Userland/Libraries/LibGUI/ItemListModel.h | 143 - Userland/Libraries/LibGUI/JsonArrayModel.cpp | 168 - Userland/Libraries/LibGUI/JsonArrayModel.h | 87 - Userland/Libraries/LibGUI/Label.cpp | 117 - Userland/Libraries/LibGUI/Label.h | 58 - .../LibGUI/LabelWithEventDispatcher.cpp | 38 - .../LibGUI/LabelWithEventDispatcher.h | 29 - Userland/Libraries/LibGUI/Layout.cpp | 132 - Userland/Libraries/LibGUI/Layout.h | 81 - Userland/Libraries/LibGUI/LazyWidget.cpp | 24 - Userland/Libraries/LibGUI/LazyWidget.h | 29 - Userland/Libraries/LibGUI/LinkLabel.cpp | 138 - Userland/Libraries/LibGUI/LinkLabel.h | 47 - Userland/Libraries/LibGUI/ListView.cpp | 271 - Userland/Libraries/LibGUI/ListView.h | 73 - Userland/Libraries/LibGUI/Margins.h | 153 - Userland/Libraries/LibGUI/Menu.cpp | 260 - Userland/Libraries/LibGUI/Menu.h | 98 - Userland/Libraries/LibGUI/MenuItem.cpp | 112 - Userland/Libraries/LibGUI/MenuItem.h | 76 - Userland/Libraries/LibGUI/Menubar.cpp | 34 - Userland/Libraries/LibGUI/Menubar.h | 36 - Userland/Libraries/LibGUI/MessageBox.cpp | 203 - Userland/Libraries/LibGUI/MessageBox.h | 78 - Userland/Libraries/LibGUI/Model.cpp | 486 -- Userland/Libraries/LibGUI/Model.h | 221 - .../Libraries/LibGUI/ModelEditingDelegate.h | 108 - Userland/Libraries/LibGUI/ModelIndex.cpp | 47 - Userland/Libraries/LibGUI/ModelIndex.h | 80 - Userland/Libraries/LibGUI/ModelRole.h | 25 - Userland/Libraries/LibGUI/ModelSelection.cpp | 86 - Userland/Libraries/LibGUI/ModelSelection.h | 102 - Userland/Libraries/LibGUI/MouseTracker.cpp | 36 - Userland/Libraries/LibGUI/MouseTracker.h | 33 - Userland/Libraries/LibGUI/MultiView.cpp | 149 - Userland/Libraries/LibGUI/MultiView.h | 103 - Userland/Libraries/LibGUI/Notification.cpp | 87 - Userland/Libraries/LibGUI/Notification.h | 69 - Userland/Libraries/LibGUI/NumericInput.cpp | 109 - Userland/Libraries/LibGUI/NumericInput.h | 41 - Userland/Libraries/LibGUI/Object.cpp | 74 - Userland/Libraries/LibGUI/Object.h | 253 - Userland/Libraries/LibGUI/OpacitySlider.cpp | 195 - Userland/Libraries/LibGUI/OpacitySlider.h | 71 - Userland/Libraries/LibGUI/Painter.cpp | 28 - Userland/Libraries/LibGUI/Painter.h | 20 - .../Libraries/LibGUI/PasswordInputDialog.cpp | 69 - .../Libraries/LibGUI/PasswordInputDialog.gml | 94 - .../Libraries/LibGUI/PasswordInputDialog.h | 30 - .../LibGUI/PasswordInputDialogWidget.h | 24 - .../Libraries/LibGUI/PathBreadcrumbbar.cpp | 178 - Userland/Libraries/LibGUI/PathBreadcrumbbar.h | 45 - .../Libraries/LibGUI/PersistentModelIndex.cpp | 96 - .../Libraries/LibGUI/PersistentModelIndex.h | 93 - Userland/Libraries/LibGUI/Process.cpp | 36 - Userland/Libraries/LibGUI/Process.h | 20 - Userland/Libraries/LibGUI/ProcessChooser.cpp | 107 - Userland/Libraries/LibGUI/ProcessChooser.h | 43 - Userland/Libraries/LibGUI/Progressbar.cpp | 93 - Userland/Libraries/LibGUI/Progressbar.h | 85 - Userland/Libraries/LibGUI/Property.cpp | 19 - Userland/Libraries/LibGUI/Property.h | 45 - .../Libraries/LibGUI/PropertyDeserializer.cpp | 183 - .../Libraries/LibGUI/PropertyDeserializer.h | 30 - Userland/Libraries/LibGUI/RadioButton.cpp | 77 - Userland/Libraries/LibGUI/RadioButton.h | 37 - Userland/Libraries/LibGUI/RangeSlider.cpp | 235 - Userland/Libraries/LibGUI/RangeSlider.h | 72 - .../Libraries/LibGUI/RegularEditingEngine.cpp | 65 - .../Libraries/LibGUI/RegularEditingEngine.h | 25 - Userland/Libraries/LibGUI/ResizeCorner.cpp | 83 - Userland/Libraries/LibGUI/ResizeCorner.h | 26 - Userland/Libraries/LibGUI/ResizeDirection.h | 15 - .../LibGUI/RunningProcessesModel.cpp | 89 - .../Libraries/LibGUI/RunningProcessesModel.h | 47 - Userland/Libraries/LibGUI/ScreenLayout.cpp | 7 - .../LibGUI/ScrollableContainerWidget.cpp | 148 - .../LibGUI/ScrollableContainerWidget.h | 43 - Userland/Libraries/LibGUI/Scrollbar.cpp | 442 -- Userland/Libraries/LibGUI/Scrollbar.h | 109 - Userland/Libraries/LibGUI/SeparatorWidget.cpp | 55 - Userland/Libraries/LibGUI/SeparatorWidget.h | 55 - Userland/Libraries/LibGUI/SettingsWindow.cpp | 128 - Userland/Libraries/LibGUI/SettingsWindow.h | 87 - Userland/Libraries/LibGUI/Shortcut.cpp | 47 - Userland/Libraries/LibGUI/Shortcut.h | 95 - Userland/Libraries/LibGUI/Slider.cpp | 221 - Userland/Libraries/LibGUI/Slider.h | 85 - .../Libraries/LibGUI/SortingProxyModel.cpp | 291 -- Userland/Libraries/LibGUI/SortingProxyModel.h | 83 - Userland/Libraries/LibGUI/SpinBox.cpp | 147 - Userland/Libraries/LibGUI/SpinBox.h | 50 - Userland/Libraries/LibGUI/Splitter.cpp | 279 - Userland/Libraries/LibGUI/Splitter.h | 104 - Userland/Libraries/LibGUI/StackWidget.cpp | 74 - Userland/Libraries/LibGUI/StackWidget.h | 36 - Userland/Libraries/LibGUI/Statusbar.cpp | 177 - Userland/Libraries/LibGUI/Statusbar.h | 84 - Userland/Libraries/LibGUI/SystemEffects.h | 17 - Userland/Libraries/LibGUI/TabWidget.cpp | 828 --- Userland/Libraries/LibGUI/TabWidget.h | 164 - Userland/Libraries/LibGUI/TableView.cpp | 336 -- Userland/Libraries/LibGUI/TableView.h | 60 - Userland/Libraries/LibGUI/TextBox.cpp | 132 - Userland/Libraries/LibGUI/TextBox.h | 64 - Userland/Libraries/LibGUI/TextDocument.cpp | 1144 ----- Userland/Libraries/LibGUI/TextDocument.h | 295 -- Userland/Libraries/LibGUI/TextEditor.cpp | 2660 ---------- Userland/Libraries/LibGUI/TextEditor.h | 477 -- Userland/Libraries/LibGUI/TextPosition.h | 16 - Userland/Libraries/LibGUI/TextRange.h | 15 - Userland/Libraries/LibGUI/Toolbar.cpp | 255 - Userland/Libraries/LibGUI/Toolbar.h | 62 - .../Libraries/LibGUI/ToolbarContainer.cpp | 43 - Userland/Libraries/LibGUI/ToolbarContainer.h | 26 - Userland/Libraries/LibGUI/Tray.cpp | 215 - Userland/Libraries/LibGUI/Tray.h | 57 - Userland/Libraries/LibGUI/TreeView.cpp | 806 --- Userland/Libraries/LibGUI/TreeView.h | 85 - Userland/Libraries/LibGUI/TreeViewModel.cpp | 83 - Userland/Libraries/LibGUI/TreeViewModel.h | 92 - Userland/Libraries/LibGUI/UIDimensions.h | 339 -- Userland/Libraries/LibGUI/UndoStack.cpp | 128 - Userland/Libraries/LibGUI/UndoStack.h | 50 - Userland/Libraries/LibGUI/ValueSlider.cpp | 229 - Userland/Libraries/LibGUI/ValueSlider.h | 59 - Userland/Libraries/LibGUI/Variant.cpp | 60 - Userland/Libraries/LibGUI/Variant.h | 221 - .../Libraries/LibGUI/VimEditingEngine.cpp | 1581 ------ Userland/Libraries/LibGUI/VimEditingEngine.h | 204 - Userland/Libraries/LibGUI/Widget.cpp | 1212 ----- Userland/Libraries/LibGUI/Widget.h | 491 -- Userland/Libraries/LibGUI/Window.cpp | 1474 ------ Userland/Libraries/LibGUI/Window.h | 343 -- Userland/Libraries/LibGUI/WindowMode.h | 15 - Userland/Libraries/LibGUI/WindowType.h | 15 - .../LibGUI/Wizards/AbstractWizardPage.cpp | 36 - .../LibGUI/Wizards/AbstractWizardPage.h | 39 - .../LibGUI/Wizards/CoverWizardPage.cpp | 56 - .../LibGUI/Wizards/CoverWizardPage.h | 39 - .../Libraries/LibGUI/Wizards/WizardDialog.cpp | 154 - .../Libraries/LibGUI/Wizards/WizardDialog.h | 49 - .../Libraries/LibGUI/Wizards/WizardPage.cpp | 63 - .../Libraries/LibGUI/Wizards/WizardPage.h | 38 - Userland/Libraries/LibJIT/Assembler.cpp | 11 - Userland/Libraries/LibJIT/Assembler.h | 19 - Userland/Libraries/LibJIT/CMakeLists.txt | 14 - Userland/Libraries/LibJIT/GDB.cpp | 104 - Userland/Libraries/LibJIT/GDB.h | 28 - Userland/Libraries/LibJIT/GDBElf.cpp | 87 - Userland/Libraries/LibJIT/GDBUnsupported.cpp | 14 - Userland/Libraries/LibJIT/X86_64/Assembler.h | 1056 ---- Userland/Libraries/LibJS/CMakeLists.txt | 3 - Userland/Libraries/LibPDF/CMakeLists.txt | 32 - Userland/Libraries/LibPDF/ColorSpace.cpp | 807 --- Userland/Libraries/LibPDF/ColorSpace.h | 267 - Userland/Libraries/LibPDF/CommonNames.cpp | 18 - Userland/Libraries/LibPDF/CommonNames.h | 215 - Userland/Libraries/LibPDF/Document.cpp | 654 --- Userland/Libraries/LibPDF/Document.h | 278 - Userland/Libraries/LibPDF/DocumentParser.cpp | 886 ---- Userland/Libraries/LibPDF/DocumentParser.h | 107 - Userland/Libraries/LibPDF/Encoding.cpp | 190 - Userland/Libraries/LibPDF/Encoding.h | 655 --- Userland/Libraries/LibPDF/Encryption.cpp | 810 --- Userland/Libraries/LibPDF/Encryption.h | 98 - Userland/Libraries/LibPDF/Error.h | 115 - Userland/Libraries/LibPDF/Filter.cpp | 411 -- Userland/Libraries/LibPDF/Filter.h | 37 - .../Libraries/LibPDF/Fonts/AdobeGlyphList.cpp | 4546 ----------------- .../Libraries/LibPDF/Fonts/AdobeGlyphList.h | 15 - Userland/Libraries/LibPDF/Fonts/CFF.cpp | 1149 ----- Userland/Libraries/LibPDF/Fonts/CFF.h | 142 - Userland/Libraries/LibPDF/Fonts/PDFFont.cpp | 105 - Userland/Libraries/LibPDF/Fonts/PDFFont.h | 64 - .../Libraries/LibPDF/Fonts/PS1FontProgram.cpp | 255 - .../Libraries/LibPDF/Fonts/PS1FontProgram.h | 48 - .../Libraries/LibPDF/Fonts/SimpleFont.cpp | 97 - Userland/Libraries/LibPDF/Fonts/SimpleFont.h | 39 - .../Libraries/LibPDF/Fonts/TrueTypeFont.cpp | 204 - .../Libraries/LibPDF/Fonts/TrueTypeFont.h | 53 - Userland/Libraries/LibPDF/Fonts/Type0Font.cpp | 513 -- Userland/Libraries/LibPDF/Fonts/Type0Font.h | 84 - Userland/Libraries/LibPDF/Fonts/Type1Font.cpp | 149 - Userland/Libraries/LibPDF/Fonts/Type1Font.h | 54 - .../LibPDF/Fonts/Type1FontProgram.cpp | 750 --- .../Libraries/LibPDF/Fonts/Type1FontProgram.h | 124 - Userland/Libraries/LibPDF/Fonts/Type3Font.cpp | 80 - Userland/Libraries/LibPDF/Fonts/Type3Font.h | 28 - Userland/Libraries/LibPDF/Forward.h | 40 - Userland/Libraries/LibPDF/Function.cpp | 1043 ---- Userland/Libraries/LibPDF/Function.h | 21 - Userland/Libraries/LibPDF/Interpolation.cpp | 35 - Userland/Libraries/LibPDF/Interpolation.h | 27 - Userland/Libraries/LibPDF/Object.h | 113 - .../Libraries/LibPDF/ObjectDerivatives.cpp | 190 - Userland/Libraries/LibPDF/ObjectDerivatives.h | 219 - Userland/Libraries/LibPDF/Operator.h | 186 - Userland/Libraries/LibPDF/Page.cpp | 37 - Userland/Libraries/LibPDF/Page.h | 67 - Userland/Libraries/LibPDF/Parser.cpp | 635 --- Userland/Libraries/LibPDF/Parser.h | 93 - Userland/Libraries/LibPDF/Reader.cpp | 113 - Userland/Libraries/LibPDF/Reader.h | 187 - Userland/Libraries/LibPDF/Reference.h | 37 - Userland/Libraries/LibPDF/Renderer.cpp | 1457 ------ Userland/Libraries/LibPDF/Renderer.h | 347 -- Userland/Libraries/LibPDF/Value.cpp | 39 - Userland/Libraries/LibPDF/Value.h | 102 - Userland/Libraries/LibPDF/XRefTable.h | 149 - .../Libraries/LibSoftGPU/Buffer/FrameBuffer.h | 57 - .../LibSoftGPU/Buffer/Typed2DBuffer.h | 59 - .../LibSoftGPU/Buffer/Typed3DBuffer.h | 72 - Userland/Libraries/LibSoftGPU/CMakeLists.txt | 15 - Userland/Libraries/LibSoftGPU/Clipper.cpp | 174 - Userland/Libraries/LibSoftGPU/Clipper.h | 39 - Userland/Libraries/LibSoftGPU/Config.h | 46 - Userland/Libraries/LibSoftGPU/Device.cpp | 1756 ------- Userland/Libraries/LibSoftGPU/Device.h | 132 - Userland/Libraries/LibSoftGPU/ISA.h | 63 - Userland/Libraries/LibSoftGPU/Image.cpp | 199 - Userland/Libraries/LibSoftGPU/Image.h | 64 - .../Libraries/LibSoftGPU/PixelConverter.cpp | 443 -- .../Libraries/LibSoftGPU/PixelConverter.h | 34 - Userland/Libraries/LibSoftGPU/PixelQuad.h | 72 - Userland/Libraries/LibSoftGPU/SIMD.h | 147 - Userland/Libraries/LibSoftGPU/Sampler.cpp | 243 - Userland/Libraries/LibSoftGPU/Sampler.h | 29 - Userland/Libraries/LibSoftGPU/Shader.cpp | 17 - Userland/Libraries/LibSoftGPU/Shader.h | 25 - .../Libraries/LibSoftGPU/ShaderCompiler.cpp | 17 - .../Libraries/LibSoftGPU/ShaderCompiler.h | 21 - .../Libraries/LibSoftGPU/ShaderProcessor.cpp | 115 - .../Libraries/LibSoftGPU/ShaderProcessor.h | 46 - Userland/Libraries/LibSoftGPU/Triangle.h | 20 - Userland/Libraries/LibWeb/CMakeLists.txt | 7 +- .../Libraries/LibWeb/WebGL/OpenGLContext.cpp | 137 +- Userland/Libraries/LibWebView/CMakeLists.txt | 4 - .../LibWebView/OutOfProcessWebView.cpp | 370 -- .../LibWebView/OutOfProcessWebView.h | 95 - Userland/Libraries/LibX86/CMakeLists.txt | 5 - Userland/Libraries/LibX86/Disassembler.h | 37 - Userland/Libraries/LibX86/ELFSymbolProvider.h | 31 - Userland/Libraries/LibX86/Instruction.cpp | 2540 --------- Userland/Libraries/LibX86/Instruction.h | 1318 ----- Userland/Libraries/LibX86/Interpreter.h | 823 --- .../Services/WebContent/Documentation.txt | 16 - .../Services/WindowServer/ResizeDirection.h | 24 - Userland/Services/WindowServer/WindowMode.h | 25 - Userland/Services/WindowServer/WindowType.h | 27 - Userland/Utilities/CMakeLists.txt | 4 +- Userland/Utilities/adjtime.cpp | 43 - Userland/Utilities/file.cpp | 231 - Userland/Utilities/pdf.cpp | 285 -- 779 files changed, 3 insertions(+), 122585 deletions(-) delete mode 100644 AK/FixedStringBuffer.h delete mode 100644 AK/UBSanitizer.h delete mode 100644 AK/Userspace.h delete mode 100644 Kernel/FileSystem/CustodyBase.cpp delete mode 100644 Kernel/FileSystem/CustodyBase.h delete mode 100644 Kernel/Memory/VirtualAddress.h delete mode 100644 Meta/CMake/libgl_generators.cmake delete mode 100644 Meta/Lagom/Contrib/MacPDF/AppDelegate.h delete mode 100644 Meta/Lagom/Contrib/MacPDF/AppDelegate.mm delete mode 100644 Meta/Lagom/Contrib/MacPDF/CMakeLists.txt delete mode 100644 Meta/Lagom/Contrib/MacPDF/CocoaWrapper.h delete mode 100644 Meta/Lagom/Contrib/MacPDF/Info.plist delete mode 100644 Meta/Lagom/Contrib/MacPDF/MacPDFDocument.h delete mode 100644 Meta/Lagom/Contrib/MacPDF/MacPDFDocument.mm delete mode 100644 Meta/Lagom/Contrib/MacPDF/MacPDFOutlineViewDataSource.h delete mode 100644 Meta/Lagom/Contrib/MacPDF/MacPDFOutlineViewDataSource.mm delete mode 100644 Meta/Lagom/Contrib/MacPDF/MacPDFView.h delete mode 100644 Meta/Lagom/Contrib/MacPDF/MacPDFView.mm delete mode 100644 Meta/Lagom/Contrib/MacPDF/MacPDFWindowController.h delete mode 100644 Meta/Lagom/Contrib/MacPDF/MacPDFWindowController.mm delete mode 100644 Meta/Lagom/Contrib/MacPDF/MainMenu.xib delete mode 100644 Meta/Lagom/Contrib/MacPDF/main.mm delete mode 100644 Meta/Lagom/Fuzzers/FuzzELF.cpp delete mode 100644 Meta/Lagom/Fuzzers/FuzzPDF.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/GMLCompiler/CMakeLists.txt delete mode 100644 Meta/Lagom/Tools/CodeGenerators/GMLCompiler/main.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/CMakeLists.txt delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/CompilationPipeline.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/CompilerPass.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/CompilerPass.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/EnableGraphPointers.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/GenericASTPass.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/GenericASTPass.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGBuildingPass.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGBuildingPass.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGSimplificationPass.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGSimplificationPass.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/DeadCodeEliminationPass.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/DeadCodeEliminationPass.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/IfBranchMergingPass.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/IfBranchMergingPass.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/ReferenceResolvingPass.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/ReferenceResolvingPass.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/SSABuildingPass.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/SSABuildingPass.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/StronglyConnectedComponents.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/DiagnosticEngine.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/DiagnosticEngine.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Forward.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Algorithm.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/AlgorithmStep.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/AlgorithmStepList.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/CppASTConverter.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/CppASTConverter.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Lexer.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Lexer.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Specification.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationClause.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationFunction.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationParsing.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationParsingContext.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationParsingStep.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Token.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/XMLUtils.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/XMLUtils.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Printer.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Cell.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Object.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Object.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/ObjectType.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/ObjectType.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Realm.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Realm.h delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/simple.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/simple.cpp.expectation delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-headers.xml delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-headers.xml.expectation delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-no-new-line-after-dot.xml delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-no-new-line-after-dot.xml.expectation delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-optional-arguments.xml delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-optional-arguments.xml.expectation delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml.expectation delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-single-function-simple.xml delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-single-function-simple.xml.expectation delete mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/main.cpp delete mode 100644 Meta/Lagom/Tools/CodeGenerators/LibGL/CMakeLists.txt delete mode 100644 Meta/Lagom/Tools/CodeGenerators/LibGL/GenerateGLAPIWrapper.cpp delete mode 100644 Meta/gn/secondary/Kernel/BUILD.gn delete mode 100644 Meta/gn/secondary/Kernel/Prekernel/BUILD.gn delete mode 100755 Meta/gn/secondary/Kernel/generate_version_header.py delete mode 100644 Meta/gn/secondary/Kernel/post_process_kernel.py delete mode 100644 Meta/gn/secondary/Meta/Lagom/Contrib/MacPDF/BUILD.gn delete mode 100644 Meta/gn/secondary/Userland/Libraries/LibC/BUILD.gn delete mode 100644 Meta/gn/secondary/Userland/Libraries/LibC/libc_headers.gni delete mode 100644 Meta/gn/secondary/Userland/Libraries/LibELF/BUILD.gn delete mode 100644 Meta/gn/secondary/Userland/Libraries/LibGL/BUILD.gn delete mode 100644 Meta/gn/secondary/Userland/Libraries/LibGLSL/BUILD.gn delete mode 100644 Meta/gn/secondary/Userland/Libraries/LibGPU/BUILD.gn delete mode 100644 Meta/gn/secondary/Userland/Libraries/LibGUI/BUILD.gn delete mode 100644 Meta/gn/secondary/Userland/Libraries/LibJIT/BUILD.gn delete mode 100644 Meta/gn/secondary/Userland/Libraries/LibPDF/BUILD.gn delete mode 100644 Meta/gn/secondary/Userland/Libraries/LibSoftGPU/BUILD.gn delete mode 100644 Meta/gn/secondary/Userland/Libraries/LibX86/BUILD.gn delete mode 100755 Meta/test_pdf.py delete mode 100644 Tests/JSSpecCompiler/CMakeLists.txt delete mode 100644 Tests/JSSpecCompiler/test-runner.cpp delete mode 100644 Tests/LibCpp/CMakeLists.txt delete mode 100644 Tests/LibCpp/test-cpp-parser.cpp delete mode 100644 Tests/LibCpp/test-cpp-preprocessor.cpp delete mode 100644 Tests/LibELF/CMakeLists.txt delete mode 100644 Tests/LibELF/Dynlib.cpp delete mode 100644 Tests/LibELF/TLSDef.cpp delete mode 100644 Tests/LibELF/TLSUse.cpp delete mode 100644 Tests/LibELF/TestDlOpen.cpp delete mode 100644 Tests/LibELF/TestOrder.cpp delete mode 100644 Tests/LibELF/TestOrderExe.cpp delete mode 100644 Tests/LibELF/TestOrderLib1.cpp delete mode 100644 Tests/LibELF/TestOrderLib2.cpp delete mode 100644 Tests/LibELF/TestTLS.cpp delete mode 100644 Tests/LibELF/TestWeakSymbolResolution.cpp delete mode 100644 Tests/LibELF/TestWeakSymbolResolution1.cpp delete mode 100644 Tests/LibELF/TestWeakSymbolResolution2.cpp delete mode 100644 Tests/LibELF/test-elf.cpp delete mode 100644 Tests/LibGL/CMakeLists.txt delete mode 100644 Tests/LibGL/TestAPI.cpp delete mode 100644 Tests/LibGL/TestRender.cpp delete mode 100644 Tests/LibGL/TestShaders.cpp delete mode 100644 Tests/LibGL/reference-images/0001_simple_triangle.qoi delete mode 100644 Tests/LibGL/reference-images/0002_quad_color_interpolation.qoi delete mode 100644 Tests/LibGL/reference-images/0003_rect_w_coordinate_regression.qoi delete mode 100644 Tests/LibGL/reference-images/0004_points.qoi delete mode 100644 Tests/LibGL/reference-images/0005_lines.qoi delete mode 100644 Tests/LibGL/reference-images/0006_test_rgb565_texture.qoi delete mode 100644 Tests/LibGL/reference-images/0007_test_rgba_to_rgb_texture.qoi delete mode 100644 Tests/LibGL/reference-images/0008_test_pop_matrix_regression.qoi delete mode 100644 Tests/LibGL/reference-images/0009_test_draw_elements_in_display_list.qoi delete mode 100644 Tests/LibGL/reference-images/0010_test_store_data_in_buffer.qoi delete mode 100644 Tests/LibGL/reference-images/0011_tex_env_combine_with_constant_color.qoi delete mode 100644 Tests/LibGL/reference-images/0012_blend_equations.qoi delete mode 100644 Tests/LibGLSL/CMakeLists.txt delete mode 100644 Tests/LibGLSL/test-parser.cpp delete mode 100644 Tests/LibPDF/BenchmarkPDF.cpp delete mode 100644 Tests/LibPDF/CMakeLists.txt delete mode 100644 Tests/LibPDF/TestPDF.cpp delete mode 100644 Tests/LibPDF/colorspaces.pdf delete mode 100644 Tests/LibPDF/complex.pdf delete mode 100644 Tests/LibPDF/encoding.pdf delete mode 100644 Tests/LibPDF/encryption_nocopy.pdf delete mode 100644 Tests/LibPDF/jbig2-globals.pdf delete mode 100644 Tests/LibPDF/linearized.pdf delete mode 100644 Tests/LibPDF/non-linearized.pdf delete mode 100644 Tests/LibPDF/oss-fuzz-testcase-62065.pdf delete mode 100644 Tests/LibPDF/password-is-sup.pdf delete mode 100644 Tests/LibPDF/pattern.pdf delete mode 100644 Tests/LibPDF/rotate.pdf delete mode 100644 Tests/LibPDF/standard-14-fonts.pdf delete mode 100644 Tests/LibPDF/text.pdf delete mode 100644 Tests/LibPDF/type1.pdf delete mode 100644 Tests/LibPDF/type3.pdf delete mode 100644 Tests/LibPDF/wide-gamut-only.pdf delete mode 100644 Tests/Spreadsheet/CMakeLists.txt delete mode 100644 Tests/Spreadsheet/test-spreadsheet.cpp delete mode 100644 Tests/Utilities/CMakeLists.txt delete mode 100644 Tests/Utilities/TestPatch.cpp delete mode 100644 Tests/Utilities/TestSed.cpp delete mode 100644 Tests/Utilities/TestUniq.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/CMakeLists.txt delete mode 100644 Userland/Libraries/LibCodeComprehension/CodeComprehensionEngine.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/CodeComprehensionEngine.h delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/CMakeLists.txt delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/ConnectionFromClient.h delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/CppComprehensionEngine.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/CppComprehensionEngine.h delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/Tests.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/Tests.h delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/Tests/.clang-format delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/Tests/complete_includes.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/Tests/complete_local_args.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/Tests/complete_local_vars.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/Tests/complete_type.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/Tests/find_array_variable_declaration.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/Tests/find_variable_declaration.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/Tests/parameters_hint1.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/Cpp/Tests/sample_header.h delete mode 100644 Userland/Libraries/LibCodeComprehension/FileDB.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/FileDB.h delete mode 100644 Userland/Libraries/LibCodeComprehension/Shell/CMakeLists.txt delete mode 100644 Userland/Libraries/LibCodeComprehension/Shell/ConnectionFromClient.h delete mode 100644 Userland/Libraries/LibCodeComprehension/Shell/ShellComprehensionEngine.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/Shell/ShellComprehensionEngine.h delete mode 100644 Userland/Libraries/LibCodeComprehension/Shell/main.cpp delete mode 100644 Userland/Libraries/LibCodeComprehension/Types.h delete mode 100644 Userland/Libraries/LibCpp/AST.cpp delete mode 100644 Userland/Libraries/LibCpp/AST.h delete mode 100644 Userland/Libraries/LibCpp/CMakeLists.txt delete mode 100644 Userland/Libraries/LibCpp/Lexer.cpp delete mode 100644 Userland/Libraries/LibCpp/Lexer.h delete mode 100644 Userland/Libraries/LibCpp/Parser.cpp delete mode 100644 Userland/Libraries/LibCpp/Parser.h delete mode 100644 Userland/Libraries/LibCpp/Preprocessor.cpp delete mode 100644 Userland/Libraries/LibCpp/Preprocessor.h delete mode 100644 Userland/Libraries/LibCpp/SemanticSyntaxHighlighter.cpp delete mode 100644 Userland/Libraries/LibCpp/SemanticSyntaxHighlighter.h delete mode 100644 Userland/Libraries/LibCpp/SyntaxHighlighter.cpp delete mode 100644 Userland/Libraries/LibCpp/SyntaxHighlighter.h delete mode 100644 Userland/Libraries/LibCpp/Tests/.clang-format delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/array-initialization.ast delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/array-initialization.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/class.ast delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/class.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/function-decl.ast delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/function-decl.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/if-else.ast delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/if-else.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/inheritance.ast delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/inheritance.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/local-vars.ast delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/local-vars.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/out-of-line.ast delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/out-of-line.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/strace.ast delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/strace.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/struct.ast delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/struct.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/using-namespace.ast delete mode 100644 Userland/Libraries/LibCpp/Tests/parser/using-namespace.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/preprocessor/macro1.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/preprocessor/macro1.txt delete mode 100644 Userland/Libraries/LibCpp/Tests/preprocessor/macro2.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/preprocessor/macro2.txt delete mode 100644 Userland/Libraries/LibCpp/Tests/preprocessor/macro3.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/preprocessor/macro3.txt delete mode 100644 Userland/Libraries/LibCpp/Tests/preprocessor/simple_define.cpp delete mode 100644 Userland/Libraries/LibCpp/Tests/preprocessor/simple_define.txt delete mode 100644 Userland/Libraries/LibCpp/Token.cpp delete mode 100644 Userland/Libraries/LibCpp/Token.h delete mode 100644 Userland/Libraries/LibELF/Arch/GenericDynamicRelocationType.h delete mode 100644 Userland/Libraries/LibELF/Arch/aarch64/GenericDynamicRelocationType.h delete mode 100644 Userland/Libraries/LibELF/Arch/aarch64/entry.S delete mode 100644 Userland/Libraries/LibELF/Arch/aarch64/plt_trampoline.S delete mode 100644 Userland/Libraries/LibELF/Arch/aarch64/tls.S delete mode 100644 Userland/Libraries/LibELF/Arch/aarch64/tls.cpp delete mode 100644 Userland/Libraries/LibELF/Arch/aarch64/tls.h delete mode 100644 Userland/Libraries/LibELF/Arch/riscv64/GenericDynamicRelocationType.h delete mode 100644 Userland/Libraries/LibELF/Arch/riscv64/entry.S delete mode 100644 Userland/Libraries/LibELF/Arch/riscv64/plt_trampoline.S delete mode 100644 Userland/Libraries/LibELF/Arch/riscv64/tls.cpp delete mode 100644 Userland/Libraries/LibELF/Arch/riscv64/tls.h delete mode 100644 Userland/Libraries/LibELF/Arch/tls.h delete mode 100644 Userland/Libraries/LibELF/Arch/x86_64/GenericDynamicRelocationType.h delete mode 100644 Userland/Libraries/LibELF/Arch/x86_64/entry.S delete mode 100644 Userland/Libraries/LibELF/Arch/x86_64/plt_trampoline.S delete mode 100644 Userland/Libraries/LibELF/Arch/x86_64/tls.cpp delete mode 100644 Userland/Libraries/LibELF/Arch/x86_64/tls.h delete mode 100644 Userland/Libraries/LibELF/AuxiliaryVector.h delete mode 100644 Userland/Libraries/LibELF/CMakeLists.txt delete mode 100644 Userland/Libraries/LibELF/Core.h delete mode 100644 Userland/Libraries/LibELF/DynamicLinker.cpp delete mode 100644 Userland/Libraries/LibELF/DynamicLinker.h delete mode 100644 Userland/Libraries/LibELF/DynamicLoader.cpp delete mode 100644 Userland/Libraries/LibELF/DynamicLoader.h delete mode 100644 Userland/Libraries/LibELF/DynamicObject.cpp delete mode 100644 Userland/Libraries/LibELF/DynamicObject.h delete mode 100644 Userland/Libraries/LibELF/ELFABI.h delete mode 100644 Userland/Libraries/LibELF/ELFBuild.cpp delete mode 100644 Userland/Libraries/LibELF/ELFBuild.h delete mode 100644 Userland/Libraries/LibELF/Hashes.h delete mode 100644 Userland/Libraries/LibELF/Image.cpp delete mode 100644 Userland/Libraries/LibELF/Image.h delete mode 100644 Userland/Libraries/LibELF/Relocation.cpp delete mode 100644 Userland/Libraries/LibELF/Relocation.h delete mode 100644 Userland/Libraries/LibELF/Validation.cpp delete mode 100644 Userland/Libraries/LibELF/Validation.h delete mode 100644 Userland/Libraries/LibGL/Blending.cpp delete mode 100644 Userland/Libraries/LibGL/Buffer.cpp delete mode 100644 Userland/Libraries/LibGL/Buffer/Buffer.cpp delete mode 100644 Userland/Libraries/LibGL/Buffer/Buffer.h delete mode 100644 Userland/Libraries/LibGL/CMakeLists.txt delete mode 100644 Userland/Libraries/LibGL/ClipPlane.cpp delete mode 100644 Userland/Libraries/LibGL/ContextParameter.cpp delete mode 100644 Userland/Libraries/LibGL/GL/gl.h delete mode 100644 Userland/Libraries/LibGL/GL/glext.h delete mode 100644 Userland/Libraries/LibGL/GL/glplatform.h delete mode 100644 Userland/Libraries/LibGL/GLAPI.json delete mode 100644 Userland/Libraries/LibGL/GLContext.cpp delete mode 100644 Userland/Libraries/LibGL/GLContext.h delete mode 100644 Userland/Libraries/LibGL/Image.cpp delete mode 100644 Userland/Libraries/LibGL/Image.h delete mode 100644 Userland/Libraries/LibGL/Lighting.cpp delete mode 100644 Userland/Libraries/LibGL/List.cpp delete mode 100644 Userland/Libraries/LibGL/Matrix.cpp delete mode 100644 Userland/Libraries/LibGL/NameAllocator.cpp delete mode 100644 Userland/Libraries/LibGL/NameAllocator.h delete mode 100644 Userland/Libraries/LibGL/Shader.cpp delete mode 100644 Userland/Libraries/LibGL/Shaders/Program.cpp delete mode 100644 Userland/Libraries/LibGL/Shaders/Program.h delete mode 100644 Userland/Libraries/LibGL/Shaders/Shader.cpp delete mode 100644 Userland/Libraries/LibGL/Shaders/Shader.h delete mode 100644 Userland/Libraries/LibGL/Stencil.cpp delete mode 100644 Userland/Libraries/LibGL/Tex/Sampler2D.h delete mode 100644 Userland/Libraries/LibGL/Tex/Texture.h delete mode 100644 Userland/Libraries/LibGL/Tex/Texture2D.cpp delete mode 100644 Userland/Libraries/LibGL/Tex/Texture2D.h delete mode 100644 Userland/Libraries/LibGL/Tex/TextureUnit.h delete mode 100644 Userland/Libraries/LibGL/Texture.cpp delete mode 100644 Userland/Libraries/LibGL/Vertex.cpp delete mode 100644 Userland/Libraries/LibGLSL/AST.cpp delete mode 100644 Userland/Libraries/LibGLSL/AST.h delete mode 100644 Userland/Libraries/LibGLSL/CMakeLists.txt delete mode 100644 Userland/Libraries/LibGLSL/Compiler.cpp delete mode 100644 Userland/Libraries/LibGLSL/Compiler.h delete mode 100644 Userland/Libraries/LibGLSL/Lexer.cpp delete mode 100644 Userland/Libraries/LibGLSL/Lexer.h delete mode 100644 Userland/Libraries/LibGLSL/LinkedShader.h delete mode 100644 Userland/Libraries/LibGLSL/Linker.cpp delete mode 100644 Userland/Libraries/LibGLSL/Linker.h delete mode 100644 Userland/Libraries/LibGLSL/ObjectFile.h delete mode 100644 Userland/Libraries/LibGLSL/Parser.cpp delete mode 100644 Userland/Libraries/LibGLSL/Parser.h delete mode 100644 Userland/Libraries/LibGLSL/Preprocessor.cpp delete mode 100644 Userland/Libraries/LibGLSL/Preprocessor.h delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/discard.ast delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/discard.glsl delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/expression.ast delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/expression.glsl delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/for-statement.ast delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/for-statement.glsl delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/function-declaration.ast delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/function-declaration.glsl delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/function-definition.ast delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/function-definition.glsl delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/if-else.ast delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/if-else.glsl delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/return.ast delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/return.glsl delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/struct.ast delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/struct.glsl delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/unary-expression.ast delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/unary-expression.glsl delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/variable-declaration.ast delete mode 100644 Userland/Libraries/LibGLSL/Tests/parser/variable-declaration.glsl delete mode 100644 Userland/Libraries/LibGLSL/Token.cpp delete mode 100644 Userland/Libraries/LibGLSL/Token.h delete mode 100644 Userland/Libraries/LibGPU/CMakeLists.txt delete mode 100644 Userland/Libraries/LibGPU/Config.h delete mode 100644 Userland/Libraries/LibGPU/Device.h delete mode 100644 Userland/Libraries/LibGPU/DeviceInfo.h delete mode 100644 Userland/Libraries/LibGPU/Driver.cpp delete mode 100644 Userland/Libraries/LibGPU/Driver.h delete mode 100644 Userland/Libraries/LibGPU/Enums.h delete mode 100644 Userland/Libraries/LibGPU/IR.h delete mode 100644 Userland/Libraries/LibGPU/Image.cpp delete mode 100644 Userland/Libraries/LibGPU/Image.h delete mode 100644 Userland/Libraries/LibGPU/ImageDataLayout.h delete mode 100644 Userland/Libraries/LibGPU/ImageFormat.h delete mode 100644 Userland/Libraries/LibGPU/Light.h delete mode 100644 Userland/Libraries/LibGPU/LightModelParameters.h delete mode 100644 Userland/Libraries/LibGPU/Material.h delete mode 100644 Userland/Libraries/LibGPU/RasterPosition.h delete mode 100644 Userland/Libraries/LibGPU/RasterizerOptions.h delete mode 100644 Userland/Libraries/LibGPU/SamplerConfig.h delete mode 100644 Userland/Libraries/LibGPU/Shader.h delete mode 100644 Userland/Libraries/LibGPU/StencilConfiguration.h delete mode 100644 Userland/Libraries/LibGPU/TextureUnitConfiguration.h delete mode 100644 Userland/Libraries/LibGPU/Vertex.h delete mode 100644 Userland/Libraries/LibGUI/AboutDialog.cpp delete mode 100644 Userland/Libraries/LibGUI/AboutDialog.gml delete mode 100644 Userland/Libraries/LibGUI/AboutDialog.h delete mode 100644 Userland/Libraries/LibGUI/AboutDialogWidget.h delete mode 100644 Userland/Libraries/LibGUI/AbstractButton.cpp delete mode 100644 Userland/Libraries/LibGUI/AbstractButton.h delete mode 100644 Userland/Libraries/LibGUI/AbstractScrollableWidget.cpp delete mode 100644 Userland/Libraries/LibGUI/AbstractScrollableWidget.h delete mode 100644 Userland/Libraries/LibGUI/AbstractSlider.cpp delete mode 100644 Userland/Libraries/LibGUI/AbstractSlider.h delete mode 100644 Userland/Libraries/LibGUI/AbstractTableView.cpp delete mode 100644 Userland/Libraries/LibGUI/AbstractTableView.h delete mode 100644 Userland/Libraries/LibGUI/AbstractThemePreview.cpp delete mode 100644 Userland/Libraries/LibGUI/AbstractThemePreview.h delete mode 100644 Userland/Libraries/LibGUI/AbstractView.cpp delete mode 100644 Userland/Libraries/LibGUI/AbstractView.h delete mode 100644 Userland/Libraries/LibGUI/AbstractZoomPanWidget.cpp delete mode 100644 Userland/Libraries/LibGUI/AbstractZoomPanWidget.h delete mode 100644 Userland/Libraries/LibGUI/Action.cpp delete mode 100644 Userland/Libraries/LibGUI/Action.h delete mode 100644 Userland/Libraries/LibGUI/ActionGroup.cpp delete mode 100644 Userland/Libraries/LibGUI/ActionGroup.h delete mode 100644 Userland/Libraries/LibGUI/Application.cpp delete mode 100644 Userland/Libraries/LibGUI/Application.h delete mode 100644 Userland/Libraries/LibGUI/AutocompleteProvider.cpp delete mode 100644 Userland/Libraries/LibGUI/AutocompleteProvider.h delete mode 100644 Userland/Libraries/LibGUI/BoxLayout.cpp delete mode 100644 Userland/Libraries/LibGUI/BoxLayout.h delete mode 100644 Userland/Libraries/LibGUI/Breadcrumbbar.cpp delete mode 100644 Userland/Libraries/LibGUI/Breadcrumbbar.h delete mode 100644 Userland/Libraries/LibGUI/Button.cpp delete mode 100644 Userland/Libraries/LibGUI/Button.h delete mode 100644 Userland/Libraries/LibGUI/CMakeLists.txt delete mode 100644 Userland/Libraries/LibGUI/Calendar.cpp delete mode 100644 Userland/Libraries/LibGUI/Calendar.h delete mode 100644 Userland/Libraries/LibGUI/CheckBox.cpp delete mode 100644 Userland/Libraries/LibGUI/CheckBox.h delete mode 100644 Userland/Libraries/LibGUI/Clipboard.cpp delete mode 100644 Userland/Libraries/LibGUI/Clipboard.h delete mode 100644 Userland/Libraries/LibGUI/ColorFilterer.h delete mode 100644 Userland/Libraries/LibGUI/ColorInput.cpp delete mode 100644 Userland/Libraries/LibGUI/ColorInput.h delete mode 100644 Userland/Libraries/LibGUI/ColorPicker.cpp delete mode 100644 Userland/Libraries/LibGUI/ColorPicker.h delete mode 100644 Userland/Libraries/LibGUI/ColumnsView.cpp delete mode 100644 Userland/Libraries/LibGUI/ColumnsView.h delete mode 100644 Userland/Libraries/LibGUI/ComboBox.cpp delete mode 100644 Userland/Libraries/LibGUI/ComboBox.h delete mode 100644 Userland/Libraries/LibGUI/Command.h delete mode 100644 Userland/Libraries/LibGUI/CommandPalette.cpp delete mode 100644 Userland/Libraries/LibGUI/CommandPalette.h delete mode 100644 Userland/Libraries/LibGUI/CommonActions.cpp delete mode 100644 Userland/Libraries/LibGUI/CommonLocationsProvider.cpp delete mode 100644 Userland/Libraries/LibGUI/CommonLocationsProvider.h delete mode 100644 Userland/Libraries/LibGUI/CommonMenus.cpp delete mode 100644 Userland/Libraries/LibGUI/ConnectionToWindowManagerServer.cpp delete mode 100644 Userland/Libraries/LibGUI/ConnectionToWindowManagerServer.h delete mode 100644 Userland/Libraries/LibGUI/ConnectionToWindowServer.cpp delete mode 100644 Userland/Libraries/LibGUI/ConnectionToWindowServer.h delete mode 100644 Userland/Libraries/LibGUI/DatePicker.cpp delete mode 100644 Userland/Libraries/LibGUI/DatePicker.h delete mode 100644 Userland/Libraries/LibGUI/DatePickerDialog.gml delete mode 100644 Userland/Libraries/LibGUI/Desktop.cpp delete mode 100644 Userland/Libraries/LibGUI/Desktop.h delete mode 100644 Userland/Libraries/LibGUI/Dialog.cpp delete mode 100644 Userland/Libraries/LibGUI/Dialog.h delete mode 100644 Userland/Libraries/LibGUI/DisplayLink.cpp delete mode 100644 Userland/Libraries/LibGUI/DisplayLink.h delete mode 100644 Userland/Libraries/LibGUI/DragOperation.cpp delete mode 100644 Userland/Libraries/LibGUI/DragOperation.h delete mode 100644 Userland/Libraries/LibGUI/DynamicWidgetContainer.cpp delete mode 100644 Userland/Libraries/LibGUI/DynamicWidgetContainer.h delete mode 100644 Userland/Libraries/LibGUI/DynamicWidgetContainerControls.gml delete mode 100644 Userland/Libraries/LibGUI/DynamicWidgetContainerControls.h delete mode 100644 Userland/Libraries/LibGUI/EditingEngine.cpp delete mode 100644 Userland/Libraries/LibGUI/EditingEngine.h delete mode 100644 Userland/Libraries/LibGUI/EmojiInputDialog.cpp delete mode 100644 Userland/Libraries/LibGUI/EmojiInputDialog.gml delete mode 100644 Userland/Libraries/LibGUI/EmojiInputDialog.h delete mode 100644 Userland/Libraries/LibGUI/EmojiInputDialogWidget.h delete mode 100644 Userland/Libraries/LibGUI/Event.cpp delete mode 100644 Userland/Libraries/LibGUI/Event.h delete mode 100644 Userland/Libraries/LibGUI/FileIconProvider.cpp delete mode 100644 Userland/Libraries/LibGUI/FileIconProvider.h delete mode 100644 Userland/Libraries/LibGUI/FilePicker.cpp delete mode 100644 Userland/Libraries/LibGUI/FilePicker.h delete mode 100644 Userland/Libraries/LibGUI/FilePickerDialog.gml delete mode 100644 Userland/Libraries/LibGUI/FilePickerDialogWidget.h delete mode 100644 Userland/Libraries/LibGUI/FileSystemModel.cpp delete mode 100644 Userland/Libraries/LibGUI/FileSystemModel.h delete mode 100644 Userland/Libraries/LibGUI/FileTypeFilter.h delete mode 100644 Userland/Libraries/LibGUI/FilteringProxyModel.cpp delete mode 100644 Userland/Libraries/LibGUI/FilteringProxyModel.h delete mode 100644 Userland/Libraries/LibGUI/FocusPolicy.h delete mode 100644 Userland/Libraries/LibGUI/FocusSource.h delete mode 100644 Userland/Libraries/LibGUI/FontPicker.cpp delete mode 100644 Userland/Libraries/LibGUI/FontPicker.h delete mode 100644 Userland/Libraries/LibGUI/FontPickerDialog.gml delete mode 100644 Userland/Libraries/LibGUI/FontPickerDialogWidget.h delete mode 100644 Userland/Libraries/LibGUI/Forward.h delete mode 100644 Userland/Libraries/LibGUI/Frame.cpp delete mode 100644 Userland/Libraries/LibGUI/Frame.h delete mode 100644 Userland/Libraries/LibGUI/GML/AST.h delete mode 100644 Userland/Libraries/LibGUI/GML/AutocompleteProvider.cpp delete mode 100644 Userland/Libraries/LibGUI/GML/AutocompleteProvider.h delete mode 100644 Userland/Libraries/LibGUI/GML/Formatter.h delete mode 100644 Userland/Libraries/LibGUI/GML/Lexer.cpp delete mode 100644 Userland/Libraries/LibGUI/GML/Lexer.h delete mode 100644 Userland/Libraries/LibGUI/GML/Parser.cpp delete mode 100644 Userland/Libraries/LibGUI/GML/Parser.h delete mode 100644 Userland/Libraries/LibGUI/GML/SyntaxHighlighter.cpp delete mode 100644 Userland/Libraries/LibGUI/GML/SyntaxHighlighter.h delete mode 100644 Userland/Libraries/LibGUI/GitCommitLexer.cpp delete mode 100644 Userland/Libraries/LibGUI/GitCommitLexer.h delete mode 100644 Userland/Libraries/LibGUI/GitCommitSyntaxHighlighter.cpp delete mode 100644 Userland/Libraries/LibGUI/GitCommitSyntaxHighlighter.h delete mode 100644 Userland/Libraries/LibGUI/GlyphMapWidget.cpp delete mode 100644 Userland/Libraries/LibGUI/GlyphMapWidget.h delete mode 100644 Userland/Libraries/LibGUI/GroupBox.cpp delete mode 100644 Userland/Libraries/LibGUI/GroupBox.h delete mode 100644 Userland/Libraries/LibGUI/HeaderView.cpp delete mode 100644 Userland/Libraries/LibGUI/HeaderView.h delete mode 100644 Userland/Libraries/LibGUI/HorizontalSlider.h delete mode 100644 Userland/Libraries/LibGUI/INILexer.cpp delete mode 100644 Userland/Libraries/LibGUI/INILexer.h delete mode 100644 Userland/Libraries/LibGUI/INISyntaxHighlighter.cpp delete mode 100644 Userland/Libraries/LibGUI/INISyntaxHighlighter.h delete mode 100644 Userland/Libraries/LibGUI/Icon.cpp delete mode 100644 Userland/Libraries/LibGUI/Icon.h delete mode 100644 Userland/Libraries/LibGUI/IconView.cpp delete mode 100644 Userland/Libraries/LibGUI/IconView.h delete mode 100644 Userland/Libraries/LibGUI/ImageWidget.cpp delete mode 100644 Userland/Libraries/LibGUI/ImageWidget.h delete mode 100644 Userland/Libraries/LibGUI/IncrementalSearchBanner.cpp delete mode 100644 Userland/Libraries/LibGUI/IncrementalSearchBanner.gml delete mode 100644 Userland/Libraries/LibGUI/IncrementalSearchBanner.h delete mode 100644 Userland/Libraries/LibGUI/InputBox.cpp delete mode 100644 Userland/Libraries/LibGUI/InputBox.h delete mode 100644 Userland/Libraries/LibGUI/ItemListModel.h delete mode 100644 Userland/Libraries/LibGUI/JsonArrayModel.cpp delete mode 100644 Userland/Libraries/LibGUI/JsonArrayModel.h delete mode 100644 Userland/Libraries/LibGUI/Label.cpp delete mode 100644 Userland/Libraries/LibGUI/Label.h delete mode 100644 Userland/Libraries/LibGUI/LabelWithEventDispatcher.cpp delete mode 100644 Userland/Libraries/LibGUI/LabelWithEventDispatcher.h delete mode 100644 Userland/Libraries/LibGUI/Layout.cpp delete mode 100644 Userland/Libraries/LibGUI/Layout.h delete mode 100644 Userland/Libraries/LibGUI/LazyWidget.cpp delete mode 100644 Userland/Libraries/LibGUI/LazyWidget.h delete mode 100644 Userland/Libraries/LibGUI/LinkLabel.cpp delete mode 100644 Userland/Libraries/LibGUI/LinkLabel.h delete mode 100644 Userland/Libraries/LibGUI/ListView.cpp delete mode 100644 Userland/Libraries/LibGUI/ListView.h delete mode 100644 Userland/Libraries/LibGUI/Margins.h delete mode 100644 Userland/Libraries/LibGUI/Menu.cpp delete mode 100644 Userland/Libraries/LibGUI/Menu.h delete mode 100644 Userland/Libraries/LibGUI/MenuItem.cpp delete mode 100644 Userland/Libraries/LibGUI/MenuItem.h delete mode 100644 Userland/Libraries/LibGUI/Menubar.cpp delete mode 100644 Userland/Libraries/LibGUI/Menubar.h delete mode 100644 Userland/Libraries/LibGUI/MessageBox.cpp delete mode 100644 Userland/Libraries/LibGUI/MessageBox.h delete mode 100644 Userland/Libraries/LibGUI/Model.cpp delete mode 100644 Userland/Libraries/LibGUI/Model.h delete mode 100644 Userland/Libraries/LibGUI/ModelEditingDelegate.h delete mode 100644 Userland/Libraries/LibGUI/ModelIndex.cpp delete mode 100644 Userland/Libraries/LibGUI/ModelIndex.h delete mode 100644 Userland/Libraries/LibGUI/ModelRole.h delete mode 100644 Userland/Libraries/LibGUI/ModelSelection.cpp delete mode 100644 Userland/Libraries/LibGUI/ModelSelection.h delete mode 100644 Userland/Libraries/LibGUI/MouseTracker.cpp delete mode 100644 Userland/Libraries/LibGUI/MouseTracker.h delete mode 100644 Userland/Libraries/LibGUI/MultiView.cpp delete mode 100644 Userland/Libraries/LibGUI/MultiView.h delete mode 100644 Userland/Libraries/LibGUI/Notification.cpp delete mode 100644 Userland/Libraries/LibGUI/Notification.h delete mode 100644 Userland/Libraries/LibGUI/NumericInput.cpp delete mode 100644 Userland/Libraries/LibGUI/NumericInput.h delete mode 100644 Userland/Libraries/LibGUI/Object.cpp delete mode 100644 Userland/Libraries/LibGUI/Object.h delete mode 100644 Userland/Libraries/LibGUI/OpacitySlider.cpp delete mode 100644 Userland/Libraries/LibGUI/OpacitySlider.h delete mode 100644 Userland/Libraries/LibGUI/Painter.cpp delete mode 100644 Userland/Libraries/LibGUI/Painter.h delete mode 100644 Userland/Libraries/LibGUI/PasswordInputDialog.cpp delete mode 100644 Userland/Libraries/LibGUI/PasswordInputDialog.gml delete mode 100644 Userland/Libraries/LibGUI/PasswordInputDialog.h delete mode 100644 Userland/Libraries/LibGUI/PasswordInputDialogWidget.h delete mode 100644 Userland/Libraries/LibGUI/PathBreadcrumbbar.cpp delete mode 100644 Userland/Libraries/LibGUI/PathBreadcrumbbar.h delete mode 100644 Userland/Libraries/LibGUI/PersistentModelIndex.cpp delete mode 100644 Userland/Libraries/LibGUI/PersistentModelIndex.h delete mode 100644 Userland/Libraries/LibGUI/Process.cpp delete mode 100644 Userland/Libraries/LibGUI/Process.h delete mode 100644 Userland/Libraries/LibGUI/ProcessChooser.cpp delete mode 100644 Userland/Libraries/LibGUI/ProcessChooser.h delete mode 100644 Userland/Libraries/LibGUI/Progressbar.cpp delete mode 100644 Userland/Libraries/LibGUI/Progressbar.h delete mode 100644 Userland/Libraries/LibGUI/Property.cpp delete mode 100644 Userland/Libraries/LibGUI/Property.h delete mode 100644 Userland/Libraries/LibGUI/PropertyDeserializer.cpp delete mode 100644 Userland/Libraries/LibGUI/PropertyDeserializer.h delete mode 100644 Userland/Libraries/LibGUI/RadioButton.cpp delete mode 100644 Userland/Libraries/LibGUI/RadioButton.h delete mode 100644 Userland/Libraries/LibGUI/RangeSlider.cpp delete mode 100644 Userland/Libraries/LibGUI/RangeSlider.h delete mode 100644 Userland/Libraries/LibGUI/RegularEditingEngine.cpp delete mode 100644 Userland/Libraries/LibGUI/RegularEditingEngine.h delete mode 100644 Userland/Libraries/LibGUI/ResizeCorner.cpp delete mode 100644 Userland/Libraries/LibGUI/ResizeCorner.h delete mode 100644 Userland/Libraries/LibGUI/ResizeDirection.h delete mode 100644 Userland/Libraries/LibGUI/RunningProcessesModel.cpp delete mode 100644 Userland/Libraries/LibGUI/RunningProcessesModel.h delete mode 100644 Userland/Libraries/LibGUI/ScreenLayout.cpp delete mode 100644 Userland/Libraries/LibGUI/ScrollableContainerWidget.cpp delete mode 100644 Userland/Libraries/LibGUI/ScrollableContainerWidget.h delete mode 100644 Userland/Libraries/LibGUI/Scrollbar.cpp delete mode 100644 Userland/Libraries/LibGUI/Scrollbar.h delete mode 100644 Userland/Libraries/LibGUI/SeparatorWidget.cpp delete mode 100644 Userland/Libraries/LibGUI/SeparatorWidget.h delete mode 100644 Userland/Libraries/LibGUI/SettingsWindow.cpp delete mode 100644 Userland/Libraries/LibGUI/SettingsWindow.h delete mode 100644 Userland/Libraries/LibGUI/Shortcut.cpp delete mode 100644 Userland/Libraries/LibGUI/Shortcut.h delete mode 100644 Userland/Libraries/LibGUI/Slider.cpp delete mode 100644 Userland/Libraries/LibGUI/Slider.h delete mode 100644 Userland/Libraries/LibGUI/SortingProxyModel.cpp delete mode 100644 Userland/Libraries/LibGUI/SortingProxyModel.h delete mode 100644 Userland/Libraries/LibGUI/SpinBox.cpp delete mode 100644 Userland/Libraries/LibGUI/SpinBox.h delete mode 100644 Userland/Libraries/LibGUI/Splitter.cpp delete mode 100644 Userland/Libraries/LibGUI/Splitter.h delete mode 100644 Userland/Libraries/LibGUI/StackWidget.cpp delete mode 100644 Userland/Libraries/LibGUI/StackWidget.h delete mode 100644 Userland/Libraries/LibGUI/Statusbar.cpp delete mode 100644 Userland/Libraries/LibGUI/Statusbar.h delete mode 100644 Userland/Libraries/LibGUI/SystemEffects.h delete mode 100644 Userland/Libraries/LibGUI/TabWidget.cpp delete mode 100644 Userland/Libraries/LibGUI/TabWidget.h delete mode 100644 Userland/Libraries/LibGUI/TableView.cpp delete mode 100644 Userland/Libraries/LibGUI/TableView.h delete mode 100644 Userland/Libraries/LibGUI/TextBox.cpp delete mode 100644 Userland/Libraries/LibGUI/TextBox.h delete mode 100644 Userland/Libraries/LibGUI/TextDocument.cpp delete mode 100644 Userland/Libraries/LibGUI/TextDocument.h delete mode 100644 Userland/Libraries/LibGUI/TextEditor.cpp delete mode 100644 Userland/Libraries/LibGUI/TextEditor.h delete mode 100644 Userland/Libraries/LibGUI/TextPosition.h delete mode 100644 Userland/Libraries/LibGUI/TextRange.h delete mode 100644 Userland/Libraries/LibGUI/Toolbar.cpp delete mode 100644 Userland/Libraries/LibGUI/Toolbar.h delete mode 100644 Userland/Libraries/LibGUI/ToolbarContainer.cpp delete mode 100644 Userland/Libraries/LibGUI/ToolbarContainer.h delete mode 100644 Userland/Libraries/LibGUI/Tray.cpp delete mode 100644 Userland/Libraries/LibGUI/Tray.h delete mode 100644 Userland/Libraries/LibGUI/TreeView.cpp delete mode 100644 Userland/Libraries/LibGUI/TreeView.h delete mode 100644 Userland/Libraries/LibGUI/TreeViewModel.cpp delete mode 100644 Userland/Libraries/LibGUI/TreeViewModel.h delete mode 100644 Userland/Libraries/LibGUI/UIDimensions.h delete mode 100644 Userland/Libraries/LibGUI/UndoStack.cpp delete mode 100644 Userland/Libraries/LibGUI/UndoStack.h delete mode 100644 Userland/Libraries/LibGUI/ValueSlider.cpp delete mode 100644 Userland/Libraries/LibGUI/ValueSlider.h delete mode 100644 Userland/Libraries/LibGUI/Variant.cpp delete mode 100644 Userland/Libraries/LibGUI/Variant.h delete mode 100644 Userland/Libraries/LibGUI/VimEditingEngine.cpp delete mode 100644 Userland/Libraries/LibGUI/VimEditingEngine.h delete mode 100644 Userland/Libraries/LibGUI/Widget.cpp delete mode 100644 Userland/Libraries/LibGUI/Widget.h delete mode 100644 Userland/Libraries/LibGUI/Window.cpp delete mode 100644 Userland/Libraries/LibGUI/Window.h delete mode 100644 Userland/Libraries/LibGUI/WindowMode.h delete mode 100644 Userland/Libraries/LibGUI/WindowType.h delete mode 100644 Userland/Libraries/LibGUI/Wizards/AbstractWizardPage.cpp delete mode 100644 Userland/Libraries/LibGUI/Wizards/AbstractWizardPage.h delete mode 100644 Userland/Libraries/LibGUI/Wizards/CoverWizardPage.cpp delete mode 100644 Userland/Libraries/LibGUI/Wizards/CoverWizardPage.h delete mode 100644 Userland/Libraries/LibGUI/Wizards/WizardDialog.cpp delete mode 100644 Userland/Libraries/LibGUI/Wizards/WizardDialog.h delete mode 100644 Userland/Libraries/LibGUI/Wizards/WizardPage.cpp delete mode 100644 Userland/Libraries/LibGUI/Wizards/WizardPage.h delete mode 100644 Userland/Libraries/LibJIT/Assembler.cpp delete mode 100644 Userland/Libraries/LibJIT/Assembler.h delete mode 100644 Userland/Libraries/LibJIT/CMakeLists.txt delete mode 100644 Userland/Libraries/LibJIT/GDB.cpp delete mode 100644 Userland/Libraries/LibJIT/GDB.h delete mode 100644 Userland/Libraries/LibJIT/GDBElf.cpp delete mode 100644 Userland/Libraries/LibJIT/GDBUnsupported.cpp delete mode 100644 Userland/Libraries/LibJIT/X86_64/Assembler.h delete mode 100644 Userland/Libraries/LibPDF/CMakeLists.txt delete mode 100644 Userland/Libraries/LibPDF/ColorSpace.cpp delete mode 100644 Userland/Libraries/LibPDF/ColorSpace.h delete mode 100644 Userland/Libraries/LibPDF/CommonNames.cpp delete mode 100644 Userland/Libraries/LibPDF/CommonNames.h delete mode 100644 Userland/Libraries/LibPDF/Document.cpp delete mode 100644 Userland/Libraries/LibPDF/Document.h delete mode 100644 Userland/Libraries/LibPDF/DocumentParser.cpp delete mode 100644 Userland/Libraries/LibPDF/DocumentParser.h delete mode 100644 Userland/Libraries/LibPDF/Encoding.cpp delete mode 100644 Userland/Libraries/LibPDF/Encoding.h delete mode 100644 Userland/Libraries/LibPDF/Encryption.cpp delete mode 100644 Userland/Libraries/LibPDF/Encryption.h delete mode 100644 Userland/Libraries/LibPDF/Error.h delete mode 100644 Userland/Libraries/LibPDF/Filter.cpp delete mode 100644 Userland/Libraries/LibPDF/Filter.h delete mode 100644 Userland/Libraries/LibPDF/Fonts/AdobeGlyphList.cpp delete mode 100644 Userland/Libraries/LibPDF/Fonts/AdobeGlyphList.h delete mode 100644 Userland/Libraries/LibPDF/Fonts/CFF.cpp delete mode 100644 Userland/Libraries/LibPDF/Fonts/CFF.h delete mode 100644 Userland/Libraries/LibPDF/Fonts/PDFFont.cpp delete mode 100644 Userland/Libraries/LibPDF/Fonts/PDFFont.h delete mode 100644 Userland/Libraries/LibPDF/Fonts/PS1FontProgram.cpp delete mode 100644 Userland/Libraries/LibPDF/Fonts/PS1FontProgram.h delete mode 100644 Userland/Libraries/LibPDF/Fonts/SimpleFont.cpp delete mode 100644 Userland/Libraries/LibPDF/Fonts/SimpleFont.h delete mode 100644 Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp delete mode 100644 Userland/Libraries/LibPDF/Fonts/TrueTypeFont.h delete mode 100644 Userland/Libraries/LibPDF/Fonts/Type0Font.cpp delete mode 100644 Userland/Libraries/LibPDF/Fonts/Type0Font.h delete mode 100644 Userland/Libraries/LibPDF/Fonts/Type1Font.cpp delete mode 100644 Userland/Libraries/LibPDF/Fonts/Type1Font.h delete mode 100644 Userland/Libraries/LibPDF/Fonts/Type1FontProgram.cpp delete mode 100644 Userland/Libraries/LibPDF/Fonts/Type1FontProgram.h delete mode 100644 Userland/Libraries/LibPDF/Fonts/Type3Font.cpp delete mode 100644 Userland/Libraries/LibPDF/Fonts/Type3Font.h delete mode 100644 Userland/Libraries/LibPDF/Forward.h delete mode 100644 Userland/Libraries/LibPDF/Function.cpp delete mode 100644 Userland/Libraries/LibPDF/Function.h delete mode 100644 Userland/Libraries/LibPDF/Interpolation.cpp delete mode 100644 Userland/Libraries/LibPDF/Interpolation.h delete mode 100644 Userland/Libraries/LibPDF/Object.h delete mode 100644 Userland/Libraries/LibPDF/ObjectDerivatives.cpp delete mode 100644 Userland/Libraries/LibPDF/ObjectDerivatives.h delete mode 100644 Userland/Libraries/LibPDF/Operator.h delete mode 100644 Userland/Libraries/LibPDF/Page.cpp delete mode 100644 Userland/Libraries/LibPDF/Page.h delete mode 100644 Userland/Libraries/LibPDF/Parser.cpp delete mode 100644 Userland/Libraries/LibPDF/Parser.h delete mode 100644 Userland/Libraries/LibPDF/Reader.cpp delete mode 100644 Userland/Libraries/LibPDF/Reader.h delete mode 100644 Userland/Libraries/LibPDF/Reference.h delete mode 100644 Userland/Libraries/LibPDF/Renderer.cpp delete mode 100644 Userland/Libraries/LibPDF/Renderer.h delete mode 100644 Userland/Libraries/LibPDF/Value.cpp delete mode 100644 Userland/Libraries/LibPDF/Value.h delete mode 100644 Userland/Libraries/LibPDF/XRefTable.h delete mode 100644 Userland/Libraries/LibSoftGPU/Buffer/FrameBuffer.h delete mode 100644 Userland/Libraries/LibSoftGPU/Buffer/Typed2DBuffer.h delete mode 100644 Userland/Libraries/LibSoftGPU/Buffer/Typed3DBuffer.h delete mode 100644 Userland/Libraries/LibSoftGPU/CMakeLists.txt delete mode 100644 Userland/Libraries/LibSoftGPU/Clipper.cpp delete mode 100644 Userland/Libraries/LibSoftGPU/Clipper.h delete mode 100644 Userland/Libraries/LibSoftGPU/Config.h delete mode 100644 Userland/Libraries/LibSoftGPU/Device.cpp delete mode 100644 Userland/Libraries/LibSoftGPU/Device.h delete mode 100644 Userland/Libraries/LibSoftGPU/ISA.h delete mode 100644 Userland/Libraries/LibSoftGPU/Image.cpp delete mode 100644 Userland/Libraries/LibSoftGPU/Image.h delete mode 100644 Userland/Libraries/LibSoftGPU/PixelConverter.cpp delete mode 100644 Userland/Libraries/LibSoftGPU/PixelConverter.h delete mode 100644 Userland/Libraries/LibSoftGPU/PixelQuad.h delete mode 100644 Userland/Libraries/LibSoftGPU/SIMD.h delete mode 100644 Userland/Libraries/LibSoftGPU/Sampler.cpp delete mode 100644 Userland/Libraries/LibSoftGPU/Sampler.h delete mode 100644 Userland/Libraries/LibSoftGPU/Shader.cpp delete mode 100644 Userland/Libraries/LibSoftGPU/Shader.h delete mode 100644 Userland/Libraries/LibSoftGPU/ShaderCompiler.cpp delete mode 100644 Userland/Libraries/LibSoftGPU/ShaderCompiler.h delete mode 100644 Userland/Libraries/LibSoftGPU/ShaderProcessor.cpp delete mode 100644 Userland/Libraries/LibSoftGPU/ShaderProcessor.h delete mode 100644 Userland/Libraries/LibSoftGPU/Triangle.h delete mode 100644 Userland/Libraries/LibWebView/OutOfProcessWebView.cpp delete mode 100644 Userland/Libraries/LibWebView/OutOfProcessWebView.h delete mode 100644 Userland/Libraries/LibX86/CMakeLists.txt delete mode 100644 Userland/Libraries/LibX86/Disassembler.h delete mode 100644 Userland/Libraries/LibX86/ELFSymbolProvider.h delete mode 100644 Userland/Libraries/LibX86/Instruction.cpp delete mode 100644 Userland/Libraries/LibX86/Instruction.h delete mode 100644 Userland/Libraries/LibX86/Interpreter.h delete mode 100644 Userland/Services/WebContent/Documentation.txt delete mode 100644 Userland/Services/WindowServer/ResizeDirection.h delete mode 100644 Userland/Services/WindowServer/WindowMode.h delete mode 100644 Userland/Services/WindowServer/WindowType.h delete mode 100644 Userland/Utilities/adjtime.cpp delete mode 100644 Userland/Utilities/file.cpp delete mode 100644 Userland/Utilities/pdf.cpp diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index dea995b913e..fa3269e5190 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,20 +3,15 @@ /AK/*Stream.* @timschumi /Lagom/Tools/CodeGenerators/LibWeb @AtkinsSJ /Tests/LibCompress @timschumi -/Toolchain @BertalanD /Userland/Libraries/LibArchive @timschumi /Userland/Libraries/LibCompress @timschumi /Userland/Libraries/LibCore/File.* @timschumi /Userland/Libraries/LibCore/Socket.* @timschumi /Userland/Libraries/LibCrypto @alimpfard -/Userland/Libraries/LibELF @BertalanD -/Userland/Libraries/LibGL @GMTA -/Userland/Libraries/LibGPU @GMTA /Userland/Libraries/LibHTTP @alimpfard /Userland/Libraries/LibJS/Runtime/Intl @trflynn89 /Userland/Libraries/LibLocale @trflynn89 /Userland/Libraries/LibRegex @alimpfard -/Userland/Libraries/LibSoftGPU @GMTA /Userland/Libraries/LibSQL @GMTA @trflynn89 /Userland/Libraries/LibTLS @alimpfard /Userland/Libraries/LibTimeZone @trflynn89 diff --git a/AK/FixedStringBuffer.h b/AK/FixedStringBuffer.h deleted file mode 100644 index 20e03a6d31c..00000000000 --- a/AK/FixedStringBuffer.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2023, Liav A. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -#ifdef KERNEL -# include -# include -# include -#endif - -namespace AK { - -template -class FixedStringBuffer { -public: - [[nodiscard]] static ErrorOr> vformatted(StringView fmtstr, AK::TypeErasedFormatParams& params) - requires(Size < StringBuilder::inline_capacity) - { - StringBuilder builder { StringBuilder::UseInlineCapacityOnly::Yes }; - TRY(AK::vformat(builder, fmtstr, params)); - FixedStringBuffer buffer {}; - buffer.store_characters(builder.string_view()); - return buffer; - } - - template - [[nodiscard]] static ErrorOr> formatted(CheckedFormatString&& fmtstr, Parameters const&... parameters) - requires(Size < StringBuilder::inline_capacity) - { - AK::VariadicFormatParams variadic_format_parameters { parameters... }; - return vformatted(fmtstr.view(), variadic_format_parameters); - } - - void store_characters(StringView characters) - { - // NOTE: Only store the characters up to the first null terminator - // because we don't care about any further characters. - // This matches some expected behavior in the Kernel code, because - // technically userspace programs could send a syscall argument with - // multiple null terminators - we only care about the *first* chunk up to - // the first null terminator, if present at all. - size_t stored_length = 0; - for (; stored_length < min(Size, characters.length()); stored_length++) { - if (characters[stored_length] == '\0') - break; - m_storage[stored_length] = characters[stored_length]; - } - m_stored_length = stored_length; - // NOTE: Fill the rest of the array bytes with zeroes, just to be - // on the safe side. - // Technically, it means that a sent StringView could occupy the - // entire storage without any null terminators and that's OK as well. - for (size_t index = m_stored_length; index < Size; index++) - m_storage[index] = '\0'; - } - -#ifdef KERNEL - ErrorOr copy_characters_from_user(Userspace user_str, size_t user_str_size) - { - if (user_str_size > Size) - return EFAULT; - bool is_user = Kernel::Memory::is_user_range(user_str.vaddr(), user_str_size); - if (!is_user) - return EFAULT; - Kernel::SmapDisabler disabler; - void* fault_at; - ssize_t length = Kernel::safe_strnlen(user_str.unsafe_userspace_ptr(), user_str_size, fault_at); - if (length < 0) { - dbgln("FixedStringBuffer::copy_characters_into_storage({:p}, {}) failed at {} (strnlen)", static_cast(user_str.unsafe_userspace_ptr()), user_str_size, VirtualAddress { fault_at }); - return EFAULT; - } - if (!Kernel::safe_memcpy(m_storage.data(), user_str.unsafe_userspace_ptr(), (size_t)length, fault_at)) { - dbgln("FixedStringBuffer::copy_characters_into_storage({:p}, {}) failed at {} (memcpy)", static_cast(user_str.unsafe_userspace_ptr()), user_str_size, VirtualAddress { fault_at }); - return EFAULT; - } - m_stored_length = (size_t)length; - for (size_t index = m_stored_length; index < Size; index++) - m_storage[index] = '\0'; - return {}; - } -#endif - - Span storage() - { - return m_storage.span(); - } - StringView representable_view() const { return StringView(m_storage.data(), m_stored_length); } - Span span_view_ensuring_ending_null_char() - { - VERIFY(m_stored_length + 1 <= Size); - m_storage[m_stored_length] = '\0'; - return Span(m_storage.data(), m_stored_length + 1); - } - - size_t stored_length() const { return m_stored_length; } - - FixedStringBuffer() - { - m_storage.fill(0); - } - -private: - Array m_storage; - size_t m_stored_length { 0 }; -}; - -} - -#if USING_AK_GLOBALLY -using AK::FixedStringBuffer; -#endif diff --git a/AK/UBSanitizer.h b/AK/UBSanitizer.h deleted file mode 100644 index 23157ab5b16..00000000000 --- a/AK/UBSanitizer.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2021, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace AK::UBSanitizer { - -extern Atomic g_ubsan_is_deadly; - -typedef void* ValueHandle; - -class SourceLocation { - AK_MAKE_NONCOPYABLE(SourceLocation); - -public: - char const* filename() const { return m_filename; } - u32 line() const { return m_line; } - u32 column() const { return m_column; } - - // Replace the location information in the .data segment with one that won't be logged in the future - // Using this method prevents log spam when sanitizers are not deadly by not logging the exact same - // code paths multiple times. - SourceLocation permanently_clear() { return move(*this); } - - bool needs_logging() const { return !(m_filename == nullptr); } - - SourceLocation() = default; - SourceLocation(SourceLocation&& other) - : m_filename(other.m_filename) - , m_line(other.m_line) - , m_column(other.m_column) - { - other = {}; - } - - SourceLocation& operator=(SourceLocation&& other) - { - if (this != &other) { - m_filename = exchange(other.m_filename, nullptr); - m_line = exchange(other.m_line, 0); - m_column = exchange(other.m_column, 0); - } - return *this; - } - -private: - char const* m_filename { nullptr }; - u32 m_line { 0 }; - u32 m_column { 0 }; -}; - -enum TypeKind : u16 { - Integer = 0, - Float = 1, - Unknown = 0xffff, -}; - -class TypeDescriptor { -public: - char const* name() const { return m_name; } - TypeKind kind() const { return (TypeKind)m_kind; } - bool is_integer() const { return kind() == TypeKind::Integer; } - bool is_signed() const { return m_info & 1; } - bool is_unsigned() const { return !is_signed(); } - size_t bit_width() const { return 1 << (m_info >> 1); } - -private: - u16 m_kind; - u16 m_info; - char m_name[1]; -}; - -struct InvalidValueData { - SourceLocation location; - TypeDescriptor const& type; -}; - -struct NonnullArgData { - SourceLocation location; - SourceLocation attribute_location; - int argument_index; -}; - -struct NonnullReturnData { - SourceLocation attribute_location; -}; - -struct OverflowData { - SourceLocation location; - TypeDescriptor const& type; -}; - -struct VLABoundData { - SourceLocation location; - TypeDescriptor const& type; -}; - -struct ShiftOutOfBoundsData { - SourceLocation location; - TypeDescriptor const& lhs_type; - TypeDescriptor const& rhs_type; -}; - -struct OutOfBoundsData { - SourceLocation location; - TypeDescriptor const& array_type; - TypeDescriptor const& index_type; -}; - -struct TypeMismatchData { - SourceLocation location; - TypeDescriptor const& type; - u8 log_alignment; - u8 type_check_kind; -}; - -struct AlignmentAssumptionData { - SourceLocation location; - SourceLocation assumption_location; - TypeDescriptor const& type; -}; - -struct UnreachableData { - SourceLocation location; -}; - -struct ImplicitConversionData { - SourceLocation location; - TypeDescriptor const& from_type; - TypeDescriptor const& to_type; - /* ImplicitConversionCheckKind */ unsigned char kind; -}; - -struct InvalidBuiltinData { - SourceLocation location; - unsigned char kind; -}; - -struct PointerOverflowData { - SourceLocation location; -}; - -struct FunctionTypeMismatchData { - SourceLocation location; - TypeDescriptor const& type; -}; - -struct FloatCastOverflowData { - SourceLocation location; - TypeDescriptor const& from_type; - TypeDescriptor const& to_type; -}; - -} diff --git a/AK/Userspace.h b/AK/Userspace.h deleted file mode 100644 index 9314542ca2f..00000000000 --- a/AK/Userspace.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -#ifdef KERNEL -# include -#endif - -namespace AK { - -template -concept PointerTypeName = IsPointer; - -template -class Userspace { -public: - Userspace() = default; - - // Disable default implementations that would use surprising integer promotion. - bool operator==(Userspace const&) const = delete; - bool operator<=(Userspace const&) const = delete; - bool operator>=(Userspace const&) const = delete; - bool operator<(Userspace const&) const = delete; - bool operator>(Userspace const&) const = delete; - -#ifdef KERNEL - Userspace(FlatPtr ptr) - : m_ptr(ptr) - { - } - - explicit operator bool() const { return m_ptr != 0; } - - FlatPtr ptr() const { return m_ptr; } - VirtualAddress vaddr() const { return VirtualAddress(m_ptr); } - T unsafe_userspace_ptr() const { return reinterpret_cast(m_ptr); } -#else - Userspace(T ptr) - : m_ptr(ptr) - { - } - - explicit operator bool() const { return m_ptr != nullptr; } - - T ptr() const { return m_ptr; } -#endif - -private: -#ifdef KERNEL - FlatPtr m_ptr { 0 }; -#else - T m_ptr { nullptr }; -#endif -}; - -template -inline Userspace static_ptr_cast(Userspace const& ptr) -{ -#ifdef KERNEL - auto casted_ptr = static_cast(ptr.unsafe_userspace_ptr()); -#else - auto casted_ptr = static_cast(ptr.ptr()); -#endif - return Userspace(reinterpret_cast(casted_ptr)); -} - -} - -#if USING_AK_GLOBALLY -using AK::static_ptr_cast; -using AK::Userspace; -#endif diff --git a/Kernel/FileSystem/CustodyBase.cpp b/Kernel/FileSystem/CustodyBase.cpp deleted file mode 100644 index 03fc8c3f4c3..00000000000 --- a/Kernel/FileSystem/CustodyBase.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2024, Liav A. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -namespace Kernel { - -ErrorOr> CustodyBase::resolve() const -{ - if (m_base) - return *m_base; - if (KLexicalPath::is_absolute(m_path)) - return VirtualFileSystem::the().root_custody(); - return Process::current().custody_for_dirfd({}, m_dirfd); -} - -} diff --git a/Kernel/FileSystem/CustodyBase.h b/Kernel/FileSystem/CustodyBase.h deleted file mode 100644 index 3fd12262ed4..00000000000 --- a/Kernel/FileSystem/CustodyBase.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2024, Liav A. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace Kernel { - -class CustodyBase { -public: - CustodyBase(int dirfd, StringView path) - : m_path(path) - , m_dirfd(dirfd) - { - } - - CustodyBase(NonnullRefPtr base) - : m_base(base) - { - } - - CustodyBase(Custody& base) - : m_base(base) - { - } - - CustodyBase(Custody const& base) - : m_base(base) - { - } - - ErrorOr> resolve() const; - -private: - RefPtr const m_base; - StringView m_path; - int m_dirfd { -1 }; -}; - -} diff --git a/Kernel/Memory/VirtualAddress.h b/Kernel/Memory/VirtualAddress.h deleted file mode 100644 index 52817266cd4..00000000000 --- a/Kernel/Memory/VirtualAddress.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -class VirtualAddress { -public: - VirtualAddress() = default; - constexpr explicit VirtualAddress(FlatPtr address) - : m_address(address) - { - } - - explicit VirtualAddress(void const* address) - : m_address((FlatPtr)address) - { - } - - [[nodiscard]] constexpr bool is_null() const { return m_address == 0; } - [[nodiscard]] constexpr bool is_page_aligned() const { return (m_address & 0xfff) == 0; } - - [[nodiscard]] constexpr VirtualAddress offset(FlatPtr o) const { return VirtualAddress(m_address + o); } - [[nodiscard]] constexpr FlatPtr get() const { return m_address; } - void set(FlatPtr address) { m_address = address; } - void mask(FlatPtr m) { m_address &= m; } - - bool operator<=(VirtualAddress const& other) const { return m_address <= other.m_address; } - bool operator>=(VirtualAddress const& other) const { return m_address >= other.m_address; } - bool operator>(VirtualAddress const& other) const { return m_address > other.m_address; } - bool operator<(VirtualAddress const& other) const { return m_address < other.m_address; } - bool operator==(VirtualAddress const& other) const { return m_address == other.m_address; } - bool operator!=(VirtualAddress const& other) const { return m_address != other.m_address; } - - // NOLINTNEXTLINE(readability-make-member-function-const) const VirtualAddress shouldn't be allowed to modify the underlying memory - [[nodiscard]] u8* as_ptr() { return reinterpret_cast(m_address); } - [[nodiscard]] u8 const* as_ptr() const { return reinterpret_cast(m_address); } - - [[nodiscard]] VirtualAddress page_base() const { return VirtualAddress(m_address & ~(FlatPtr)0xfffu); } - -private: - FlatPtr m_address { 0 }; -}; - -inline VirtualAddress operator-(VirtualAddress const& a, VirtualAddress const& b) -{ - return VirtualAddress(a.get() - b.get()); -} - -template<> -struct AK::Formatter : AK::Formatter { - ErrorOr format(FormatBuilder& builder, VirtualAddress const& value) - { - return AK::Formatter::format(builder, "V{}"sv, value.as_ptr()); - } -}; diff --git a/Meta/CMake/code_generators.cmake b/Meta/CMake/code_generators.cmake index 0c96f2d8f4f..4613cb91299 100644 --- a/Meta/CMake/code_generators.cmake +++ b/Meta/CMake/code_generators.cmake @@ -29,22 +29,6 @@ function(stringify_gml source output string_name) embed_as_string_view(${output_name} ${source} ${output} ${string_name}) endfunction() -function(compile_gml source output) - set(source ${CMAKE_CURRENT_SOURCE_DIR}/${source}) - add_custom_command( - OUTPUT ${output} - COMMAND $ ${source} > ${output}.tmp - COMMAND "${CMAKE_COMMAND}" -E copy_if_different ${output}.tmp ${output} - COMMAND "${CMAKE_COMMAND}" -E remove ${output}.tmp - VERBATIM - DEPENDS Lagom::GMLCompiler - MAIN_DEPENDENCY ${source} - ) - get_filename_component(output_name ${output} NAME) - add_custom_target(generate_${output_name} DEPENDS ${output}) - add_dependencies(all_generated generate_${output_name}) -endfunction() - function(compile_ipc source output) if (NOT IS_ABSOLUTE ${source}) set(source ${CMAKE_CURRENT_SOURCE_DIR}/${source}) diff --git a/Meta/CMake/libgl_generators.cmake b/Meta/CMake/libgl_generators.cmake deleted file mode 100644 index 606a12dc109..00000000000 --- a/Meta/CMake/libgl_generators.cmake +++ /dev/null @@ -1,14 +0,0 @@ -function (generate_libgl_implementation) - set(LIBGL_INPUT_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}") - - invoke_generator( - "GLAPI.cpp" - Lagom::GenerateGLAPIWrapper - "${LIBGL_INPUT_FOLDER}/GLAPI.json" - "GL/glapi.h" - "GLAPI.cpp" - arguments -j "${LIBGL_INPUT_FOLDER}/GLAPI.json" - ) - - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/GL/glapi.h" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/LibGL/GL/" OPTIONAL) -endfunction() diff --git a/Meta/Lagom/CMakeLists.txt b/Meta/Lagom/CMakeLists.txt index 45650ae531e..48997647f34 100644 --- a/Meta/Lagom/CMakeLists.txt +++ b/Meta/Lagom/CMakeLists.txt @@ -386,17 +386,6 @@ install(TARGETS LibTimeZone EXPORT LagomTargets) # This is used by the BindingsGenerator so needs to always be built. add_serenity_subdirectory(Userland/Libraries/LibIDL) -# LibGUI - only GML -# This is used by the GML compiler and therefore always needed. -set(LIBGUI_GML_SOURCES - GML/Lexer.cpp - GML/Parser.cpp -) -list(TRANSFORM LIBGUI_GML_SOURCES PREPEND "${SERENITY_PROJECT_ROOT}/Userland/Libraries/LibGUI/") -lagom_lib(LibGUI_GML gui_gml - SOURCES ${LIBGUI_GML_SOURCES} -) - # Manually install AK headers install( DIRECTORY "${SERENITY_PROJECT_ROOT}/AK" @@ -444,27 +433,20 @@ if (BUILD_LAGOM) Archive Audio Compress - Cpp Crypto Diff Gemini Gfx - GL - GLSL - GPU HTTP ImageDecoderClient IPC - JIT JS Line Locale Markdown - PDF Protocol Regex RIFF - SoftGPU SQL Syntax TextCodec @@ -489,10 +471,6 @@ if (BUILD_LAGOM) compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/WebContent/WebDriverServer.ipc Userland/Services/WebContent/WebDriverServerEndpoint.h) endif() - if (NOT EMSCRIPTEN) - list(APPEND lagom_standard_libraries ELF X86) - endif() - foreach(lib IN LISTS lagom_standard_libraries) add_serenity_subdirectory("Userland/Libraries/Lib${lib}") endforeach() @@ -518,10 +496,6 @@ if (BUILD_LAGOM) add_serenity_subdirectory(Ladybird) endif() - if (APPLE) - add_serenity_subdirectory(Meta/Lagom/Contrib/MacPDF) - endif() - find_package(SDL2 QUIET) if (SDL2_FOUND) add_serenity_subdirectory(Meta/Lagom/Contrib/VideoPlayerSDL) @@ -544,7 +518,6 @@ if (BUILD_LAGOM) lagom_utility(lzcat SOURCES ../../Userland/Utilities/lzcat.cpp LIBS LibCompress LibMain) - lagom_utility(pdf SOURCES ../../Userland/Utilities/pdf.cpp LIBS LibGfx LibPDF LibMain) lagom_utility(sql SOURCES ../../Userland/Utilities/sql.cpp LIBS LibFileSystem LibIPC LibLine LibMain LibSQL) lagom_utility(tar SOURCES ../../Userland/Utilities/tar.cpp LIBS LibArchive LibCompress LibFileSystem LibMain) lagom_utility(test262-runner SOURCES ../../Tests/LibJS/test262-runner.cpp LIBS LibJS LibFileSystem) @@ -591,14 +564,11 @@ if (BUILD_LAGOM) # LibTest tests from Tests/ set(TEST_DIRECTORIES AK - JSSpecCompiler LibCrypto LibCompress - LibGL LibGfx LibLocale LibMarkdown - LibPDF LibSQL LibTest LibTextCodec diff --git a/Meta/Lagom/Contrib/MacPDF/AppDelegate.h b/Meta/Lagom/Contrib/MacPDF/AppDelegate.h deleted file mode 100644 index 13517b3ccb8..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/AppDelegate.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2023, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -// Several AK types conflict with MacOS types. -#define FixedPoint FixedPointMacOS -#import -#undef FixedPoint - -@interface AppDelegate : NSObject -@end diff --git a/Meta/Lagom/Contrib/MacPDF/AppDelegate.mm b/Meta/Lagom/Contrib/MacPDF/AppDelegate.mm deleted file mode 100644 index fe3ded39614..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/AppDelegate.mm +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2023, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#import "AppDelegate.h" - -#include - -@interface AppDelegate () -@property (strong) IBOutlet NSWindow* window; -@end - -@implementation AppDelegate - -- (void)applicationDidFinishLaunching:(NSNotification*)aNotification -{ - // FIXME: Copy fonts and icc file to the bundle or something - - // Get from `Build/lagom/bin/MacPDF.app/Contents/MacOS/MacPDF` to `Build/lagom/Root/res`. - NSString* source_root = [[NSBundle mainBundle] executablePath]; - for (int i = 0; i < 5; ++i) - source_root = [source_root stringByDeletingLastPathComponent]; - auto source_root_string = ByteString([source_root UTF8String]); - Core::ResourceImplementation::install(make(MUST(String::formatted("{}/Root/res", source_root_string)))); -} - -- (void)applicationWillTerminate:(NSNotification*)aNotification -{ -} - -- (BOOL)applicationSupportsSecureRestorableState:(NSApplication*)app -{ - return YES; -} - -- (BOOL)application:(NSApplication*)sender openFile:(NSString*)filename -{ - [[NSDocumentController sharedDocumentController] - openDocumentWithContentsOfURL:[NSURL fileURLWithPath:filename] - display:YES - completionHandler:^(NSDocument*, BOOL, NSError*) {}]; - return YES; -} - -@end diff --git a/Meta/Lagom/Contrib/MacPDF/CMakeLists.txt b/Meta/Lagom/Contrib/MacPDF/CMakeLists.txt deleted file mode 100644 index e5e3009d3c3..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ -# This has the effect of making LC_RPATH absolute. -# Since the binary is in Build/lagom/bin/MacPDF.app/Contents/MacOS/MacPDF, -# the default "@executable_path/../lib" doesn't work to get from the binary -# to Build/lagom/lib. -# FIXME: Pass "-Wl,-rpath,@executable_path/../../../../lib" instead for a relative path? -# Long-term, probably want to copy the dylibs into the bundle instead. -set(CMAKE_SKIP_BUILD_RPATH FALSE) -set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) - -add_compile_options(-DAK_DONT_REPLACE_STD) - -set(RESOURCES - MainMenu.xib -) - -add_executable(MacPDF MACOSX_BUNDLE - main.mm - AppDelegate.mm - MacPDFDocument.mm - MacPDFOutlineViewDataSource.mm - MacPDFView.mm - MacPDFWindowController.mm -) -target_compile_options(MacPDF PRIVATE - -fobjc-arc -) -target_link_libraries(MacPDF PRIVATE AK LibCore LibGfx LibPDF) -target_link_libraries(MacPDF PRIVATE - "-framework Cocoa" - "-framework UniformTypeIdentifiers" -) - -set_target_properties(MacPDF PROPERTIES - MACOSX_BUNDLE TRUE - - # FIXME: Apparently the Info.plist is only copied when the binary relinks, - # not if only the Info.plist contents changes and you rebuild? - MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist" -) - -# Normally you'd set `RESOURCE "${RESOURCES}"` on the MacPDF target properties -# and add `"${RESOURCES}" to the sources in add_executable() -# and CMake would add build steps to compile the xib files to nib files and -# add them to the bundle. -# But with CMake's ninja generator that seems to not work, so do it manually. -# See also https://github.com/dolphin-emu/dolphin/blob/2e39c79984490e/Source/Core/MacUpdater/CMakeLists.txt#L49-L56 -find_program(IBTOOL ibtool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin") -foreach(xib ${RESOURCES}) - string(REGEX REPLACE "[.]xib$" ".nib" nib "${xib}") - - # FIXME: This is gross! It makes the link at least as slow as compiling all xib files. - # Better to have a separate command for the compiles and to only do the copying in the postbuild. - add_custom_command(TARGET MacPDF POST_BUILD - COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text - --compile "$/Contents/Resources/${nib}" - "${CMAKE_CURRENT_SOURCE_DIR}/${xib}" - COMMENT "Compiling ${CMAKE_CURRENT_SOURCE_DIR}/${xib}.xib") -endforeach() diff --git a/Meta/Lagom/Contrib/MacPDF/CocoaWrapper.h b/Meta/Lagom/Contrib/MacPDF/CocoaWrapper.h deleted file mode 100644 index 3ae5460e97e..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/CocoaWrapper.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) 2023, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -// Several AK types conflict with MacOS types. -#define FixedPoint FixedPointMacOS -#import -#undef FixedPoint diff --git a/Meta/Lagom/Contrib/MacPDF/Info.plist b/Meta/Lagom/Contrib/MacPDF/Info.plist deleted file mode 100644 index c88dcd1217b..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/Info.plist +++ /dev/null @@ -1,41 +0,0 @@ - - - - - CFBundleDocumentTypes - - - CFBundleTypeName - PDF - CFBundleTypeRole - Viewer - LSHandlerRank - Default - LSItemContentTypes - - com.adobe.pdf - - NSDocumentClass - MacPDFDocument - - - CFBundleExecutable - MacPDF - CFBundleIdentifier - org.serenityos.MacPDF - CFBundleName - MacPDF - CFBundlePackageType - APPL - LSMinimumSystemVersion - 13.3 - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - NSSupportsAutomaticTermination - - NSSupportsSuddenTermination - - - diff --git a/Meta/Lagom/Contrib/MacPDF/MacPDFDocument.h b/Meta/Lagom/Contrib/MacPDF/MacPDFDocument.h deleted file mode 100644 index db439b0252e..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/MacPDFDocument.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2023, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "CocoaWrapper.h" - -#import "MacPDFWindowController.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface MacPDFDocument : NSDocument - -- (PDF::Document*)pdf; -- (void)windowIsReady; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Meta/Lagom/Contrib/MacPDF/MacPDFDocument.mm b/Meta/Lagom/Contrib/MacPDF/MacPDFDocument.mm deleted file mode 100644 index bc8ab778d05..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/MacPDFDocument.mm +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2023, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#import "MacPDFDocument.h" - -#import - -#import "MacPDFWindowController.h" -#include - -@interface MacPDFDocument () -{ - NSData* _data; // Strong, _doc refers to it. - RefPtr _doc; - MacPDFWindowController* _windowController; -} -@end - -@implementation MacPDFDocument - -- (PDF::Document*)pdf -{ - return _doc; -} - -- (void)promptForPassword:(NSWindow*)window -{ - auto alert = [[NSAlert alloc] init]; - alert.messageText = @"Password"; - [alert addButtonWithTitle:@"OK"]; - [alert addButtonWithTitle:@"Cancel"]; - - auto textField = [[NSSecureTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)]; - alert.accessoryView = textField; - alert.window.initialFirstResponder = textField; - - // Without this, the window's not visible yet and the sheet can't attach to it. - // FIXME: This causes the window to change position after restoring, so this isn't quite right either. - // Probably nicest to put the password prompt right in the window, instead of in a sheet. - [window orderFront:self]; - - [alert beginSheetModalForWindow:window - completionHandler:^(NSModalResponse response) { - if (response == NSAlertFirstButtonReturn) { - NSString* password = [textField stringValue]; - StringView password_view { [password UTF8String], strlen([password UTF8String]) }; - if (!self->_doc->security_handler()->try_provide_user_password(password_view)) { - warnln("invalid password '{}'", password); - [self performSelector:@selector(promptForPassword:) withObject:window]; - return; - } - [self initializePDF]; - } else if (response == NSAlertSecondButtonReturn) { - [self close]; - } - }]; -} - -- (PDF::PDFErrorOr>)load:(NSData*)data -{ - // Runs on background thread, can't interact with UI. - auto document = TRY(PDF::Document::create(ReadonlyBytes { [data bytes], [data length] })); - return document; -} - -- (void)initializePDF -{ - // FIXME: on background thread? - if (auto err = _doc->initialize(); err.is_error()) { - // FIXME: show error? - NSLog(@"failed to load 2: %@", @(err.error().message().characters())); - } else { - [_windowController pdfDidInitialize]; - } -} - -- (void)makeWindowControllers -{ - _windowController = [[MacPDFWindowController alloc] initWithDocument:self]; - [self addWindowController:_windowController]; - [self windowIsReady]; -} - -- (void)windowIsReady -{ - if (_doc) { - if (auto handler = _doc->security_handler(); handler && !handler->has_user_password()) { - [self promptForPassword:_windowController.window]; - return; - } - [self initializePDF]; - } -} - -- (NSData*)dataOfType:(NSString*)typeName error:(NSError**)outError -{ - if (outError) { - *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:nil]; - } - return nil; -} - -- (BOOL)readFromData:(NSData*)data ofType:(NSString*)typeName error:(NSError**)outError -{ - if (![[UTType typeWithIdentifier:typeName] conformsToType:UTTypePDF]) { - if (outError) { - *outError = [NSError errorWithDomain:NSOSStatusErrorDomain - code:unimpErr - userInfo:nil]; - } - return NO; - } - - if (auto doc_or = [self load:data]; !doc_or.is_error()) { - _doc = doc_or.value(); - _data = data; - return YES; - } else { - NSLog(@"failed to load: %@", @(doc_or.error().message().characters())); - if (outError) { - *outError = [NSError errorWithDomain:NSOSStatusErrorDomain - code:unimpErr - userInfo:nil]; - } - return NO; - } -} - -+ (BOOL)autosavesInPlace -{ - return YES; -} - -+ (BOOL)canConcurrentlyReadDocumentsOfType:(NSString*)typeName -{ - // Run readFromData:ofType:error: on background thread: - return YES; -} - -- (BOOL)isEntireFileLoaded -{ - return NO; -} - -@end diff --git a/Meta/Lagom/Contrib/MacPDF/MacPDFOutlineViewDataSource.h b/Meta/Lagom/Contrib/MacPDF/MacPDFOutlineViewDataSource.h deleted file mode 100644 index b8e0d9779ab..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/MacPDFOutlineViewDataSource.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2023, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "CocoaWrapper.h" - -#include - -NS_ASSUME_NONNULL_BEGIN - -// Objective-C wrapper of PDF::OutlineItem, to launder it through the NSOutlineViewDataSource protocol. -@interface OutlineItemWrapper : NSObject - -- (BOOL)isGroupItem; -- (Optional)page; - -@end - -@interface MacPDFOutlineViewDataSource : NSObject - -- (instancetype)initWithOutline:(RefPtr)outline; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Meta/Lagom/Contrib/MacPDF/MacPDFOutlineViewDataSource.mm b/Meta/Lagom/Contrib/MacPDF/MacPDFOutlineViewDataSource.mm deleted file mode 100644 index b6fe2efb950..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/MacPDFOutlineViewDataSource.mm +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2023, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#import "MacPDFOutlineViewDataSource.h" - -@interface OutlineItemWrapper () -{ - // Only one of those two is set. - RefPtr _item; - NSString* _groupName; -} -@end - -@implementation OutlineItemWrapper -- (instancetype)initWithItem:(NonnullRefPtr)item -{ - if (self = [super init]; !self) - return nil; - _item = move(item); - _groupName = nil; - return self; -} - -- (instancetype)initWithGroupName:(nonnull NSString*)groupName -{ - if (self = [super init]; !self) - return nil; - _groupName = groupName; - return self; -} - -- (BOOL)isGroupItem -{ - return _groupName != nil; -} - -- (Optional)page -{ - if ([self isGroupItem]) - return {}; - return _item->dest.page.map([](u32 page_index) { return page_index + 1; }); -} - -- (OutlineItemWrapper*)child:(NSInteger)index -{ - return [[OutlineItemWrapper alloc] initWithItem:_item->children[index]]; -} - -- (NSInteger)numberOfChildren -{ - if ([self isGroupItem]) - return 0; - return _item->children.size(); -} - -- (NSString*)objectValue -{ - if (_groupName) - return _groupName; - NSString* title = [NSString stringWithUTF8String:_item->title.characters()]; - - // Newlines confuse NSOutlineView, at least in sidebar style (even with `usesSingleLineMode` set to YES on the cell view's text field). - title = [[title componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] componentsJoinedByString:@" "]; - - return title; -} -@end - -@interface MacPDFOutlineViewDataSource () -{ - RefPtr _outline; -} -@end - -@implementation MacPDFOutlineViewDataSource - -- (instancetype)initWithOutline:(RefPtr)outline -{ - if (self = [super init]; !self) - return nil; - _outline = move(outline); - return self; -} - -#pragma mark - NSOutlineViewDataSource - -- (id)outlineView:(NSOutlineView*)outlineView child:(NSInteger)index ofItem:(nullable id)item -{ - if (item) - return [(OutlineItemWrapper*)item child:index]; - - if (index == 0) { - bool has_outline = _outline && !_outline->children.is_empty(); - // FIXME: Maybe put filename here instead? - return [[OutlineItemWrapper alloc] initWithGroupName:has_outline ? @"Outline" : @"(No outline)"]; - } - return [[OutlineItemWrapper alloc] initWithItem:_outline->children[index - 1]]; -} - -- (BOOL)outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item -{ - return [self outlineView:outlineView numberOfChildrenOfItem:item] > 0; -} - -- (NSInteger)outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(nullable id)item -{ - if (item) - return [(OutlineItemWrapper*)item numberOfChildren]; - - return 1 + (_outline ? _outline->children.size() : 0); -} - -- (id)outlineView:(NSOutlineView*)outlineView objectValueForTableColumn:(nullable NSTableColumn*)tableColumn byItem:(nullable id)item -{ - return [(OutlineItemWrapper*)item objectValue]; -} - -@end diff --git a/Meta/Lagom/Contrib/MacPDF/MacPDFView.h b/Meta/Lagom/Contrib/MacPDF/MacPDFView.h deleted file mode 100644 index 089b1fded19..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/MacPDFView.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "CocoaWrapper.h" - -#include -#include - -@protocol MacPDFViewDelegate -- (void)pageChanged; -@end - -@interface MacPDFView : NSView - -- (void)setDocument:(WeakPtr)doc; -- (void)goToPage:(int)page; -- (int)page; - -- (void)setDelegate:(id)delegate; - -- (IBAction)goToNextPage:(id)sender; -- (IBAction)goToPreviousPage:(id)sender; - -- (IBAction)toggleShowClippingPaths:(id)sender; -- (IBAction)toggleClipImages:(id)sender; -- (IBAction)toggleClipPaths:(id)sender; -- (IBAction)toggleClipText:(id)sender; -- (IBAction)toggleShowImages:(id)sender; -- (IBAction)toggleShowHiddenText:(id)sender; - -@end diff --git a/Meta/Lagom/Contrib/MacPDF/MacPDFView.mm b/Meta/Lagom/Contrib/MacPDF/MacPDFView.mm deleted file mode 100644 index 9de4c44c27a..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/MacPDFView.mm +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2023, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#import "MacPDFView.h" - -#include -#include -#include - -@interface MacPDFView () -{ - WeakPtr _doc; - NSBitmapImageRep* _cachedBitmap; - int _page_index; - __weak id _delegate; - PDF::RenderingPreferences _preferences; -} -@end - -static PDF::PDFErrorOr> render(PDF::Document& document, int page_index, NSSize size, PDF::RenderingPreferences const& preferences) -{ - auto page = TRY(document.get_page(page_index)); - - auto page_size = Gfx::IntSize { size.width, size.height }; - if (int rotation_count = (page.rotate / 90) % 4; rotation_count % 2 == 1) - page_size = Gfx::IntSize { page_size.height(), page_size.width() }; - - auto bitmap = TRY(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, page_size)); - - auto errors = PDF::Renderer::render(document, page, bitmap, Color::White, preferences); - if (errors.is_error()) { - for (auto const& error : errors.error().errors()) - NSLog(@"warning: %@", @(error.message().characters())); - } - - return TRY(PDF::Renderer::apply_page_rotation(bitmap, page)); -} - -static NSBitmapImageRep* ns_from_gfx(NonnullRefPtr bitmap_p) -{ - auto& bitmap = bitmap_p.leak_ref(); - CGBitmapInfo info = kCGBitmapByteOrder32Little | (CGBitmapInfo)kCGImageAlphaFirst; - auto data = CGDataProviderCreateWithData( - &bitmap, bitmap.begin(), bitmap.size_in_bytes(), - [](void* p, void const*, size_t) { - (void)adopt_ref(*reinterpret_cast(p)); - }); - auto space = CGColorSpaceCreateDeviceRGB(); - auto cgbmp = CGImageCreate(bitmap.width(), bitmap.height(), 8, - 32, bitmap.pitch(), space, - info, data, nullptr, false, kCGRenderingIntentDefault); - CGColorSpaceRelease(space); - CGDataProviderRelease(data); - auto* bmp = [[NSBitmapImageRep alloc] initWithCGImage:cgbmp]; - CGImageRelease(cgbmp); - return bmp; -} - -@implementation MacPDFView - -// Called from MacPDFDocument. -- (void)setDocument:(WeakPtr)doc -{ - _doc = move(doc); - _page_index = 0; - - [self addObserver:self - forKeyPath:@"safeAreaRect" - options:NSKeyValueObservingOptionNew - context:nil]; - - [self invalidateCachedBitmap]; -} - -- (void)observeValueForKeyPath:(NSString*)keyPath - ofObject:(id)object - change:(NSDictionary*)change - context:(void*)context -{ - // AppKit by default doesn't invalidate a view if safeAreaRect changes but the view's bounds don't change. - // This happens for example when toggling the visibility of the toolbar with a full-size content view. - // We do want a repaint in this case. - VERIFY([keyPath isEqualToString:@"safeAreaRect"]); - VERIFY(object == self); - [self setNeedsDisplay:YES]; -} - -- (void)goToPage:(int)page -{ - if (!_doc) - return; - - int new_index = max(0, min(page - 1, _doc->get_page_count() - 1)); - if (new_index == _page_index) - return; - - _page_index = new_index; - [self invalidateRestorableState]; - [self invalidateCachedBitmap]; - [_delegate pageChanged]; -} - -- (int)page -{ - return _page_index + 1; -} - -- (void)setDelegate:(id)delegate -{ - _delegate = delegate; -} - -#pragma mark - Drawing - -- (void)invalidateCachedBitmap -{ - _cachedBitmap = nil; - [self setNeedsDisplay:YES]; -} - -- (void)ensureCachedBitmapIsUpToDate -{ - if (!_doc || _doc->get_page_count() == 0) - return; - - NSSize pixel_size = [self convertSizeToBacking:self.safeAreaRect.size]; - if (NSEqualSizes([_cachedBitmap size], pixel_size)) - return; - - if (auto bitmap_or = render(*_doc, _page_index, pixel_size, _preferences); !bitmap_or.is_error()) - _cachedBitmap = ns_from_gfx(bitmap_or.value()); -} - -- (void)drawRect:(NSRect)rect -{ - [self ensureCachedBitmapIsUpToDate]; - [_cachedBitmap drawInRect:self.safeAreaRect]; -} - -#pragma mark - Keyboard handling - -- (BOOL)acceptsFirstResponder -{ - return YES; -} - -- (IBAction)goToNextPage:(id)sender -{ - int current_page = _page_index + 1; - [self goToPage:current_page + 1]; -} - -- (IBAction)goToPreviousPage:(id)sender -{ - int current_page = _page_index + 1; - [self goToPage:current_page - 1]; -} - -- (BOOL)validateMenuItem:(NSMenuItem*)item -{ - if ([item action] == @selector(goToNextPage:)) - return _doc ? (_page_index < (int)_doc->get_page_count() - 1) : NO; - if ([item action] == @selector(goToPreviousPage:)) - return _doc ? (_page_index > 0) : NO; - if ([item action] == @selector(toggleShowClippingPaths:)) { - [item setState:_preferences.show_clipping_paths ? NSControlStateValueOn : NSControlStateValueOff]; - return _doc ? YES : NO; - } - if ([item action] == @selector(toggleClipImages:)) { - [item setState:_preferences.clip_images ? NSControlStateValueOn : NSControlStateValueOff]; - return _doc ? YES : NO; - } - if ([item action] == @selector(toggleClipPaths:)) { - [item setState:_preferences.clip_paths ? NSControlStateValueOn : NSControlStateValueOff]; - return _doc ? YES : NO; - } - if ([item action] == @selector(toggleClipText:)) { - [item setState:_preferences.clip_text ? NSControlStateValueOn : NSControlStateValueOff]; - return _doc ? YES : NO; - } - if ([item action] == @selector(toggleShowImages:)) { - [item setState:_preferences.show_images ? NSControlStateValueOn : NSControlStateValueOff]; - return _doc ? YES : NO; - } - if ([item action] == @selector(toggleShowHiddenText:)) { - [item setState:_preferences.show_hidden_text ? NSControlStateValueOn : NSControlStateValueOff]; - return _doc ? YES : NO; - } - return NO; -} - -- (IBAction)toggleShowClippingPaths:(id)sender -{ - if (_doc) { - _preferences.show_clipping_paths = !_preferences.show_clipping_paths; - [self invalidateCachedBitmap]; - } -} - -- (IBAction)toggleClipImages:(id)sender -{ - if (_doc) { - _preferences.clip_images = !_preferences.clip_images; - [self invalidateCachedBitmap]; - } -} - -- (IBAction)toggleClipPaths:(id)sender -{ - if (_doc) { - _preferences.clip_paths = !_preferences.clip_paths; - [self invalidateCachedBitmap]; - } -} - -- (IBAction)toggleClipText:(id)sender -{ - if (_doc) { - _preferences.clip_text = !_preferences.clip_text; - [self invalidateCachedBitmap]; - } -} - -- (IBAction)toggleShowImages:(id)sender -{ - if (_doc) { - _preferences.show_images = !_preferences.show_images; - [self invalidateCachedBitmap]; - } -} - -- (IBAction)toggleShowHiddenText:(id)sender -{ - if (_doc) { - _preferences.show_hidden_text = !_preferences.show_hidden_text; - [self invalidateCachedBitmap]; - } -} - -- (void)keyDown:(NSEvent*)event -{ - // Calls moveLeft: or moveRight: below. - [self interpretKeyEvents:@[ event ]]; -} - -// Called on down arrow. -- (IBAction)moveDown:(id)sender -{ - [self goToNextPage:self]; -} - -// Called on left arrow. -- (IBAction)moveLeft:(id)sender -{ - [self goToPreviousPage:self]; -} - -// Called on right arrow. -- (IBAction)moveRight:(id)sender -{ - [self goToNextPage:self]; -} - -// Called on up arrow. -- (IBAction)moveUp:(id)sender -{ - [self goToPreviousPage:self]; -} - -#pragma mark - State restoration - -- (void)encodeRestorableStateWithCoder:(NSCoder*)coder -{ - [coder encodeInt:_page_index forKey:@"PageIndex"]; - NSLog(@"encodeRestorableStateWithCoder encoded %d", _page_index); -} - -- (void)restoreStateWithCoder:(NSCoder*)coder -{ - if ([coder containsValueForKey:@"PageIndex"]) { - int page_index = [coder decodeIntForKey:@"PageIndex"]; - _page_index = min(max(0, page_index), _doc->get_page_count() - 1); - NSLog(@"encodeRestorableStateWithCoder restored %d", _page_index); - [self invalidateCachedBitmap]; - [_delegate pageChanged]; - } -} - -@end diff --git a/Meta/Lagom/Contrib/MacPDF/MacPDFWindowController.h b/Meta/Lagom/Contrib/MacPDF/MacPDFWindowController.h deleted file mode 100644 index 4535d333fde..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/MacPDFWindowController.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "CocoaWrapper.h" - -#import "MacPDFView.h" -#include - -NS_ASSUME_NONNULL_BEGIN - -@class MacPDFDocument; - -@interface MacPDFWindowController : NSWindowController - -- (instancetype)initWithDocument:(MacPDFDocument*)document; - -- (IBAction)goToNextPage:(id)sender; -- (IBAction)goToPreviousPage:(id)sender; -- (IBAction)toggleShowClippingPaths:(id)sender; -- (IBAction)toggleClipImages:(id)sender; -- (IBAction)toggleClipPaths:(id)sender; -- (IBAction)toggleClipText:(id)sender; -- (IBAction)toggleShowImages:(id)sender; -- (IBAction)toggleShowHiddenText:(id)sender; -- (IBAction)showGoToPageDialog:(id)sender; - -- (void)pdfDidInitialize; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Meta/Lagom/Contrib/MacPDF/MacPDFWindowController.mm b/Meta/Lagom/Contrib/MacPDF/MacPDFWindowController.mm deleted file mode 100644 index 68439b2a09c..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/MacPDFWindowController.mm +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright (c) 2023, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#import "MacPDFWindowController.h" - -#import "MacPDFDocument.h" -#import "MacPDFOutlineViewDataSource.h" - -@interface MacPDFWindowController () -{ - MacPDFDocument* _pdfDocument; - IBOutlet MacPDFView* _pdfView; - - MacPDFOutlineViewDataSource* _outlineDataSource; - NSOutlineView* _outlineView; -} -@end - -@implementation MacPDFWindowController - -- (instancetype)initWithDocument:(MacPDFDocument*)document -{ - auto const style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable | NSWindowStyleMaskFullSizeContentView; - NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 600, 800) - styleMask:style_mask - backing:NSBackingStoreBuffered - defer:YES]; - - if (self = [super initWithWindow:window]; !self) - return nil; - - _pdfView = [[MacPDFView alloc] initWithFrame:NSZeroRect]; - _pdfView.identifier = @"PDFView"; // To make state restoration work. - [_pdfView setDelegate:self]; - - NSSplitViewController* split_view = [[NSSplitViewController alloc] initWithNibName:nil bundle:nil]; - [split_view addSplitViewItem:[self makeSidebarSplitItem]]; - [split_view addSplitViewItem:[NSSplitViewItem splitViewItemWithViewController:[self viewControllerForView:_pdfView]]]; - - // Autosave if the sidebar is open or not, and how far. - // autosaveName only works if identifier is set too. - // identifier docs: "For programmatically created views, you typically set this value - // after creating the item but before adding it to a window. [...] For views and controls - // in a window, the value you specify for this string must be unique on a per-window basis." - split_view.splitView.autosaveName = @"MacPDFSplitView"; - split_view.splitView.identifier = @"MacPDFSplitViewId"; - - window.contentViewController = split_view; - - NSToolbar* toolbar = [[NSToolbar alloc] initWithIdentifier:@"MacPDFToolbar"]; - toolbar.delegate = self; - toolbar.displayMode = NSToolbarDisplayModeIconOnly; - [window setToolbar:toolbar]; - - _pdfDocument = document; - return self; -} - -- (NSViewController*)viewControllerForView:(NSView*)view -{ - NSViewController* view_controller = [[NSViewController alloc] initWithNibName:nil bundle:nil]; - view_controller.view = view; - return view_controller; -} - -- (NSSplitViewItem*)makeSidebarSplitItem -{ - _outlineView = [[NSOutlineView alloc] initWithFrame:NSZeroRect]; - - _outlineView.floatsGroupRows = NO; - _outlineView.focusRingType = NSFocusRingTypeNone; - _outlineView.headerView = nil; - - // FIXME: Implement data source support for autosaveExpandedItems and use that. - - // rowSizeStyle does not default to NSTableViewRowSizeStyleDefault, but needs to be set to it for outline views in sourcelist style. - _outlineView.rowSizeStyle = NSTableViewRowSizeStyleDefault; - - NSTableColumn* column = [[NSTableColumn alloc] initWithIdentifier:@"OutlineColumn"]; - column.editable = NO; - [_outlineView addTableColumn:column]; - - NSScrollView* scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect]; - scrollView.hasVerticalScroller = YES; - scrollView.drawsBackground = NO; - scrollView.documentView = _outlineView; - - // The scroll view knows to put things only in the safe area, but it doesn't clip to it. - // So momentum scrolling would let things draw above it, which looks weird. - // Put the scroll view in a containing view and make the containing view limit the scroll view to - // the safe area, so that it gets clipped. - NSView* view = [[NSView alloc] initWithFrame:NSZeroRect]; - [view addSubview:scrollView]; - - [scrollView.topAnchor constraintEqualToAnchor:view.safeAreaLayoutGuide.topAnchor].active = YES; - [scrollView.leftAnchor constraintEqualToAnchor:view.safeAreaLayoutGuide.leftAnchor].active = YES; - [scrollView.rightAnchor constraintEqualToAnchor:view.safeAreaLayoutGuide.rightAnchor].active = YES; - [scrollView.bottomAnchor constraintEqualToAnchor:view.safeAreaLayoutGuide.bottomAnchor].active = YES; - scrollView.translatesAutoresizingMaskIntoConstraints = NO; - - NSSplitViewItem* item = [NSSplitViewItem sidebarWithViewController:[self viewControllerForView:view]]; - item.collapseBehavior = NSSplitViewItemCollapseBehaviorPreferResizingSplitViewWithFixedSiblings; - - // This only has an effect on the very first run. - // Later, the collapsed state is loaded from the sidebar's autosave data. - item.collapsed = YES; - - return item; -} - -- (void)pdfDidInitialize -{ - [_pdfView setDocument:_pdfDocument.pdf->make_weak_ptr()]; - [self pageChanged]; - - // FIXME: Only set data source when sidebar is open. - _outlineDataSource = [[MacPDFOutlineViewDataSource alloc] initWithOutline:_pdfDocument.pdf->outline()]; - _outlineView.dataSource = _outlineDataSource; - _outlineView.delegate = self; -} - -- (IBAction)goToNextPage:(id)sender -{ - [_pdfView goToNextPage:sender]; -} - -- (IBAction)goToPreviousPage:(id)sender -{ - [_pdfView goToPreviousPage:sender]; -} - -- (BOOL)validateMenuItem:(NSMenuItem*)item -{ - if ([_pdfView validateMenuItem:item]) - return YES; - return [super validateMenuItem:item]; -} - -- (IBAction)toggleShowClippingPaths:(id)sender -{ - [_pdfView toggleShowClippingPaths:sender]; -} - -- (IBAction)toggleClipImages:(id)sender -{ - [_pdfView toggleClipImages:sender]; -} - -- (IBAction)toggleClipPaths:(id)sender -{ - [_pdfView toggleClipPaths:sender]; -} - -- (IBAction)toggleClipText:(id)sender -{ - [_pdfView toggleClipText:sender]; -} - -- (IBAction)toggleShowImages:(id)sender -{ - [_pdfView toggleShowImages:sender]; -} - -- (IBAction)toggleShowHiddenText:(id)sender -{ - [_pdfView toggleShowHiddenText:sender]; -} - -- (IBAction)showGoToPageDialog:(id)sender -{ - auto alert = [[NSAlert alloc] init]; - alert.messageText = @"Page Number"; - [alert addButtonWithTitle:@"Go"]; - [alert addButtonWithTitle:@"Cancel"]; - - auto textField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 24)]; - NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init]; - formatter.numberStyle = NSNumberFormatterNoStyle; // Integers only. - [textField setFormatter:formatter]; - [textField setIntValue:[_pdfView page]]; - - alert.accessoryView = textField; - alert.window.initialFirstResponder = textField; - - [alert beginSheetModalForWindow:self.window - completionHandler:^(NSModalResponse response) { - if (response == NSAlertFirstButtonReturn) - [self->_pdfView goToPage:[textField intValue]]; - }]; -} - -#pragma mark - MacPDFViewDelegate - -- (void)pageChanged -{ - [self.window setSubtitle: - [NSString stringWithFormat:@"Page %d of %d", [_pdfView page], _pdfDocument.pdf->get_page_count()]]; -} - -#pragma mark - NSToolbarDelegate - -- (NSArray*)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar -{ - return [self toolbarDefaultItemIdentifiers:toolbar]; -} - -- (NSArray*)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar -{ - // NSToolbarToggleSidebarItemIdentifier sends toggleSidebar: along the responder chain, - // which NSSplitViewController conveniently implements. - return @[ - NSToolbarToggleSidebarItemIdentifier, - NSToolbarSidebarTrackingSeparatorItemIdentifier, - ]; -} - -- (NSToolbarItem*)toolbar:(NSToolbar*)toolbar - itemForItemIdentifier:(NSToolbarItemIdentifier)itemIdentifier - willBeInsertedIntoToolbar:(BOOL)flag -{ - // Not called for standard identifiers, but the implementation of the method must exist, or else: - // ERROR: invalid delegate (does not implement all required methods) - return nil; -} - -#pragma mark - NSOutlineViewDelegate - -- (BOOL)outlineView:(NSOutlineView*)outlineView isGroupItem:(id)item -{ - return [item isGroupItem]; -} - -- (BOOL)outlineView:(NSOutlineView*)outlineView shouldSelectItem:(id)item -{ - return ![self outlineView:outlineView isGroupItem:item]; -} - -// "This method is required if you wish to turn on the use of NSViews instead of NSCells." -- (NSView*)outlineView:(NSOutlineView*)outlineView viewForTableColumn:(NSTableColumn*)tableColumn item:(id)item -{ - // "The implementation of this method will usually call -[tableView makeViewWithIdentifier:[tableColumn identifier] owner:self] - // in order to reuse a previous view, or automatically unarchive an associated prototype view for that identifier." - - // Figure 1-5 in "Understanding Table Views" at - // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TableView/TableViewOverview/TableViewOverview.html - // describes what makeViewWithIdentifier:owner: does: It tries to cache views, so that if an item scrolls out of view - // and then back in again, the old view can be reused, without having to allocate a new one. - // It also tries to load the view from a xib if it doesn't exist. We don't use a xib though, so we have - // to create the view in code if it's not already cached. - - // After calling this method to create a view, the framework assigns its objectValue to what's - // returned by outlineView:objectValueForTableColumn:byItem: from the data source. - // NSTableCellView implements objectValue, but it doesn't do anything with it. We have to manually - // bind assignment to its objectValue field to update concrete views. - // This is done here using Cocoa bindings. - // Alternatively, we could also get the data from the data model directly and assign it to - // the text field's stringValue, but then we'd call outlineView:objectValueForTableColumn:byItem: - // twice, and this somewhat roundabout method here seems to be how the framework wants to be used. - - NSTableCellView* cellView = [outlineView makeViewWithIdentifier:tableColumn.identifier owner:self]; - if (!cellView) { - cellView = [[NSTableCellView alloc] init]; - cellView.identifier = tableColumn.identifier; - - NSTextField* textField = [NSTextField labelWithString:@""]; - textField.lineBreakMode = NSLineBreakByTruncatingTail; - textField.allowsExpansionToolTips = YES; - - // https://stackoverflow.com/a/29725553/551986 - // "If your cell view is an NSTableCellView, that class also responds to -setObjectValue:. [...] - // However, an NSTableCellView does not inherently do anything with the object value. It just holds it. - // What you can then do is have the subviews bind to it through the objectValue property." - [textField bind:@"objectValue" toObject:cellView withKeyPath:@"objectValue" options:nil]; - - [cellView addSubview:textField]; - cellView.textField = textField; - } - - return cellView; -} - -- (void)outlineViewSelectionDidChange:(NSNotification*)notification -{ - NSInteger row = _outlineView.selectedRow; - if (row == -1) - return; - - OutlineItemWrapper* item = [_outlineView itemAtRow:row]; - if (auto page = [item page]; page.has_value()) - [_pdfView goToPage:page.value()]; -} - -@end diff --git a/Meta/Lagom/Contrib/MacPDF/MainMenu.xib b/Meta/Lagom/Contrib/MacPDF/MainMenu.xib deleted file mode 100644 index 4b83fe4b4b6..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/MainMenu.xib +++ /dev/null @@ -1,747 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Meta/Lagom/Contrib/MacPDF/main.mm b/Meta/Lagom/Contrib/MacPDF/main.mm deleted file mode 100644 index 7aaf40a7d85..00000000000 --- a/Meta/Lagom/Contrib/MacPDF/main.mm +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) 2023, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#import - -int main(int argc, char const* argv[]) -{ - return NSApplicationMain(argc, argv); -} diff --git a/Meta/Lagom/Fuzzers/FuzzELF.cpp b/Meta/Lagom/Fuzzers/FuzzELF.cpp deleted file mode 100644 index 146945ec0fb..00000000000 --- a/Meta/Lagom/Fuzzers/FuzzELF.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size) -{ - AK::set_debug_enabled(false); - ELF::Image elf(data, size, /*verbose_logging=*/false); - return 0; -} diff --git a/Meta/Lagom/Fuzzers/FuzzPDF.cpp b/Meta/Lagom/Fuzzers/FuzzPDF.cpp deleted file mode 100644 index 49b806cca64..00000000000 --- a/Meta/Lagom/Fuzzers/FuzzPDF.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2021, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size) -{ - AK::set_debug_enabled(false); - - ReadonlyBytes bytes { data, size }; - - if (auto maybe_document = PDF::Document::create(bytes); !maybe_document.is_error()) { - auto document = maybe_document.release_value(); - (void)document->initialize(); - auto pages = document->get_page_count(); - for (size_t i = 0; i < pages; ++i) { - (void)document->get_page(i); - } - } - - return 0; -} diff --git a/Meta/Lagom/Fuzzers/fuzzers.cmake b/Meta/Lagom/Fuzzers/fuzzers.cmake index c8cf12621df..6ac49a5bb8a 100644 --- a/Meta/Lagom/Fuzzers/fuzzers.cmake +++ b/Meta/Lagom/Fuzzers/fuzzers.cmake @@ -7,7 +7,6 @@ set(FUZZER_TARGETS DDSLoader DeflateCompression DeflateDecompression - ELF FlacLoader Gemini GIFLoader @@ -30,7 +29,6 @@ set(FUZZER_TARGETS MP3Loader PAMLoader PBMLoader - PDF PEM PGMLoader PNGLoader @@ -99,7 +97,6 @@ set(FUZZER_DEPENDENCIES_MD5 LibCrypto) set(FUZZER_DEPENDENCIES_MP3Loader LibAudio) set(FUZZER_DEPENDENCIES_PAMLoader LibGfx) set(FUZZER_DEPENDENCIES_PBMLoader LibGfx) -set(FUZZER_DEPENDENCIES_PDF LibPDF) set(FUZZER_DEPENDENCIES_PEM LibCrypto) set(FUZZER_DEPENDENCIES_PGMLoader LibGfx) set(FUZZER_DEPENDENCIES_PNGLoader LibGfx) diff --git a/Meta/Lagom/Tools/CodeGenerators/CMakeLists.txt b/Meta/Lagom/Tools/CodeGenerators/CMakeLists.txt index c659ae74acb..9cab846dfe6 100644 --- a/Meta/Lagom/Tools/CodeGenerators/CMakeLists.txt +++ b/Meta/Lagom/Tools/CodeGenerators/CMakeLists.txt @@ -1,9 +1,4 @@ -add_subdirectory(GMLCompiler) add_subdirectory(IPCCompiler) -if (BUILD_LAGOM) - add_subdirectory(JSSpecCompiler) -endif() -add_subdirectory(LibGL) add_subdirectory(LibLocale) add_subdirectory(LibTextCodec) add_subdirectory(LibTimeZone) diff --git a/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/CMakeLists.txt b/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/CMakeLists.txt deleted file mode 100644 index ad30e72e059..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(SOURCES - main.cpp -) - -lagom_tool(GMLCompiler LIBS LibMain LibCore LibGUI_GML) diff --git a/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/main.cpp b/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/main.cpp deleted file mode 100644 index f296fdcb001..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/main.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -enum class UseObjectConstructor : bool { - No, - Yes, -}; - -// Classes whose header doesn't have the same name as the class. -static Optional map_class_to_file(StringView class_) -{ - static HashMap class_file_mappings { - { "GUI::HorizontalSplitter"sv, "GUI/Splitter"sv }, - { "GUI::VerticalSplitter"sv, "GUI/Splitter"sv }, - { "GUI::HorizontalSeparator"sv, "GUI/SeparatorWidget"sv }, - { "GUI::VerticalSeparator"sv, "GUI/SeparatorWidget"sv }, - { "GUI::HorizontalBoxLayout"sv, "GUI/BoxLayout"sv }, - { "GUI::VerticalBoxLayout"sv, "GUI/BoxLayout"sv }, - { "GUI::HorizontalProgressbar"sv, "GUI/Progressbar"sv }, - { "GUI::VerticalProgressbar"sv, "GUI/Progressbar"sv }, - { "GUI::DialogButton"sv, "GUI/Button"sv }, - { "GUI::PasswordBox"sv, "GUI/TextBox"sv }, - { "GUI::HorizontalOpacitySlider"sv, "GUI/OpacitySlider"sv }, - // Map Layout::Spacer to the Layout header even though it's a pseudo class. - { "GUI::Layout::Spacer"sv, "GUI/Layout"sv }, - }; - return class_file_mappings.get(class_); -} - -// Properties which don't take a direct JSON-like primitive (StringView, int, bool, Array etc) as arguments and need the arguments to be wrapped in a constructor call. -static Optional map_property_to_type(StringView property) -{ - static HashMap property_to_type_mappings { - { "container_margins"sv, "GUI::Margins"sv }, - { "margins"sv, "GUI::Margins"sv }, - }; - return property_to_type_mappings.get(property); -} - -// Properties which take a UIDimension which can handle JSON directly. -static bool is_ui_dimension_property(StringView property) -{ - static HashTable ui_dimension_properties; - if (ui_dimension_properties.is_empty()) { - ui_dimension_properties.set("min_width"sv); - ui_dimension_properties.set("max_width"sv); - ui_dimension_properties.set("preferred_width"sv); - ui_dimension_properties.set("min_height"sv); - ui_dimension_properties.set("max_height"sv); - ui_dimension_properties.set("preferred_height"sv); - } - return ui_dimension_properties.contains(property); -} - -// FIXME: Since normal string-based properties take either String or StringView (and the latter can be implicitly constructed from the former), -// we need to special-case ByteString property setters while those still exist. -// Please remove a setter from this list once it uses StringView or String. -static bool takes_byte_string(StringView property) -{ - static HashTable byte_string_properties; - if (byte_string_properties.is_empty()) { - byte_string_properties.set("icon_from_path"sv); - byte_string_properties.set("name"sv); - } - return byte_string_properties.contains(property); -} - -static ErrorOr include_path_for(StringView class_name, LexicalPath const& gml_file_name) -{ - String pathed_name; - if (auto mapping = map_class_to_file(class_name); mapping.has_value()) - pathed_name = TRY(String::from_utf8(mapping.value())); - else - pathed_name = TRY(TRY(String::from_utf8(class_name)).replace("::"sv, "/"sv, ReplaceMode::All)); - - if (class_name.starts_with("GUI::"sv) || class_name.starts_with("WebView::"sv)) - return String::formatted("", pathed_name); - - // We assume that all other paths are within the current application, for now. - // To figure out what kind of userland program this is (application, service, ...) we consider the path to the original GML file. - auto const& paths = gml_file_name.parts_view(); - auto path_iter = paths.find("Userland"sv); - path_iter++; - auto const userland_subdirectory = (path_iter == paths.end()) ? "Applications"_string : TRY(String::from_utf8(*path_iter)); - return String::formatted("<{}/{}.h>", userland_subdirectory, pathed_name); -} - -// Each entry is an include path, without the "#include" itself. -static ErrorOr> extract_necessary_includes(GUI::GML::Object const& gml_hierarchy, LexicalPath const& gml_file_name, bool is_root = false) -{ - HashTable necessary_includes; - if (!is_root) - TRY(necessary_includes.try_set(TRY(include_path_for(gml_hierarchy.name(), gml_file_name)))); - if (gml_hierarchy.layout_object() != nullptr) - TRY(necessary_includes.try_set(TRY(include_path_for(gml_hierarchy.layout_object()->name(), gml_file_name)))); - - TRY(gml_hierarchy.try_for_each_child_object([&](auto const& object) -> ErrorOr { - auto necessary_child_includes = TRY(extract_necessary_includes(object, gml_file_name)); - for (auto const& include : necessary_child_includes) - TRY(necessary_includes.try_set(include)); - return {}; - })); - - return necessary_includes; -} - -static char const header[] = R"~~~( -/* - * Auto-generated by the GML compiler - */ - -)~~~"; - -static char const class_declaration[] = R"~~~( -// A barebones definition of @main_class_name@ used to emit the symbol try_create. -// Requirements: -// - Inherits from GUI::Widget (indirectly, is declared as 'class') -// - Has a default ctor -// - Has declared a compatible static ErrorOr> try_create(). -namespace @class_namespace@ { -class @pure_class_name@ : public GUI::Widget { -public: - @pure_class_name@(); - static ErrorOr> try_create(); -}; -} - -)~~~"; - -static char const function_start[] = R"~~~( -// Creates a @main_class_name@ and initializes it. -// This function was auto-generated by the GML compiler. -ErrorOr> @main_class_name@::try_create() -{ - RefPtr<::@main_class_name@> main_object; - -)~~~"; - -static char const footer[] = R"~~~( - return main_object.release_nonnull(); -} -)~~~"; - -static ErrorOr escape_string(JsonValue to_escape) -{ - auto string = TRY(String::from_byte_string(to_escape.as_string())); - - // All C++ simple escape sequences; see https://en.cppreference.com/w/cpp/language/escape - // Other commonly-escaped characters are hard-to-type Unicode and therefore fine to include verbatim in UTF-8 coded strings. - static HashMap escape_sequences = { - { "\\"sv, "\\\\"sv }, // This needs to be the first because otherwise the the backslashes of other items will be double escaped - { "\0"sv, "\\0"sv }, - { "\'"sv, "\\'"sv }, - { "\""sv, "\\\""sv }, - { "\a"sv, "\\a"sv }, - { "\b"sv, "\\b"sv }, - { "\f"sv, "\\f"sv }, - { "\n"sv, "\\n"sv }, - { "\r"sv, "\\r"sv }, - { "\t"sv, "\\t"sv }, - { "\v"sv, "\\v"sv }, - }; - - for (auto const& entries : escape_sequences) - string = TRY(string.replace(entries.key, entries.value, ReplaceMode::All)); - - return string; -} - -// This function assumes that the string is already the same as its enum constant's name. -// Therefore, it does not handle UI dimensions. -static ErrorOr> generate_enum_initializer_for(StringView property_name, JsonValue value) -{ - // The value is the enum's type name. - static HashMap enum_properties = { - { "background_role"sv, "Gfx::ColorRole"sv }, - { "button_style"sv, "Gfx::ButtonStyle"sv }, - { "checkbox_position"sv, "GUI::CheckBox::CheckBoxPosition"sv }, - { "focus_policy"sv, "GUI::FocusPolicy"sv }, - { "font_weight"sv, "Gfx::FontWeight"sv }, - { "foreground_role"sv, "Gfx::ColorRole"sv }, - { "frame_style"sv, "Gfx::FrameStyle"sv }, - { "mode"sv, "GUI::TextEditor::Mode"sv }, - { "opportunistic_resizee"sv, "GUI::Splitter::OpportunisticResizee"sv }, - { "orientation"sv, "Gfx::Orientation"sv }, - { "text_alignment"sv, "Gfx::TextAlignment"sv }, - { "text_wrapping"sv, "Gfx::TextWrapping"sv }, - }; - - auto const& enum_type_name = enum_properties.get(property_name); - if (!enum_type_name.has_value()) - return Optional {}; - - return String::formatted("{}::{}", *enum_type_name, value.as_string()); -} - -// FIXME: In case of error, propagate the precise array+property that triggered the error. -static ErrorOr generate_initializer_for(Optional property_name, JsonValue value) -{ - if (value.is_string()) { - if (property_name.has_value()) { - if (takes_byte_string(*property_name)) - return String::formatted(R"~~~("{}"sv)~~~", TRY(escape_string(value))); - - if (auto const enum_value = TRY(generate_enum_initializer_for(*property_name, value)); enum_value.has_value()) - return String::formatted("{}", *enum_value); - - if (*property_name == "bitmap"sv) - return String::formatted(R"~~~(TRY(Gfx::Bitmap::load_from_file("{}"sv)))~~~", TRY(escape_string(value))); - } - - return String::formatted(R"~~~("{}"_string)~~~", TRY(escape_string(value))); - } - if (value.is_bool()) - return String::formatted("{}", value.as_bool()); - if (value.is_number()) { - return value.as_number().visit( - // NOTE: Passing by mutable reference here in order to disallow implicit casts. - [](u64& value) { return String::formatted("static_cast({})", value); }, - [](i64& value) { return String::formatted("static_cast({})", value); }, - [](double& value) { return String::formatted("static_cast({})", value); }); - } - if (value.is_array()) { - auto const& array = value.as_array(); - auto child_type = Optional {}; - for (auto const& child_value : array.values()) { - if (child_value.is_array()) - return Error::from_string_view("Nested arrays are not supported"sv); - -#define HANDLE_TYPE(type_name, is_type) \ - if (child_value.is_type() && (!child_type.has_value() || child_type.value() == #type_name##sv)) \ - child_type = #type_name##sv; \ - else - - HANDLE_TYPE(StringView, is_string) - HANDLE_TYPE(i64, is_integer) - HANDLE_TYPE(u64, is_integer) - HANDLE_TYPE(bool, is_bool) - // FIXME: Do we want to allow precision loss when C++ compiler parses these doubles? - HANDLE_TYPE(double, is_number) - return Error::from_string_view("Inconsistent contained type in JSON array"sv); -#undef HANDLE_TYPE - } - if (!child_type.has_value()) - return Error::from_string_view("Empty JSON array; cannot deduce type."sv); - - StringBuilder initializer; - initializer.appendff("Array<{}, {}> {{ "sv, child_type.release_value(), array.size()); - for (auto const& child_value : array.values()) - initializer.appendff("{}, ", TRY(generate_initializer_for({}, child_value))); - initializer.append("}"sv); - return initializer.to_string(); - } - return Error::from_string_view("Unsupported JSON value"sv); -} - -// Loads an object and assigns it to the RefPtr variable named object_name. -// All loading happens in a separate block. -static ErrorOr generate_loader_for_object(GUI::GML::Object const& gml_object, SourceGenerator generator, String object_name, size_t indentation, UseObjectConstructor use_object_constructor) -{ - generator.set("object_name", object_name.to_byte_string()); - generator.set("class_name", gml_object.name()); - - auto append = [&](auto& generator, char const(&text)[N]) -> ErrorOr { - generator.append(TRY(String::repeated(' ', indentation * 4))); - generator.appendln(text); - return {}; - }; - - generator.append(TRY(String::repeated(' ', (indentation - 1) * 4))); - generator.appendln("{"); - if (use_object_constructor == UseObjectConstructor::Yes) - TRY(append(generator, "@object_name@ = TRY(@class_name@::try_create());")); - else - TRY(append(generator, "@object_name@ = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) ::@class_name@()));")); - - // Properties - TRY(gml_object.try_for_each_property([&](StringView key, NonnullRefPtr value) -> ErrorOr { - auto value_code = TRY(generate_initializer_for(key, value)); - if (is_ui_dimension_property(key)) { - if (auto ui_dimension = GUI::UIDimension::construct_from_json_value(value); ui_dimension.has_value()) - value_code = TRY(ui_dimension->as_cpp_source()); - else - // FIXME: propagate precise error cause - return Error::from_string_view("UI dimension invalid"sv); - } else { - // Wrap value in an extra constructor call if necessary. - if (auto type = map_property_to_type(key); type.has_value()) - value_code = TRY(String::formatted("{} {{ {} }}", type.release_value(), value_code)); - } - - auto property_generator = generator.fork(); - property_generator.set("key", key); - property_generator.set("value", value_code.bytes_as_string_view()); - TRY(append(property_generator, R"~~~(@object_name@->set_@key@(@value@);)~~~")); - return {}; - })); - generator.appendln(""); - - // Object properties - size_t current_object_property_index = 0; - auto next_object_property_name = [&]() { - return String::formatted("{}_property_{}", object_name, current_object_property_index++); - }; - TRY(gml_object.try_for_each_object_property([&](StringView key, NonnullRefPtr value) -> ErrorOr { - if (key == "layout"sv) - return {}; // Layout is handled separately. - - auto property_generator = generator.fork(); - auto property_variable_name = TRY(next_object_property_name()); - property_generator.set("property_variable_name", property_variable_name.bytes_as_string_view()); - property_generator.set("property_class_name", value->name()); - property_generator.set("key", key); - TRY(append(property_generator, "RefPtr<::@property_class_name@> @property_variable_name@;")); - TRY(generate_loader_for_object(*value, property_generator.fork(), property_variable_name, indentation + 1, UseObjectConstructor::Yes)); - - // Set the property on the object. - TRY(append(property_generator, "@object_name@->set_@key@(*@property_variable_name@);")); - property_generator.appendln(""); - return {}; - })); - - // Layout - if (gml_object.layout_object() != nullptr) { - TRY(append(generator, "RefPtr layout;")); - TRY(generate_loader_for_object(*gml_object.layout_object(), generator.fork(), "layout"_string, indentation + 1, UseObjectConstructor::Yes)); - TRY(append(generator, "@object_name@->set_layout(layout.release_nonnull());")); - generator.appendln(""); - } - - // Children - size_t current_child_index = 0; - auto next_child_name = [&]() { - return String::formatted("{}_child_{}", object_name, current_child_index++); - }; - TRY(gml_object.try_for_each_child_object([&](auto const& child) -> ErrorOr { - // Spacer is a pseudo-class that insteads causes a call to `Widget::add_spacer` on the parent object. - if (child.name() == "GUI::Layout::Spacer"sv) { - TRY(append(generator, "@object_name@->add_spacer();")); - return {}; - } - - auto child_generator = generator.fork(); - auto child_variable_name = TRY(next_child_name()); - child_generator.set("child_variable_name", child_variable_name.bytes_as_string_view()); - child_generator.set("child_class_name", child.name()); - TRY(append(child_generator, "RefPtr<::@child_class_name@> @child_variable_name@;")); - TRY(generate_loader_for_object(child, child_generator.fork(), child_variable_name, indentation + 1, UseObjectConstructor::Yes)); - - // Handle the current special case of child adding. - // FIXME: This should be using the proper API for handling object properties. - if (gml_object.name() == "GUI::TabWidget"sv) - TRY(append(child_generator, "static_ptr_cast(@object_name@)->add_widget(*@child_variable_name@);")); - else - TRY(append(child_generator, "TRY(@object_name@->try_add_child(*@child_variable_name@));")); - child_generator.appendln(""); - return {}; - })); - - TRY(append(generator, "TRY(::GUI::initialize(*@object_name@));")); - - generator.append(TRY(String::repeated(' ', (indentation - 1) * 4))); - generator.appendln("}"); - - return {}; -} - -static ErrorOr generate_cpp(NonnullRefPtr gml, LexicalPath const& gml_file_name) -{ - StringBuilder builder; - SourceGenerator generator { builder }; - - generator.append(header); - - auto& main_class = gml->main_class(); - auto necessary_includes = TRY(extract_necessary_includes(main_class, gml_file_name, true)); - static String const always_necessary_includes[] = { - ""_string, - ""_string, - ""_string, - ""_string, - ""_string, - // For Gfx::ColorRole - ""_string, - ""_string, - // For Gfx::FontWeight - ""_string, - }; - TRY(necessary_includes.try_set_from(always_necessary_includes)); - for (auto const& include : necessary_includes) - generator.appendln(TRY(String::formatted("#include {}", include))); - - auto main_file_header = TRY(include_path_for(main_class.name(), gml_file_name)); - generator.appendln(TRY(String::formatted("#if __has_include({})", main_file_header))); - generator.appendln(TRY(String::formatted("#include {}", main_file_header))); - generator.appendln("#else"); - - // FIXME: Use a UTF-8 aware function once possible. - auto ns_position = main_class.name().find_last("::"sv); - auto ns = main_class.name().substring_view(0, ns_position.value_or(0)); - auto pure_class_name = main_class.name().substring_view(ns_position.map([](auto x) { return x + 2; }).value_or(0)); - - generator.set("class_namespace", ns); - generator.set("pure_class_name", pure_class_name); - generator.set("main_class_name", main_class.name()); - - generator.append(class_declaration); - - generator.appendln("#endif // __has_include(...)"); - - generator.append(function_start); - TRY(generate_loader_for_object(main_class, generator.fork(), "main_object"_string, 2, UseObjectConstructor::No)); - - generator.append(footer); - return builder.to_string(); -} - -ErrorOr serenity_main(Main::Arguments arguments) -{ - Core::ArgsParser argument_parser; - StringView gml_file_name; - argument_parser.add_positional_argument(gml_file_name, "GML file to compile", "GML_FILE", Core::ArgsParser::Required::Yes); - argument_parser.parse(arguments); - - auto gml_text = TRY(TRY(Core::File::open(gml_file_name, Core::File::OpenMode::Read))->read_until_eof()); - auto parsed_gml = TRY(GUI::GML::parse_gml(gml_text)); - auto generated_cpp = TRY(generate_cpp(parsed_gml, LexicalPath { gml_file_name })); - outln("{}", generated_cpp); - return 0; -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.cpp deleted file mode 100644 index 99fd5639b84..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -#include "AST/AST.h" - -namespace JSSpecCompiler { - -Tree NodeSubtreePointer::get(Badge) -{ - return m_tree_ptr.visit( - [&](NullableTree* nullable_tree) -> Tree { - NullableTree copy = *nullable_tree; - return copy.release_nonnull(); - }, - [&](Tree* tree) -> Tree { - return *tree; - }, - [&](VariableRef* tree) -> Tree { - return *tree; - }); -} - -void NodeSubtreePointer::replace_subtree(Badge, NullableTree replacement) -{ - m_tree_ptr.visit( - [&](NullableTree* nullable_tree) { - *nullable_tree = replacement; - }, - [&](Tree* tree) { - *tree = replacement.release_nonnull(); - }, - [&](VariableRef*) { - VERIFY_NOT_REACHED(); - }); -} - -Vector ControlFlowJump::references() -{ - return { &m_block }; -} - -Vector ControlFlowBranch::references() -{ - return { &m_then, &m_else }; -} - -Vector BinaryOperation::subtrees() -{ - return { { &m_left }, { &m_right } }; -} - -Vector UnaryOperation::subtrees() -{ - return { { &m_operand } }; -} - -Vector IsOneOfOperation::subtrees() -{ - Vector result = { { &m_operand } }; - for (auto& child : m_compare_values) - result.append({ &child }); - return result; -} - -Vector ReturnNode::subtrees() -{ - return { { &m_return_value } }; -} - -Vector AssertExpression::subtrees() -{ - return { { &m_condition } }; -} - -Vector IfBranch::subtrees() -{ - return { { &m_condition }, { &m_branch } }; -} - -Vector ElseIfBranch::subtrees() -{ - if (m_condition) - return { { &m_condition }, { &m_branch } }; - return { { &m_branch } }; -} - -Vector IfElseIfChain::subtrees() -{ - Vector result; - for (size_t i = 0; i < branches_count(); ++i) { - result.append({ &m_conditions[i] }); - result.append({ &m_branches[i] }); - } - if (m_else_branch) - result.append({ &m_else_branch }); - return result; -} - -TreeList::TreeList(Vector&& trees) -{ - for (auto const& tree : trees) { - if (tree->is_list()) { - for (auto const& nested_tree : as(tree)->m_trees) - m_trees.append(nested_tree); - } else { - m_trees.append(tree); - } - } -} - -Vector TreeList::subtrees() -{ - Vector result; - for (auto& expression : m_trees) - result.append({ &expression }); - return result; -} - -Vector RecordDirectListInitialization::subtrees() -{ - Vector result { &m_type_reference }; - for (auto& argument : m_arguments) { - result.append({ &argument.name }); - result.append({ &argument.value }); - } - return result; -} - -Vector FunctionCall::subtrees() -{ - Vector result = { { &m_name } }; - for (auto& child : m_arguments) - result.append({ &child }); - return result; -} - -String Variable::name() const -{ - if (m_ssa) - return MUST(String::formatted("{}@{}", m_name->m_name, m_ssa->m_version)); - return MUST(String::from_utf8(m_name->m_name)); -} - -Vector List::subtrees() -{ - Vector result; - for (auto& element : m_elements) - result.append({ &element }); - return result; -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h deleted file mode 100644 index 1c8fa49a0eb..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include "Forward.h" - -namespace JSSpecCompiler { - -template -RefPtr as(NullableTree const& tree) -{ - return dynamic_cast(tree.ptr()); -} - -class NodeSubtreePointer { -public: - NodeSubtreePointer(Tree* tree_ptr) - : m_tree_ptr(tree_ptr) - { - } - - NodeSubtreePointer(NullableTree* tree_ptr) - : m_tree_ptr(tree_ptr) - { - } - - NodeSubtreePointer(VariableRef* tree_ptr) - : m_tree_ptr(tree_ptr) - { - } - - Tree get(Badge); - void replace_subtree(Badge, NullableTree replacement); - -private: - Variant m_tree_ptr; -}; - -class VariableDeclaration : public RefCounted { -public: - virtual ~VariableDeclaration() = default; -}; - -class NamedVariableDeclaration : public VariableDeclaration { -public: - NamedVariableDeclaration(StringView name) - : m_name(name) - { - } - - StringView m_name; -}; - -class SSAVariableDeclaration : public VariableDeclaration { -public: - SSAVariableDeclaration(u64 version) - : m_version(version) - { - } - - size_t m_index = 0; - u64 m_version; -}; - -class Node : public RefCounted { -public: - virtual ~Node() = default; - - void format_tree(StringBuilder& builder); - - // For expressions, order must be the same as the evaluation order. - virtual Vector subtrees() { return {}; } - - virtual bool is_list() const { return false; } - virtual bool is_statement() { VERIFY_NOT_REACHED(); } - -protected: - template - void dump_node(StringBuilder& builder, AK::CheckedFormatString&& fmtstr, Parameters const&... parameters); - - virtual void dump_tree(StringBuilder& builder) = 0; -}; - -// Although both statements and expressions are allowed to return value, CFG building differentiates -// between them. Expressions are not allowed to change control flow, while statements are. Special -// handling required if a statement turns out to be a descendant of an expression. Roughly speaking, -// from the CFG standpoint, something like `a = ({ b + ({ c }) }) + ({ d })` will look like -// ``` -// auto tmp1 = c; -// auto tmp2 = b + tmp1; -// auto tmp3 = d; -// a = tmp1 + tmp2; -// ```. -class Statement : public Node { -public: - bool is_statement() override { return true; } -}; - -class Expression : public Node { -public: - bool is_statement() override { return false; } -}; - -class ControlFlowOperator : public Statement { -public: - bool is_statement() override { return false; } - - virtual Vector references() = 0; -}; - -class ErrorNode : public Expression { -public: - ErrorNode(StringView error = ""sv) - : m_error(error) - { - } - - StringView m_error; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class WellKnownNode : public Expression { -public: - enum Type { - False, - NewTarget, - Null, - This, - True, - Undefined, - // Update WellKnownNode::dump_tree after adding an entry here - }; - - WellKnownNode(Type type) - : m_type(type) - { - } - -protected: - void dump_tree(StringBuilder& builder) override; - -private: - Type m_type; -}; - -inline Tree const error_tree = make_ref_counted(); - -class ControlFlowFunctionReturn : public ControlFlowOperator { -public: - ControlFlowFunctionReturn(VariableRef return_value) - : m_return_value(move(return_value)) - { - } - - VariableRef m_return_value; - - Vector subtrees() override { return { { &m_return_value } }; } - Vector references() override { return {}; } - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class ControlFlowJump : public ControlFlowOperator { -public: - ControlFlowJump(BasicBlockRef block) - : m_block(block) - { - } - - Vector references() override; - - BasicBlockRef m_block; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -// This should be invalid enough to crash program on use. -inline NonnullRefPtr const invalid_continuation = make_ref_counted(nullptr); - -class ControlFlowBranch : public ControlFlowOperator { -public: - ControlFlowBranch(Tree condition, BasicBlockRef then, BasicBlockRef else_) - : m_condition(move(condition)) - , m_then(then) - , m_else(else_) - { - } - - Vector subtrees() override { return { { &m_condition } }; } - Vector references() override; - - Tree m_condition; - BasicBlockRef m_then; - BasicBlockRef m_else; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class MathematicalConstant : public Expression { -public: - MathematicalConstant(Crypto::BigFraction number) - : m_number(number) - { - } - -protected: - void dump_tree(StringBuilder& builder) override; - -private: - Crypto::BigFraction m_number; -}; - -class StringLiteral : public Expression { -public: - StringLiteral(StringView literal) - : m_literal(literal) - { - } - - StringView m_literal; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -#define ENUMERATE_UNARY_OPERATORS(F) \ - F(Invalid) \ - F(AssertCompletion) \ - F(Minus) \ - F(ReturnIfAbrubt) - -#define ENUMERATE_BINARY_OPERATORS(F) \ - F(Invalid) \ - F(ArraySubscript) \ - F(Assignment) \ - F(Comma) \ - F(CompareEqual) \ - F(CompareGreater) \ - F(CompareLess) \ - F(CompareNotEqual) \ - F(Declaration) \ - F(Division) \ - F(MemberAccess) \ - F(Minus) \ - F(Multiplication) \ - F(Plus) \ - F(Power) - -#define NAME(name) name, -#define STRINGIFY(name) #name##sv, - -enum class UnaryOperator { - ENUMERATE_UNARY_OPERATORS(NAME) -}; - -inline constexpr StringView unary_operator_names[] = { - ENUMERATE_UNARY_OPERATORS(STRINGIFY) -}; - -enum class BinaryOperator { -#define NAME(name) name, - ENUMERATE_BINARY_OPERATORS(NAME) -}; - -inline constexpr StringView binary_operator_names[] = { - ENUMERATE_BINARY_OPERATORS(STRINGIFY) -}; - -#undef NAME -#undef STRINGIFY - -class BinaryOperation : public Expression { -public: - BinaryOperation(BinaryOperator operation, Tree left, Tree right) - : m_operation(operation) - , m_left(move(left)) - , m_right(move(right)) - { - } - - Vector subtrees() override; - - BinaryOperator m_operation; - Tree m_left; - Tree m_right; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class UnaryOperation : public Expression { -public: - UnaryOperation(UnaryOperator operation, Tree operand) - : m_operation(operation) - , m_operand(move(operand)) - { - } - - Vector subtrees() override; - - UnaryOperator m_operation; - Tree m_operand; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class IsOneOfOperation : public Expression { -public: - IsOneOfOperation(Tree operand, Vector&& compare_values) - : m_operand(move(operand)) - , m_compare_values(move(compare_values)) - { - } - - Vector subtrees() override; - - Tree m_operand; - Vector m_compare_values; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class UnresolvedReference : public Expression { -public: - UnresolvedReference(StringView name) - : m_name(name) - { - } - - StringView m_name; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class ReturnNode : public Node { -public: - ReturnNode(Tree return_value) - : m_return_value(move(return_value)) - { - } - - Vector subtrees() override; - - Tree m_return_value; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -// Although assert might seems a good candidate for ControlFlowOperator, we are not interested in -// tracking control flow after a failed assertion. -class AssertExpression : public Expression { -public: - AssertExpression(Tree condition) - : m_condition(move(condition)) - { - } - - Vector subtrees() override; - - Tree m_condition; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class IfBranch : public Node { -public: - IfBranch(Tree condition, Tree branch) - : m_condition(move(condition)) - , m_branch(move(branch)) - { - } - - Vector subtrees() override; - - Tree m_condition; - Tree m_branch; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class ElseIfBranch : public Node { -public: - ElseIfBranch(NullableTree condition, Tree branch) - : m_condition(move(condition)) - , m_branch(move(branch)) - { - } - - Vector subtrees() override; - - NullableTree m_condition; - Tree m_branch; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class IfElseIfChain : public Statement { -public: - IfElseIfChain(Vector&& conditions, Vector&& branches, NullableTree else_branch) - : m_conditions(move(conditions)) - , m_branches(move(branches)) - , m_else_branch(move(else_branch)) - { - VERIFY(m_branches.size() == m_conditions.size()); - } - - Vector subtrees() override; - - // Excluding else branch, if one is present - size_t branches_count() const { return m_branches.size(); } - - Vector m_conditions; - Vector m_branches; - NullableTree m_else_branch; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class TreeList : public Statement { -public: - TreeList(Vector&& trees); - - Vector subtrees() override; - - bool is_list() const override { return true; } - - Vector m_trees; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class RecordDirectListInitialization : public Expression { -public: - struct Argument { - Tree name; - Tree value; - }; - - RecordDirectListInitialization(Tree type_reference, Vector&& arguments) - : m_type_reference(move(type_reference)) - , m_arguments(move(arguments)) - { - } - - Vector subtrees() override; - - Tree m_type_reference; - Vector m_arguments; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class FunctionCall : public Expression { -public: - FunctionCall(Tree name, Vector&& arguments) - : m_name(move(name)) - , m_arguments(move(arguments)) - { - } - - Vector subtrees() override; - - Tree m_name; - Vector m_arguments; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class SlotName : public Expression { -public: - SlotName(StringView member_name) - : m_member_name(member_name) - { - } - - StringView m_member_name; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class Variable : public Expression { -public: - Variable(NamedVariableDeclarationRef name) - : m_name(move(name)) - { - } - - NamedVariableDeclarationRef m_name; - SSAVariableDeclarationRef m_ssa; - - String name() const; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class Enumerator : public Expression { -public: - Enumerator(Badge, StringView value) - : m_value(value) - { - } - -protected: - void dump_tree(StringBuilder& builder) override; - -private: - StringView m_value; -}; - -class FunctionPointer : public Expression { -public: - FunctionPointer(FunctionDeclarationRef declaration) - : m_declaration(declaration) - { - } - - FunctionDeclarationRef m_declaration; - -protected: - void dump_tree(StringBuilder& builder) override; -}; - -class List : public Expression { -public: - List(Vector&& elements) - : m_elements(elements) - { - } - - Vector subtrees() override; - -protected: - void dump_tree(StringBuilder& builder) override; - -private: - Vector m_elements; -}; - -} - -namespace AK { - -template<> -struct Formatter : Formatter { - ErrorOr format(FormatBuilder& builder, JSSpecCompiler::Tree const& tree) - { - tree->format_tree(builder.builder()); - return {}; - } -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp deleted file mode 100644 index 00e214770c3..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -#include "AST/AST.h" -#include "Compiler/ControlFlowGraph.h" -#include "Function.h" - -namespace JSSpecCompiler { - -void Node::format_tree(StringBuilder& builder) -{ - static int current_depth = -1; - TemporaryChange depth_change(current_depth, current_depth + 1); - builder.append_repeated(' ', current_depth * 2); - dump_tree(builder); -} - -template -void Node::dump_node(StringBuilder& builder, AK::CheckedFormatString&& fmtstr, Parameters const&... parameters) -{ - AK::VariadicFormatParams variadic_format_params { parameters... }; - MUST(AK::vformat(builder, fmtstr.view(), variadic_format_params)); - builder.append("\n"sv); -} - -void ErrorNode::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "Error \"{}\"", m_error); -} - -void WellKnownNode::dump_tree(StringBuilder& builder) -{ - static constexpr StringView type_to_name[] = { - "False"sv, - "NewTarget"sv, - "Null"sv, - "This"sv, - "True"sv, - "Undefined"sv, - }; - dump_node(builder, "WellKnownNode {}", type_to_name[m_type]); -} - -void ControlFlowFunctionReturn::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "ControlFlowFunctionReturn"); - m_return_value->format_tree(builder); -} - -void ControlFlowJump::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "ControlFlowJump jump={}", m_block->m_index); -} - -void ControlFlowBranch::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "ControlFlowBranch true={} false={}", m_then->m_index, m_else->m_index); - m_condition->format_tree(builder); -} - -void MathematicalConstant::dump_tree(StringBuilder& builder) -{ - String representation; - if (Crypto::UnsignedBigInteger { 1000 }.divided_by(m_number.denominator()).remainder == 0) - representation = MUST(String::from_byte_string(m_number.to_byte_string(3))); - else - representation = MUST(String::formatted("{}/{}", MUST(m_number.numerator().to_base(10)), MUST(m_number.denominator().to_base(10)))); - dump_node(builder, "MathematicalConstant {}", representation); -} - -void StringLiteral::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "StringLiteral {}", m_literal); -} - -void BinaryOperation::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "BinaryOperation {}", binary_operator_names[to_underlying(m_operation)]); - m_left->format_tree(builder); - m_right->format_tree(builder); -} - -void UnaryOperation::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "UnaryOperation {}", unary_operator_names[to_underlying(m_operation)]); - m_operand->format_tree(builder); -} - -void IsOneOfOperation::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "IsOneOf"); - m_operand->format_tree(builder); - for (auto const& compare_value : m_compare_values) - compare_value->format_tree(builder); -} - -void UnresolvedReference::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "UnresolvedReference {}", m_name); -} - -void ReturnNode::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "ReturnNode"); - m_return_value->format_tree(builder); -} - -void AssertExpression::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "AssertExpression"); - m_condition->format_tree(builder); -} - -void IfBranch::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "IfBranch"); - m_condition->format_tree(builder); - m_branch->format_tree(builder); -} - -void ElseIfBranch::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "ElseIfBranch {}", m_condition ? "ElseIf" : "Else"); - if (m_condition) - m_condition->format_tree(builder); - m_branch->format_tree(builder); -} - -void IfElseIfChain::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "IfElseIfChain"); - - for (size_t i = 0; i < branches_count(); ++i) { - m_conditions[i]->format_tree(builder); - m_branches[i]->format_tree(builder); - } - if (m_else_branch) - m_else_branch->format_tree(builder); -} - -void TreeList::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "TreeList"); - for (auto const& expression : m_trees) - expression->format_tree(builder); -} - -void RecordDirectListInitialization::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "RecordDirectListInitialization"); - m_type_reference->format_tree(builder); - for (auto const& argument : m_arguments) - builder.appendff("{}{}", argument.name, argument.value); -} - -void FunctionCall::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "FunctionCall"); - m_name->format_tree(builder); - for (auto const& argument : m_arguments) - argument->format_tree(builder); -} - -void SlotName::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "Slot {}", m_member_name); -} - -void Variable::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "Var {}", name()); -} - -void Enumerator::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "Enumerator {}", m_value); -} - -void FunctionPointer::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "Func \"{}\"", m_declaration->name()); -} - -void List::dump_tree(StringBuilder& builder) -{ - dump_node(builder, "List"); - for (auto const& element : m_elements) - element->format_tree(builder); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/CMakeLists.txt b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/CMakeLists.txt deleted file mode 100644 index 6f7a12170ff..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -set(SOURCES - AST/AST.cpp - AST/ASTPrinting.cpp - Compiler/CompilerPass.cpp - Compiler/ControlFlowGraph.cpp - Compiler/GenericASTPass.cpp - Compiler/Passes/CFGBuildingPass.cpp - Compiler/Passes/CFGSimplificationPass.cpp - Compiler/Passes/DeadCodeEliminationPass.cpp - Compiler/Passes/IfBranchMergingPass.cpp - Compiler/Passes/ReferenceResolvingPass.cpp - Compiler/Passes/SSABuildingPass.cpp - Parser/Algorithm.cpp - Parser/AlgorithmStep.cpp - Parser/AlgorithmStepList.cpp - Parser/CppASTConverter.cpp - Parser/Lexer.cpp - Parser/Specification.cpp - Parser/SpecificationClause.cpp - Parser/SpecificationFunction.cpp - Parser/SpecificationParsingContext.cpp - Parser/SpecificationParsingStep.cpp - Parser/TextParser.cpp - Parser/XMLUtils.cpp - Runtime/Object.cpp - Runtime/ObjectType.cpp - Runtime/Realm.cpp - DiagnosticEngine.cpp - Function.cpp - main.cpp -) - -lagom_tool(JSSpecCompiler LIBS LibCpp LibMain LibXML LibCrypto) -target_include_directories(JSSpecCompiler PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) -target_compile_options(JSSpecCompiler PRIVATE -Wno-missing-field-initializers) diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/CompilationPipeline.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/CompilationPipeline.h deleted file mode 100644 index dd259145826..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/CompilationPipeline.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -#include "Forward.h" - -namespace JSSpecCompiler { - -class CompilationStep { -public: - CompilationStep(StringView name) - : m_name(name) - { - } - - virtual ~CompilationStep() = default; - virtual void run(TranslationUnitRef translation_unit) = 0; - - StringView name() const { return m_name; } - -private: - StringView m_name; -}; - -class NonOwningCompilationStep : public CompilationStep { -public: - template - NonOwningCompilationStep(StringView name, Func&& func) - : CompilationStep(name) - , m_func(func) - { - } - - void run(TranslationUnitRef translation_unit) override { m_func(translation_unit); } - -private: - AK::Function m_func; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/CompilerPass.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/CompilerPass.cpp deleted file mode 100644 index 7c849bb10ff..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/CompilerPass.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Compiler/CompilerPass.h" -#include "Function.h" - -namespace JSSpecCompiler { - -void IntraproceduralCompilerPass::run() -{ - for (auto const& function : m_translation_unit->functions_to_compile()) { - m_function = function; - process_function(); - } -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/CompilerPass.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/CompilerPass.h deleted file mode 100644 index e2433818139..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/CompilerPass.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -#include "Forward.h" - -namespace JSSpecCompiler { - -class CompilerPass { -public: - CompilerPass(TranslationUnitRef translation_unit) - : m_translation_unit(translation_unit) - { - } - - virtual ~CompilerPass() = default; - - virtual void run() = 0; - -protected: - TranslationUnitRef m_translation_unit; -}; - -class IntraproceduralCompilerPass : public CompilerPass { -public: - IntraproceduralCompilerPass(TranslationUnitRef translation_unit) - : CompilerPass(translation_unit) - { - } - - void run() override final; - -protected: - virtual void process_function() = 0; - - FunctionDefinitionRef m_function; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.cpp deleted file mode 100644 index ae1526f9af8..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -#include "AST/AST.h" -#include "Compiler/ControlFlowGraph.h" - -using namespace JSSpecCompiler; - -ErrorOr AK::Formatter::format(FormatBuilder& format_builder, ControlFlowGraph const& control_flow_graph) -{ - auto& builder = format_builder.builder(); - - for (auto const& block : control_flow_graph.blocks) { - builder.appendff("{}:\n", block->m_index); - for (auto const& phi_node : block->m_phi_nodes) { - builder.appendff("{} = phi(", phi_node.var->name()); - for (auto const& branches : phi_node.branches) { - builder.appendff("{}: {}", branches.block->m_index, branches.value->name()); - if (&branches != &phi_node.branches.last()) - builder.appendff(", "); - } - builder.appendff(")\n"); - } - for (auto const& expression : block->m_expressions) - builder.appendff("{}", expression); - builder.appendff("{}\n", Tree(block->m_continuation)); - } - - // Remove trailing \n - builder.trim(1); - - return {}; -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.h deleted file mode 100644 index 1c6c064e5a0..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -#include "Forward.h" - -namespace JSSpecCompiler { - -class BasicBlock : public RefCounted { -public: - struct PhiNode { - struct Branch { - BasicBlockRef block; - VariableRef value; - }; - - VariableRef var; - Vector branches; - }; - - BasicBlock(size_t index, NonnullRefPtr continuation) - : m_index(index) - , m_continuation(move(continuation)) - , m_immediate_dominator(nullptr) - { - } - - size_t m_index; - Vector m_phi_nodes; - Vector m_expressions; - NonnullRefPtr m_continuation; - BasicBlockRef m_immediate_dominator; -}; - -class ControlFlowGraph : public RefCounted { -public: - ControlFlowGraph() { } - - size_t blocks_count() const { return blocks.size(); } - - Vector> blocks; - BasicBlockRef start_block; - BasicBlockRef end_block; -}; - -} - -namespace AK { - -template<> -struct Formatter : Formatter { - ErrorOr format(FormatBuilder& builder, JSSpecCompiler::ControlFlowGraph const& control_flow_graph); -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/EnableGraphPointers.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/EnableGraphPointers.h deleted file mode 100644 index fb827d1c0ef..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/EnableGraphPointers.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace JSSpecCompiler { - -struct VoidRef { }; - -template -class EnableGraphPointers { -public: - class VertexBase { - public: - VertexBase() = default; - VertexBase(size_t index) - : m_index(index) - { - } - - bool is_invalid() const { return m_index == invalid_node; } - operator size_t() const { return m_index; } - - explicit VertexBase(NativeNodeRef const& node) - requires(!IsSame) - : VertexBase(node->m_index) - { - } - - auto& operator*() const { return m_instance->m_nodes[m_index]; } - auto* operator->() const { return &m_instance->m_nodes[m_index]; } - - protected: - size_t m_index = invalid_node; - }; - - using Vertex = VertexBase; - - inline static constexpr size_t invalid_node = NumericLimits::max(); - - template - void with_graph(Func func) - { - m_instance = static_cast(this); - func(); - m_instance = nullptr; - } - - template - void with_graph(size_t n, Func func) - { - m_instance = static_cast(this); - m_instance->m_nodes.resize(n); - func(); - m_instance->m_nodes.clear(); - m_instance = nullptr; - } - -protected: - inline static thread_local T* m_instance = nullptr; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/GenericASTPass.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/GenericASTPass.cpp deleted file mode 100644 index 74e7b461c40..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/GenericASTPass.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -#include "AST/AST.h" -#include "Compiler/GenericASTPass.h" -#include "Function.h" - -namespace JSSpecCompiler { - -void RecursiveASTVisitor::run_in_const_subtree(NullableTree nullable_tree) -{ - if (nullable_tree) { - auto tree = nullable_tree.release_nonnull(); - auto tree_copy = tree; - NodeSubtreePointer pointer { &tree }; - recurse(tree, pointer); - VERIFY(tree == tree_copy); - } -} - -void RecursiveASTVisitor::run_in_subtree(Tree& tree) -{ - NodeSubtreePointer pointer { &tree }; - recurse(tree, pointer); -} - -void RecursiveASTVisitor::replace_current_node_with(NullableTree tree) -{ - m_current_subtree_pointer->replace_subtree({}, move(tree)); -} - -RecursionDecision RecursiveASTVisitor::recurse(Tree root, NodeSubtreePointer& pointer) -{ - TemporaryChange change { m_current_subtree_pointer, &pointer }; - - RecursionDecision decision = on_entry(root); - root = pointer.get({}); - - if (decision == RecursionDecision::Recurse) { - for (auto& child : root->subtrees()) { - if (recurse(child.get({}), child) == RecursionDecision::Break) - return RecursionDecision::Break; - } - } - - on_leave(root); - - return RecursionDecision::Continue; -} - -void GenericASTPass::process_function() -{ - run_in_subtree(m_function->m_ast); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/GenericASTPass.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/GenericASTPass.h deleted file mode 100644 index fbea80347a2..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/GenericASTPass.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -#include "Compiler/CompilerPass.h" - -namespace JSSpecCompiler { - -class RecursiveASTVisitor { -public: - virtual ~RecursiveASTVisitor() = default; - - void run_in_const_subtree(NullableTree tree); - void run_in_subtree(Tree& tree); - -protected: - virtual RecursionDecision on_entry(Tree) { return RecursionDecision::Recurse; } - virtual void on_leave(Tree) { } - - void replace_current_node_with(NullableTree tree); - -private: - RecursionDecision recurse(Tree root, NodeSubtreePointer& pointer); - - NodeSubtreePointer* m_current_subtree_pointer = nullptr; -}; - -class GenericASTPass - : public IntraproceduralCompilerPass - , protected RecursiveASTVisitor { -public: - using IntraproceduralCompilerPass::IntraproceduralCompilerPass; - -protected: - void process_function() override; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGBuildingPass.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGBuildingPass.cpp deleted file mode 100644 index 5e1d443a5bc..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGBuildingPass.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -#include "AST/AST.h" -#include "Compiler/Passes/CFGBuildingPass.h" -#include "Function.h" - -namespace JSSpecCompiler { - -void CFGBuildingPass::process_function() -{ - m_cfg = m_function->m_cfg = make_ref_counted(); - m_current_block = m_cfg->start_block = create_empty_block(); - m_cfg->end_block = create_empty_block(); - m_cfg->end_block->m_continuation = make_ref_counted( - make_ref_counted(m_function->m_named_return_value)); - m_is_expression_stack = { false }; - - run_in_subtree(m_function->m_ast); - - // FIXME: What should we do if control flow reached the end of the function? Returning - // error_tree will 100% confuse future passes. - m_current_block->m_expressions.append(make_ref_counted( - BinaryOperator::Assignment, - make_ref_counted(m_function->m_named_return_value), - error_tree)); - m_current_block->m_continuation = make_ref_counted(m_cfg->end_block); -} - -RecursionDecision CFGBuildingPass::on_entry(Tree tree) -{ - m_is_expression_stack.append(!as(tree).is_null()); - - if (auto if_else_if_chain = as(tree); if_else_if_chain) { - auto* end_block = create_empty_block(); - - for (auto [i, current_condition] : enumerate(if_else_if_chain->m_conditions)) { - run_in_subtree(current_condition); - will_be_used_as_expression(current_condition); - auto* condition_block = exchange_current_with_empty(); - - auto* branch_entry = m_current_block; - run_in_subtree(if_else_if_chain->m_branches[i]); - auto* branch_return = exchange_current_with_empty(); - branch_return->m_continuation = make_ref_counted(end_block); - - condition_block->m_continuation = make_ref_counted(current_condition, branch_entry, m_current_block); - } - - if (if_else_if_chain->m_else_branch) - run_in_const_subtree(if_else_if_chain->m_else_branch); - m_current_block->m_continuation = make_ref_counted(end_block); - - m_current_block = end_block; - return RecursionDecision::Continue; - } - - if (auto return_node = as(tree); return_node) { - Tree return_assignment = make_ref_counted( - BinaryOperator::Assignment, - make_ref_counted(m_function->m_named_return_value), - return_node->m_return_value); - run_in_subtree(return_assignment); - auto* return_block = exchange_current_with_empty(); - return_block->m_continuation = make_ref_counted(m_cfg->end_block); - - return RecursionDecision::Continue; - } - - return RecursionDecision::Recurse; -} - -void CFGBuildingPass::on_leave(Tree tree) -{ - (void)m_is_expression_stack.take_last(); - - if (!m_is_expression_stack.last() && as(tree)) - m_current_block->m_expressions.append(tree); -} - -BasicBlockRef CFGBuildingPass::create_empty_block() -{ - m_cfg->blocks.append(make_ref_counted(m_cfg->blocks_count(), invalid_continuation)); - return m_cfg->blocks.last(); -} - -BasicBlockRef CFGBuildingPass::exchange_current_with_empty() -{ - auto* new_block = create_empty_block(); - swap(new_block, m_current_block); - return new_block; -} - -void CFGBuildingPass::will_be_used_as_expression(Tree const& tree) -{ - if (m_current_block->m_expressions.is_empty()) - VERIFY(is(tree.ptr())); - else - VERIFY(m_current_block->m_expressions.take_last() == tree); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGBuildingPass.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGBuildingPass.h deleted file mode 100644 index 2586d24e79f..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGBuildingPass.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -#include "Compiler/ControlFlowGraph.h" -#include "Compiler/GenericASTPass.h" - -namespace JSSpecCompiler { - -class CFGBuildingPass - : public IntraproceduralCompilerPass - , private RecursiveASTVisitor { -public: - inline static constexpr StringView name = "cfg-building"sv; - - using IntraproceduralCompilerPass::IntraproceduralCompilerPass; - -protected: - void process_function() override; - RecursionDecision on_entry(Tree tree) override; - void on_leave(Tree tree) override; - -private: - BasicBlockRef create_empty_block(); - BasicBlockRef exchange_current_with_empty(); - void will_be_used_as_expression(Tree const& tree); - - ControlFlowGraph* m_cfg; - BasicBlockRef m_current_block; - Vector m_is_expression_stack; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGSimplificationPass.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGSimplificationPass.cpp deleted file mode 100644 index a9655ba95f2..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGSimplificationPass.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Compiler/Passes/CFGSimplificationPass.h" -#include "AST/AST.h" -#include "Function.h" - -namespace JSSpecCompiler { - -void CFGSimplificationPass::process_function() -{ - auto& graph = *m_function->m_cfg; - - m_replacement.clear(); - m_replacement.resize(graph.blocks_count()); - m_state.clear(); - m_state.resize(graph.blocks_count()); - - for (auto const& block : graph.blocks) { - m_replacement[block->m_index] = block; - if (block->m_expressions.size() == 0) - if (auto jump = as(block->m_continuation); jump) - m_replacement[block->m_index] = jump->m_block; - } - - for (size_t i = 0; i < graph.blocks_count(); ++i) - if (m_state[i] == State::NotUsed) - VERIFY(compute_replacement_block(i)); - - // Fixing references - graph.start_block = m_replacement[graph.start_block->m_index]; - for (auto const& block : graph.blocks) { - for (auto* next_block : block->m_continuation->references()) - *next_block = m_replacement[(*next_block)->m_index]; - } - - // Removing unused nodes - m_state.span().fill(State::NotUsed); - compute_referenced_blocks(graph.start_block); - - size_t j = 0; - for (size_t i = 0; i < graph.blocks_count(); ++i) { - if (m_state[graph.blocks[i]->m_index] == State::Used) { - graph.blocks[j] = graph.blocks[i]; - graph.blocks[j]->m_index = j; - ++j; - } - } - graph.blocks.shrink(j); -} - -bool CFGSimplificationPass::compute_replacement_block(size_t i) -{ - if (m_state[i] == State::CurrentlyInside) - return false; - VERIFY(m_state[i] == State::NotUsed); - m_state[i] = State::CurrentlyInside; - - size_t j = m_replacement[i]->m_index; - - if (i == j) - return true; - if (m_state[j] == State::NotUsed) - if (!compute_replacement_block(j)) - return false; - m_replacement[i] = m_replacement[j]; - - m_state[i] = State::Used; - return true; -} - -void CFGSimplificationPass::compute_referenced_blocks(BasicBlockRef block) -{ - if (m_state[block->m_index] == State::Used) - return; - m_state[block->m_index] = State::Used; - - for (auto* next : block->m_continuation->references()) - compute_referenced_blocks(*next); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGSimplificationPass.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGSimplificationPass.h deleted file mode 100644 index abd0c3a67b6..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/CFGSimplificationPass.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Compiler/CompilerPass.h" -#include "Compiler/ControlFlowGraph.h" - -namespace JSSpecCompiler { - -// CFGSimplificationPass removes empty `BasicBlock`s with an unconditional jump continuation. It -// also removes unreferenced blocks from the graph. -class CFGSimplificationPass : public IntraproceduralCompilerPass { -public: - inline static constexpr StringView name = "cfg-simplification"sv; - - using IntraproceduralCompilerPass::IntraproceduralCompilerPass; - -protected: - void process_function() override; - -private: - enum class State : char { - NotUsed, - CurrentlyInside, - Used, - }; - - bool compute_replacement_block(size_t i); - void compute_referenced_blocks(BasicBlockRef block); - - Vector m_replacement; - Vector m_state; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/DeadCodeEliminationPass.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/DeadCodeEliminationPass.cpp deleted file mode 100644 index 48ec6d728ac..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/DeadCodeEliminationPass.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Compiler/Passes/DeadCodeEliminationPass.h" -#include "AST/AST.h" -#include "Compiler/ControlFlowGraph.h" -#include "Compiler/StronglyConnectedComponents.h" -#include "Function.h" - -namespace JSSpecCompiler { - -void DeadCodeEliminationPass::process_function() -{ - with_graph(m_function->m_local_ssa_variables.size(), [&] { - remove_unused_phi_nodes(); - }); - m_function->reindex_ssa_variables(); -} - -DeadCodeEliminationPass::Vertex DeadCodeEliminationPass::as_vertex(Variable* variable) -{ - return Vertex(variable->m_ssa); -} - -RecursionDecision DeadCodeEliminationPass::on_entry(Tree tree) -{ - if (tree->is_statement()) - TODO(); - return RecursionDecision::Recurse; -} - -void DeadCodeEliminationPass::on_leave(Tree tree) -{ - if (auto variable = as(tree); variable) - as_vertex(variable)->is_referenced = true; -} - -void DeadCodeEliminationPass::remove_unused_phi_nodes() -{ - for (auto const& block : m_function->m_cfg->blocks) { - for (auto const& phi_node : block->m_phi_nodes) { - auto to = as_vertex(phi_node.var); - for (auto const& branch : phi_node.branches) { - auto from = as_vertex(branch.value); - - from->outgoing_edges.append(to); - to->incoming_edges.append(from); - } - } - - for (auto& expr : block->m_expressions) - run_in_subtree(expr); - run_in_const_subtree(block->m_continuation); - } - - // FIXME?: There surely must be a way to do this in a linear time without finding strongly - // connected components. - for (auto const& component : find_strongly_connected_components(m_nodes)) { - bool is_referenced = false; - - for (Vertex u : component) - for (Vertex v : u->outgoing_edges) - is_referenced |= v->is_referenced; - - if (is_referenced) - for (Vertex u : component) - u->is_referenced = true; - } - - for (auto const& block : m_function->m_cfg->blocks) { - block->m_phi_nodes.remove_all_matching([&](auto const& node) { - return !as_vertex(node.var)->is_referenced; - }); - } - - m_function->m_local_ssa_variables.remove_all_matching([&](auto const& variable) { - return !Vertex(variable)->is_referenced; - }); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/DeadCodeEliminationPass.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/DeadCodeEliminationPass.h deleted file mode 100644 index f8b3c022227..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/DeadCodeEliminationPass.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Compiler/EnableGraphPointers.h" -#include "Compiler/GenericASTPass.h" -#include "Compiler/StronglyConnectedComponents.h" - -namespace JSSpecCompiler { - -class DeadCodeEliminationPass - : public IntraproceduralCompilerPass - , private RecursiveASTVisitor - , private EnableGraphPointers { -public: - inline static constexpr StringView name = "dce"sv; - - using IntraproceduralCompilerPass::IntraproceduralCompilerPass; - -protected: - void process_function() override; - -private: - friend EnableGraphPointers; - - static Vertex as_vertex(Variable* variable); - RecursionDecision on_entry(Tree tree) override; - void on_leave(Tree tree) override; - void remove_unused_phi_nodes(); - - struct NodeData { - Vector outgoing_edges; - Vector incoming_edges; - - bool is_referenced = false; - }; - - Vector m_nodes; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/IfBranchMergingPass.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/IfBranchMergingPass.cpp deleted file mode 100644 index aa94daf4642..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/IfBranchMergingPass.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -#include "AST/AST.h" -#include "Compiler/Passes/IfBranchMergingPass.h" - -namespace JSSpecCompiler { - -RecursionDecision IfBranchMergingPass::on_entry(Tree tree) -{ - if (auto list = as(tree); list) { - Vector result; - Vector unmerged_branches; - - auto merge_if_needed = [&] { - if (!unmerged_branches.is_empty()) { - result.append(merge_branches(unmerged_branches)); - unmerged_branches.clear(); - } - }; - - for (auto const& node : list->m_trees) { - if (is(node.ptr())) { - merge_if_needed(); - unmerged_branches.append(node); - } else if (is(node.ptr())) { - unmerged_branches.append(node); - } else { - merge_if_needed(); - result.append(node); - } - } - merge_if_needed(); - - list->m_trees = move(result); - } - return RecursionDecision::Recurse; -} - -Tree IfBranchMergingPass::merge_branches(Vector const& unmerged_branches) -{ - static Tree const error = make_ref_counted("Cannot make sense of if-elseif-else chain"sv); - - VERIFY(unmerged_branches.size() >= 1); - - Vector conditions; - Vector branches; - NullableTree else_branch; - - if (auto if_branch = as(unmerged_branches[0]); if_branch) { - conditions.append(if_branch->m_condition); - branches.append(if_branch->m_branch); - } else { - return error; - } - - for (size_t i = 1; i < unmerged_branches.size(); ++i) { - auto branch = as(unmerged_branches[i]); - - if (!branch) - return error; - - if (!branch->m_condition) { - // There might be situation like: - // 1. If , then - // ... - // 2. Else, - // a. If , then - // ... - // 3. Else, - // ... - auto substep_list = as(branch->m_branch); - if (substep_list && substep_list->m_trees.size() == 1) { - if (auto nested_if = as(substep_list->m_trees[0]); nested_if) - branch = make_ref_counted(nested_if->m_condition, nested_if->m_branch); - } - } - - if (branch->m_condition) { - conditions.append(branch->m_condition.release_nonnull()); - branches.append(branch->m_branch); - } else { - if (i + 1 != unmerged_branches.size()) - return error; - else_branch = branch->m_branch; - } - } - - return make_ref_counted(move(conditions), move(branches), else_branch); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/IfBranchMergingPass.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/IfBranchMergingPass.h deleted file mode 100644 index d61c85eefef..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/IfBranchMergingPass.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Compiler/GenericASTPass.h" - -namespace JSSpecCompiler { - -// IfBranchMergingPass, unsurprisingly, merges if-elseif-else chains, represented as a separate -// nodes after parsing, into one IfElseIfChain node. It also deals with the following nonsense from -// the spec: -// ``` -// 1. If , then -// ... -// 2. Else, -// a. If , then -// ... -// 3. Else, -// ... -// ``` -class IfBranchMergingPass : public GenericASTPass { -public: - inline static constexpr StringView name = "if-branch-merging"sv; - - using GenericASTPass::GenericASTPass; - -protected: - RecursionDecision on_entry(Tree tree) override; - -private: - static Tree merge_branches(Vector const& unmerged_branches); -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/ReferenceResolvingPass.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/ReferenceResolvingPass.cpp deleted file mode 100644 index faf2f756e03..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/ReferenceResolvingPass.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -#include "AST/AST.h" -#include "Compiler/Passes/ReferenceResolvingPass.h" -#include "Function.h" - -namespace JSSpecCompiler { - -void ReferenceResolvingPass::process_function() -{ - for (auto argument : m_function->arguments()) - m_function->m_local_variables.set(argument.name, make_ref_counted(argument.name)); - GenericASTPass::process_function(); -} - -RecursionDecision ReferenceResolvingPass::on_entry(Tree tree) -{ - if (auto binary_operation = as(tree); binary_operation) { - if (binary_operation->m_operation != BinaryOperator::Declaration) - return RecursionDecision::Recurse; - - binary_operation->m_operation = BinaryOperator::Assignment; - - if (auto variable_name = as(binary_operation->m_left); variable_name) { - auto name = variable_name->m_name; - if (!m_function->m_local_variables.contains(name)) - m_function->m_local_variables.set(name, make_ref_counted(name)); - } - } - return RecursionDecision::Recurse; -} - -void ReferenceResolvingPass::on_leave(Tree tree) -{ - if (auto reference = as(tree); reference) { - auto name = reference->m_name; - - if (name.starts_with("[["sv) && name.ends_with("]]"sv)) { - replace_current_node_with(make_ref_counted(name.substring_view(2, name.length() - 4))); - return; - } - - if (auto it = m_function->m_local_variables.find(name); it != m_function->m_local_variables.end()) { - replace_current_node_with(make_ref_counted(it->value)); - return; - } - - if (auto function = m_translation_unit->find_abstract_operation_by_name(name)) { - replace_current_node_with(make_ref_counted(function)); - return; - } - } -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/ReferenceResolvingPass.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/ReferenceResolvingPass.h deleted file mode 100644 index 22cd698a6ff..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/ReferenceResolvingPass.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Compiler/GenericASTPass.h" - -namespace JSSpecCompiler { - -// ReferenceResolvingPass collects all variable names declared in the function and replaces -// UnresolvedReference nodes with either SlotName, Variable, or FunctionPointer nodes. -class ReferenceResolvingPass : public GenericASTPass { -public: - inline static constexpr StringView name = "reference-resolving"sv; - - using GenericASTPass::GenericASTPass; - -protected: - void process_function() override; - RecursionDecision on_entry(Tree tree) override; - void on_leave(Tree tree) override; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/SSABuildingPass.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/SSABuildingPass.cpp deleted file mode 100644 index 48a55d24d34..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/SSABuildingPass.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -#include "AST/AST.h" -#include "Compiler/GenericASTPass.h" -#include "Compiler/Passes/SSABuildingPass.h" -#include "Function.h" - -namespace JSSpecCompiler { - -void SSABuildingPass::process_function() -{ - m_dtree_timer = 0; - m_order.clear(); - m_mark_version = 1; - m_def_stack.clear(); - m_next_id.clear(); - m_undo_vector.clear(); - m_graph = m_function->m_cfg; - - with_graph(m_graph->blocks_count(), [&] { - compute_dominator_tree(); - compute_dominance_frontiers(); - place_phi_nodes(); - rename_variables(); - }); -} - -// ===== compute_dominator_tree ===== -namespace { -class DSU { - struct NodeData { - size_t sdom; - size_t parent; - }; - -public: - DSU(size_t n) - : n(n) - { - m_nodes.resize(n); - for (size_t i = 0; i < n; ++i) - m_nodes[i] = { i, i }; - } - - NodeData get(size_t u) - { - if (m_nodes[u].parent == u) - return { n, u }; - auto [sdom, root] = get(m_nodes[u].parent); - sdom = min(sdom, m_nodes[u].sdom); - return m_nodes[u] = { sdom, root }; - } - - void merge(size_t u, size_t v, size_t v_sdom) - { - m_nodes[v] = { v_sdom, u }; - } - -private: - size_t n; - Vector m_nodes; -}; -} - -void SSABuildingPass::compute_order(BasicBlockRef u, Vertex parent) -{ - if (m_nodes[u->m_index].is_used) - return; - m_nodes[u->m_index].is_used = true; - - Vertex reordered_u = m_order.size(); - m_order.append(RefPtr(u).release_nonnull()); - reordered_u->parent = parent; - - for (auto* v : u->m_continuation->references()) - compute_order(*v, reordered_u); -} - -void SSABuildingPass::compute_dominator_tree() -{ - size_t n = m_graph->blocks_count(); - m_nodes.resize(n); - - // Algorithm is from https://tanujkhattar.wordpress.com/2016/01/11/dominator-tree-of-a-directed-graph/ , - // an author writes awful CP-style write-only code, but the explanation is pretty good. - - // Step 1 - compute_order(m_graph->start_block); - VERIFY(m_order.size() == n); - for (size_t i = 0; i < n; ++i) - m_order[i]->m_index = i; - m_graph->blocks = m_order; - - for (size_t i = 0; i < n; ++i) { - Vertex u = i; - - for (auto* reference : u.block()->m_continuation->references()) { - Vertex v { *reference }; - - v->incoming_edges.append(u); - u->outgoing_edges.append(v); - } - } - - // Steps 2 & 3 - DSU dsu(n); - - for (size_t i = n - 1; i > 0; --i) { - Vertex u = i; - - Vertex& current_sdom = u->semi_dominator; - current_sdom = n; - - for (Vertex v : u->incoming_edges) { - if (v < u) - current_sdom = min(current_sdom, v); - else - current_sdom = min(current_sdom, dsu.get(v).sdom); - } - - current_sdom->buckets.append(u); - for (Vertex w : u->buckets) { - Vertex v = dsu.get(w).sdom; - - if (v->semi_dominator == w->semi_dominator) - w->immediate_dominator = v->semi_dominator; - else - w->immediate_dominator = v; - } - dsu.merge(u->parent, u, current_sdom); - } - - m_nodes[0].immediate_dominator = invalid_node; - for (size_t i = 1; i < n; ++i) { - Vertex u = i; - - if (u->immediate_dominator.is_invalid()) - u->immediate_dominator = 0; - else if (u->immediate_dominator != u->semi_dominator) - u->immediate_dominator = u->immediate_dominator->immediate_dominator; - } - - // Populate dtree_children & BasicBlock::immediate_dominator - for (size_t i = 0; i < n; ++i) { - Vertex u = i; - - if (i != 0) { - u.block()->m_immediate_dominator = u->immediate_dominator.block(); - u->immediate_dominator->dtree_children.append(u); - } else { - u.block()->m_immediate_dominator = nullptr; - } - } -} - -// ===== compute_dominance_frontiers ===== -template -Vector SSABuildingPass::unique(Args const&... args) -{ - ++m_mark_version; - - Vector result; - (([&](auto const& list) { - for (Vertex u : list) { - if (u->mark != m_mark_version) { - u->mark = m_mark_version; - result.append(u); - } - } - })(args), - ...); - return result; -} - -void SSABuildingPass::compute_dtree_tin_tout(Vertex u) -{ - u->tin = m_dtree_timer++; - for (Vertex v : u->dtree_children) - compute_dtree_tin_tout(v); - u->tout = m_dtree_timer++; -} - -bool SSABuildingPass::is_strictly_dominating(Vertex u, Vertex v) -{ - return u != v && u->tin <= v->tin && v->tout <= u->tout; -} - -void SSABuildingPass::compute_dominance_frontiers() -{ - compute_dtree_tin_tout(0); - - // Algorithm from https://en.wikipedia.org/wiki/Static_single-assignment_form#Converting%20to%20SSA:~:text=their%20paper%20titled-,A%20Simple%2C%20Fast%20Dominance%20Algorithm,-%3A%5B13%5D . - // DF(u) = {w : !(u sdom w) /\ (\exists v \in incoming_edges(v) : u dom v)} - for (size_t wi = 0; wi < m_nodes.size(); ++wi) { - Vertex w = wi; - - for (Vertex v : w->incoming_edges) { - Vertex u = v; - while (u != invalid_node && !is_strictly_dominating(u, w)) { - u->d_frontier.append(w); - u = u->immediate_dominator; - } - } - } - - for (size_t i = 0; i < m_nodes.size(); ++i) { - Vertex u = i; - - u->d_frontier = unique(u->d_frontier); - } -} - -// ===== place_phi_nodes ===== -namespace { -class VariableAssignmentCollector : private RecursiveASTVisitor { -public: - VariableAssignmentCollector(OrderedHashMap>& declarations) - : m_declarations(declarations) - { - } - - void run(BasicBlockRef block) - { - m_current_block = block; - - for (auto& expression : block->m_expressions) - run_in_subtree(expression); - run_in_const_subtree(block->m_continuation); - } - -protected: - RecursionDecision on_entry(Tree tree) override - { - if (tree->is_statement()) - TODO(); - return RecursionDecision::Recurse; - } - - void on_leave(Tree tree) override - { - if (auto binary_operation = as(tree); binary_operation) { - if (binary_operation->m_operation != BinaryOperator::Assignment) - return; - - if (auto variable = as(binary_operation->m_left); variable) { - auto& vector = m_declarations.get(variable->m_name).value(); - if (vector.is_empty() || vector.last() != m_current_block) - vector.append(m_current_block); - } - } - } - -private: - BasicBlockRef m_current_block; - OrderedHashMap>& m_declarations; -}; -} - -void SSABuildingPass::add_phi_node(BasicBlockRef block, NamedVariableDeclarationRef decl) -{ - BasicBlock::PhiNode node { .var = make_ref_counted(decl) }; - for (Vertex incoming : Vertex(block)->incoming_edges) { - BasicBlockRef incoming_block = incoming.block(); - auto value = make_ref_counted(decl); - node.branches.append({ .block = incoming_block, .value = value }); - } - block->m_phi_nodes.append(move(node)); -} - -void SSABuildingPass::place_phi_nodes() -{ - // Entry block has implicit declarations of all variables. - OrderedHashMap> m_declarations; - for (auto const& [name, var_decl] : m_function->m_local_variables) - m_declarations.set(var_decl, { m_order[0] }); - m_declarations.set(m_function->m_named_return_value, { m_order[0] }); - - VariableAssignmentCollector collector(m_declarations); - for (auto const& block : m_order) - collector.run(block); - - for (auto const& [decl, blocks] : m_declarations) { - ++m_mark_version; - - Queue queue; - for (auto const& block : blocks) - queue.enqueue(block); - - while (!queue.is_empty()) { - Vertex u(queue.dequeue()); - - for (Vertex frontier : u->d_frontier) { - if (frontier->mark == m_mark_version) - continue; - frontier->mark = m_mark_version; - add_phi_node(frontier.block(), decl); - } - } - } -} - -// ===== rename_variables ===== -namespace { -template -class VariableRenamer : private RecursiveASTVisitor { -public: - VariableRenamer(CreateSSAVariableFunc create, RenameVariableFunc rename) - : m_create(create) - , m_rename(rename) - { - } - - void run(BasicBlockRef block) - { - for (auto& expression : block->m_expressions) - run_in_subtree(expression); - run_in_const_subtree(block->m_continuation); - } - -protected: - RecursionDecision on_entry(Tree tree) override - { - if (tree->is_statement()) - TODO(); - - auto binary_operation = as(tree); - if (binary_operation && binary_operation->m_operation == BinaryOperator::Assignment) { - run_in_subtree(binary_operation->m_right); - if (auto variable = as(binary_operation->m_left); variable) { - m_create(variable->m_name); - m_rename(variable.release_nonnull()); - } else { - run_in_subtree(binary_operation->m_left); - } - return RecursionDecision::Continue; - } - - if (auto variable = as(tree); variable) { - m_rename(variable.release_nonnull()); - return RecursionDecision::Continue; - } - - return RecursionDecision::Recurse; - } - -private: - CreateSSAVariableFunc m_create; - RenameVariableFunc m_rename; -}; -} - -void SSABuildingPass::make_new_ssa_variable_for(NamedVariableDeclarationRef var) -{ - m_undo_vector.append(var); - - u64 id = 0; - if (auto it = m_next_id.find(var); it == m_next_id.end()) - m_next_id.set(var, 1); - else - id = it->value++; - auto ssa_decl = make_ref_counted(id); - - m_function->m_local_ssa_variables.append(ssa_decl); - - if (auto it = m_def_stack.find(var); it == m_def_stack.end()) - m_def_stack.set(var, { ssa_decl }); - else - it->value.append(ssa_decl); -} - -void SSABuildingPass::rename_variable(VariableRef var) -{ - var->m_ssa = m_def_stack.get(var->m_name).value().last(); -} - -void SSABuildingPass::rename_variables(Vertex u, Vertex from) -{ - size_t rollback_point = m_undo_vector.size(); - - for (auto& phi_node : u.block()->m_phi_nodes) { - // TODO: Find the right branch index without iterating through all of the branches. - bool found = false; - for (auto& branch : phi_node.branches) { - if (branch.block->m_index == from) { - rename_variable(branch.value); - found = true; - break; - } - } - VERIFY(found); - } - - if (u->mark == m_mark_version) - return; - u->mark = m_mark_version; - - for (auto& phi_node : u.block()->m_phi_nodes) { - make_new_ssa_variable_for(phi_node.var->m_name); - rename_variable(phi_node.var); - } - - VariableRenamer renamer( - [&](NamedVariableDeclarationRef decl) { - make_new_ssa_variable_for(move(decl)); - }, - [&](VariableRef var) { - rename_variable(move(var)); - }); - renamer.run(u.block()); - - if (auto function_return = as(u.block()->m_continuation); function_return) { - // CFG should have exactly one ControlFlowFunctionReturn. - VERIFY(m_function->m_return_value == nullptr); - m_function->m_return_value = function_return->m_return_value->m_ssa; - } - - for (size_t j : u->outgoing_edges) - rename_variables(j, u); - - while (m_undo_vector.size() > rollback_point) - (void)m_def_stack.get(m_undo_vector.take_last()).value().take_last(); -} - -void SSABuildingPass::rename_variables() -{ - HashMap argument_index_by_name; - for (auto [i, argument] : enumerate(m_function->arguments())) - argument_index_by_name.set(argument.name, i); - m_function->m_ssa_arguments.resize(m_function->arguments().size()); - - for (auto const& [name, var_decl] : m_function->m_local_variables) { - make_new_ssa_variable_for(var_decl); - - if (auto maybe_index = argument_index_by_name.get(name); maybe_index.has_value()) { - size_t index = maybe_index.value(); - m_function->m_ssa_arguments[index] = m_def_stack.get(var_decl).value()[0]; - } - } - make_new_ssa_variable_for(m_function->m_named_return_value); - - ++m_mark_version; - rename_variables(0); - VERIFY(m_function->m_return_value); - m_function->reindex_ssa_variables(); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/SSABuildingPass.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/SSABuildingPass.h deleted file mode 100644 index be644c18d5e..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/SSABuildingPass.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -#include "Compiler/CompilerPass.h" -#include "Compiler/ControlFlowGraph.h" -#include "Compiler/EnableGraphPointers.h" - -namespace JSSpecCompiler { - -// TODO: Add a LOT of unit tests. - -class SSABuildingPass - : public IntraproceduralCompilerPass - , private EnableGraphPointers { -public: - inline static constexpr StringView name = "ssa-building"sv; - - using IntraproceduralCompilerPass::IntraproceduralCompilerPass; - -protected: - void process_function() override; - -private: - friend EnableGraphPointers; - - class Vertex : public VertexBase { - public: - using VertexBase::VertexBase; - - BasicBlockRef block() const { return m_instance->m_order[m_index]; } - }; - - void compute_order(BasicBlockRef u, Vertex parent = invalid_node); - void compute_dominator_tree(); - - template - Vector unique(Args const&... args); - void compute_dtree_tin_tout(Vertex u); - bool is_strictly_dominating(Vertex u, Vertex v); - void compute_dominance_frontiers(); - - void add_phi_node(BasicBlockRef block, NamedVariableDeclarationRef decl); - void place_phi_nodes(); - - void make_new_ssa_variable_for(NamedVariableDeclarationRef var); - void rename_variable(VariableRef var); - void rename_variables(Vertex u, Vertex from = invalid_node); - void rename_variables(); - - struct NodeData { - Vector incoming_edges; - Vector outgoing_edges; - - Vector buckets; - - bool is_used = false; - Vertex parent; - Vertex semi_dominator; - Vertex immediate_dominator; - - Vector dtree_children; - u64 tin, tout; - - Vector d_frontier; - - HashMap phi_nodes; - - u64 mark = 0; - }; - - u64 m_dtree_timer; - Vector m_nodes; - Vector> m_order; - - u64 m_mark_version; - - HashMap> m_def_stack; - HashMap m_next_id; - Vector m_undo_vector; - - ControlFlowGraph* m_graph; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/StronglyConnectedComponents.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/StronglyConnectedComponents.h deleted file mode 100644 index f0c6ac2fe6b..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/StronglyConnectedComponents.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -#include "Compiler/EnableGraphPointers.h" - -namespace JSSpecCompiler { - -namespace Detail { -template -class StronglyConnectedComponents - : private EnableGraphPointers> { - using Self = StronglyConnectedComponents; - using Vertex = typename EnableGraphPointers::Vertex; - -public: - StronglyConnectedComponents(Vector const& graph) - : m_graph(graph) - { - } - - Vector> find() - { - Vector> result; - size_t n = m_graph.size(); - Self::with_graph(n, [&] { - for (size_t i = 0; i < m_graph.size(); ++i) - find_order(i); - for (size_t i = n; i--;) { - if (!m_order[i]->is_processed) { - result.empend(); - find_component(GraphVertex(m_order[i]), result.last()); - } - } - }); - return result; - } - -private: - friend EnableGraphPointers; - - void find_order(Vertex u) - { - if (u->is_visited) - return; - u->is_visited = true; - - for (auto v : GraphVertex(u)->incoming_edges) - find_order(Vertex(v)); - m_order.append(u); - } - - void find_component(GraphVertex u, Vector& current_scc) - { - current_scc.empend(u); - Vertex(u)->is_processed = true; - for (auto v : u->outgoing_edges) - if (!Vertex(v)->is_processed) - find_component(v, current_scc); - } - - struct NodeData { - bool is_visited = false; - bool is_processed = false; - }; - - Vector const& m_graph; - Vector m_nodes; - Vector m_order; -}; -} - -template -auto find_strongly_connected_components(Vector const& graph) -{ - using Vertex = RemoveCVReference; - return Detail::StronglyConnectedComponents(graph).find(); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/DiagnosticEngine.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/DiagnosticEngine.cpp deleted file mode 100644 index 0c65852b8a7..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/DiagnosticEngine.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "DiagnosticEngine.h" - -namespace JSSpecCompiler { - -bool DiagnosticEngine::has_fatal_errors() const -{ - return m_has_fatal_errors; -} - -void DiagnosticEngine::print_diagnostics() -{ - auto use_color = isatty(STDERR_FILENO) ? UseColor::Yes : UseColor::No; - - StringBuilder builder; - for (auto const& diagnostic : m_diagnostics) - diagnostic.format_into(builder, use_color); - - out(stderr, "{}", builder.string_view()); -} - -void DiagnosticEngine::Diagnostic::format_into(StringBuilder& builder, UseColor use_color) const -{ - if (!location.filename.is_empty()) - builder.appendff("{}:{}:{}: ", location.filename, location.line + 1, location.column + 1); - - static constexpr Array colored_diagnostic_levels = { { - "\e[1mnote\e[0m"sv, - "\e[1;33mwarning\e[0m"sv, - "\e[1;31merror\e[0m"sv, - "\e[1;31mfatal error\e[0m"sv, - } }; - static constexpr Array diagnostic_levels = { { - "note"sv, - "warning"sv, - "error"sv, - "fatal error"sv, - } }; - - auto diagnostic_level_text = (use_color == UseColor::Yes ? colored_diagnostic_levels : diagnostic_levels); - builder.appendff("{}: ", diagnostic_level_text[to_underlying(level)]); - - if (auto logical_location = location.logical_location) { - if (!logical_location->section.is_empty()) { - builder.appendff("in {}", logical_location->section); - if (!logical_location->step.is_empty()) - builder.appendff(" step {}", logical_location->step); - builder.appendff(": "); - } - } - - builder.append(message); - builder.append('\n'); - - for (auto const& note : notes) - note.format_into(builder, use_color); -} - -void DiagnosticEngine::add_diagnostic(Diagnostic&& diagnostic) -{ - if (diagnostic.level == DiagnosticLevel::FatalError) - m_has_fatal_errors = true; - if (diagnostic.level != DiagnosticLevel::Note) - m_diagnostics.append(move(diagnostic)); - else - m_diagnostics.last().notes.append(move(diagnostic)); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/DiagnosticEngine.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/DiagnosticEngine.h deleted file mode 100644 index 3b6f2b29c6b..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/DiagnosticEngine.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace JSSpecCompiler { - -struct LogicalLocation : RefCounted { - String section; - String step; -}; - -struct Location { - StringView filename; - size_t line = 0; - size_t column = 0; - RefPtr logical_location; - - static Location global_scope() { return {}; } -}; - -class DiagnosticEngine { - AK_MAKE_NONCOPYABLE(DiagnosticEngine); - AK_MAKE_NONMOVABLE(DiagnosticEngine); - -public: - DiagnosticEngine() = default; - -#define DEFINE_DIAGNOSTIC_FUNCTION(name_, level_) \ - template \ - void name_(Location const& location, AK::CheckedFormatString&& fmtstr, Parameters const&... parameters) \ - { \ - add_diagnostic({ \ - .location = location, \ - .level = DiagnosticLevel::level_, \ - .message = MUST(String::formatted(move(fmtstr), parameters...)), \ - }); \ - } - - DEFINE_DIAGNOSTIC_FUNCTION(note, Note) - DEFINE_DIAGNOSTIC_FUNCTION(warn, Warning) - DEFINE_DIAGNOSTIC_FUNCTION(error, Error) - DEFINE_DIAGNOSTIC_FUNCTION(fatal_error, FatalError) - -#undef DEFINE_DIAGNOSTIC_FUNCTION - - bool has_fatal_errors() const; - void print_diagnostics(); - -private: - enum class DiagnosticLevel { - Note, - Warning, - Error, - FatalError, - }; - - enum class UseColor { - No, - Yes, - }; - - struct Diagnostic { - Location location; - DiagnosticLevel level; - String message; - - Vector notes; - - bool operator<(Diagnostic const& other) const; - - void format_into(StringBuilder& builder, UseColor) const; - }; - - void add_diagnostic(Diagnostic&& diagnostic); - - Vector m_diagnostics; - bool m_has_fatal_errors = false; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Forward.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Forward.h deleted file mode 100644 index 13b1fe6b9bd..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Forward.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace JSSpecCompiler { - -// AST/AST.h -class NodeSubtreePointer; -class VariableDeclaration; -using VariableDeclarationRef = NonnullRefPtr; -class NamedVariableDeclaration; -using NamedVariableDeclarationRef = NonnullRefPtr; -class SSAVariableDeclaration; -using SSAVariableDeclarationRef = RefPtr; - -class Node; -using NullableTree = RefPtr; -using Tree = NonnullRefPtr; -class Statement; -class Expression; -class ErrorNode; -class ControlFlowOperator; - -class ControlFlowFunctionReturn; -class ControlFlowJump; -class ControlFlowBranch; -class MathematicalConstant; -class StringLiteral; -class BinaryOperation; -class UnaryOperation; -class IsOneOfOperation; -class UnresolvedReference; -class ReturnNode; -class AssertExpression; -class IfBranch; -class ElseIfBranch; -class IfElseIfChain; -class TreeList; -class RecordDirectListInitialization; -class FunctionCall; -class SlotName; -class Enumerator; -using EnumeratorRef = NonnullRefPtr; -class Variable; -using VariableRef = NonnullRefPtr; -class FunctionPointer; -using FunctionPointerRef = NonnullRefPtr; - -// Compiler/ControlFlowGraph.h -class BasicBlock; -using BasicBlockRef = BasicBlock*; -class ControlFlowGraph; - -// Compiler/GenericASTPass.h -class RecursiveASTVisitor; - -// Parser/SpecParser.h -class SpecificationParsingContext; -class AlgorithmStep; -class AlgorithmStepList; -class Algorithm; -class SpecificationFunction; -class SpecificationClause; -class Specification; - -namespace Runtime { -class Cell; -class Object; -class ObjectType; -class Realm; -} - -// DiagnosticEngine.h -struct LogicalLocation; -struct Location; -class DiagnosticEngine; - -// Function.h -class TranslationUnit; -using TranslationUnitRef = TranslationUnit*; -class FunctionDeclaration; -using FunctionDeclarationRef = FunctionDeclaration*; -class FunctionDefinition; -using FunctionDefinitionRef = FunctionDefinition*; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.cpp deleted file mode 100644 index b5618358f37..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Function.h" -#include "AST/AST.h" -#include "Compiler/ControlFlowGraph.h" -#include "Runtime/Realm.h" - -namespace JSSpecCompiler { - -TranslationUnit::TranslationUnit(StringView filename) - : m_filename(filename) - , m_realm(make(m_diagnostic_engine)) -{ -} - -TranslationUnit::~TranslationUnit() = default; - -void TranslationUnit::adopt_declaration(NonnullRefPtr&& declaration) -{ - if (auto decl_name = declaration->declaration(); decl_name.has()) - m_abstract_operation_index.set(decl_name.get().name, declaration.ptr()); - m_declarations_owner.append(move(declaration)); -} - -void TranslationUnit::adopt_function(NonnullRefPtr&& definition) -{ - m_functions_to_compile.append(definition); - adopt_declaration(definition); -} - -FunctionDeclarationRef TranslationUnit::find_abstract_operation_by_name(StringView name) const -{ - auto it = m_abstract_operation_index.find(name); - if (it == m_abstract_operation_index.end()) - return nullptr; - return it->value; -} - -EnumeratorRef TranslationUnit::get_node_for_enumerator_value(StringView value) -{ - if (auto it = m_enumerator_nodes.find(value); it != m_enumerator_nodes.end()) - return it->value; - - auto enumerator = NonnullRefPtr(NonnullRefPtr::Adopt, *new Enumerator { {}, value }); - m_enumerator_nodes.set(value, enumerator); - return enumerator; -} - -FunctionDeclaration::FunctionDeclaration(Declaration&& declaration, Location location) - : m_declaration(move(declaration)) - , m_location(location) -{ -} - -String FunctionDeclaration::name() const -{ - return m_declaration.visit( - [&](AbstractOperationDeclaration const& abstract_operation) { - return abstract_operation.name.to_string(); - }, - [&](MethodDeclaration const& method) { - return MUST(String::formatted("%{}%", method.name.to_string())); - }, - [&](AccessorDeclaration const& accessor) { - return MUST(String::formatted("%get {}%", accessor.name.to_string())); - }); -} - -ReadonlySpan FunctionDeclaration::arguments() const -{ - return m_declaration.visit( - [&](AccessorDeclaration const&) { - return ReadonlySpan {}; - }, - [&](auto const& declaration) { - return declaration.arguments.span(); - }); -} - -FunctionDefinition::FunctionDefinition(Declaration&& declaration, Location location, Tree ast) - : FunctionDeclaration(move(declaration), location) - , m_ast(move(ast)) - , m_named_return_value(make_ref_counted("$return"sv)) -{ -} - -void FunctionDefinition::reindex_ssa_variables() -{ - size_t index = 0; - for (auto const& var : m_local_ssa_variables) - var->m_index = index++; -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.h deleted file mode 100644 index 28bca950798..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include "DiagnosticEngine.h" -#include "Forward.h" - -namespace JSSpecCompiler { - -class TranslationUnit { -public: - TranslationUnit(StringView filename); - ~TranslationUnit(); - - void adopt_declaration(NonnullRefPtr&& declaration); - void adopt_function(NonnullRefPtr&& definition); - FunctionDeclarationRef find_abstract_operation_by_name(StringView name) const; - - StringView filename() const { return m_filename; } - DiagnosticEngine& diag() { return m_diagnostic_engine; } - Vector functions_to_compile() const { return m_functions_to_compile; } - - EnumeratorRef get_node_for_enumerator_value(StringView value); - - Runtime::Realm* realm() const { return m_realm; } - -private: - StringView m_filename; - DiagnosticEngine m_diagnostic_engine; - Vector m_functions_to_compile; - Vector> m_declarations_owner; - HashMap m_abstract_operation_index; - HashMap m_enumerator_nodes; - - NonnullOwnPtr m_realm; -}; - -struct FunctionArgument { - StringView name; - size_t optional_arguments_group; -}; - -class QualifiedName { -public: - QualifiedName() { } - - QualifiedName(ReadonlySpan parsed_name) - { - m_components.ensure_capacity(parsed_name.size()); - for (auto component : parsed_name) - m_components.unchecked_append(MUST(FlyString::from_utf8(component))); - } - - QualifiedName(ReadonlySpan parsed_name) - { - m_components.ensure_capacity(parsed_name.size()); - for (auto component : parsed_name) - m_components.unchecked_append(component); - } - - String to_string() const - { - return MUST(String::join("."sv, m_components)); - } - - Vector const& components() const - { - return m_components; - } - - FlyString last_component() const - { - return m_components.last(); - } - - ReadonlySpan without_last_component() const - { - return components().span().slice(0, components().size() - 1); - } - - QualifiedName slice(size_t start, size_t length) const - { - return { m_components.span().slice(start, length) }; - } - - QualifiedName with_appended(FlyString component) const - { - auto new_components = m_components; - new_components.append(component); - return { new_components }; - } - -private: - Vector m_components; -}; - -struct AbstractOperationDeclaration { - FlyString name; - Vector arguments; -}; - -struct AccessorDeclaration { - QualifiedName name; -}; - -struct MethodDeclaration { - QualifiedName name; - Vector arguments; -}; - -using Declaration = Variant; - -class FunctionDeclaration : public RefCounted { -public: - FunctionDeclaration(Declaration&& declaration, Location location); - - virtual ~FunctionDeclaration() = default; - - Declaration const& declaration() const { return m_declaration; } - Location location() const { return m_location; } - String name() const; - ReadonlySpan arguments() const; - -private: - Declaration m_declaration; - Location m_location; -}; - -class FunctionDefinition : public FunctionDeclaration { -public: - FunctionDefinition(Declaration&& declaration, Location location, Tree ast); - - void reindex_ssa_variables(); - - Tree m_ast; - - // Populates during reference resolving - // NOTE: The hash map here is ordered since we do not want random hash changes to break our test - // expectations (looking at you, SipHash). - OrderedHashMap m_local_variables; - - // Fields populate during CFG building - NamedVariableDeclarationRef m_named_return_value; - RefPtr m_cfg; - - // Fields populate during SSA building - Vector m_ssa_arguments; - SSAVariableDeclarationRef m_return_value; - Vector m_local_ssa_variables; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Algorithm.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Algorithm.cpp deleted file mode 100644 index fff0a7a9f17..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Algorithm.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2023-2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Parser/Lexer.h" -#include "Parser/SpecificationParsing.h" -#include "Parser/XMLUtils.h" - -namespace JSSpecCompiler { - -Optional Algorithm::create(SpecificationParsingContext& ctx, XML::Node const* element) -{ - VERIFY(element->as_element().name == tag_emu_alg); - - Vector steps_list; - for (auto const& child : element->as_element().children) { - child->content.visit( - [&](XML::Node::Element const& element) { - if (element.name == tag_ol) { - steps_list.append(child); - return; - } - - ctx.diag().error(ctx.location_from_xml_offset(child->offset), - "<{}> should not be a child of "sv, element.name); - }, - [&](XML::Node::Text const&) { - if (!contains_empty_text(child)) { - ctx.diag().error(ctx.location_from_xml_offset(child->offset), - "non-empty text node should not be a child of "); - } - }, - [&](auto const&) {}); - } - - if (steps_list.size() != 1) { - ctx.diag().error(ctx.location_from_xml_offset(element->offset), - " should have exactly one
    child"sv); - return {}; - } - - auto steps_creation_result = AlgorithmStepList::create(ctx, steps_list[0]); - if (steps_creation_result.has_value()) { - Algorithm algorithm; - algorithm.m_tree = steps_creation_result.release_value().tree(); - return algorithm; - } - return {}; -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/AlgorithmStep.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/AlgorithmStep.cpp deleted file mode 100644 index 4a4590c0317..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/AlgorithmStep.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2023-2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Parser/Lexer.h" -#include "Parser/SpecificationParsing.h" - -namespace JSSpecCompiler { - -Optional AlgorithmStep::create(SpecificationParsingContext& ctx, XML::Node const* element) -{ - VERIFY(element->as_element().name == tag_li); - - auto [maybe_tokens, substeps] = tokenize_step(ctx, element); - - AlgorithmStep result(ctx); - result.m_node = element; - - if (substeps) { - // FIXME: Remove this once macOS Lagom CI updates to Clang >= 16. - auto substeps_copy = substeps; - - auto step_list = ctx.with_new_step_list_nesting_level([&] { - return AlgorithmStepList::create(ctx, substeps_copy); - }); - result.m_substeps = step_list.has_value() ? step_list->tree() : error_tree; - } - - if (!maybe_tokens.has_value()) - return {}; - result.m_tokens = maybe_tokens.release_value(); - - if (!result.parse()) - return {}; - return result; -} - -bool AlgorithmStep::parse() -{ - TextParser parser(m_ctx, m_tokens, m_node); - - TextParseErrorOr parse_result = TextParseError {}; - if (m_substeps) - parse_result = parser.parse_step_with_substeps(RefPtr(m_substeps).release_nonnull()); - else - parse_result = parser.parse_step_without_substeps(); - - if (parse_result.is_error()) { - auto [location, message] = parser.get_diagnostic(); - m_ctx.diag().error(location, "{}", message); - return false; - } else { - m_expression = parse_result.release_value(); - return true; - } -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/AlgorithmStepList.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/AlgorithmStepList.cpp deleted file mode 100644 index 59f8c5b2841..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/AlgorithmStepList.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2023-2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Parser/Lexer.h" -#include "Parser/SpecificationParsing.h" -#include "Parser/XMLUtils.h" - -namespace JSSpecCompiler { - -Optional AlgorithmStepList::create(SpecificationParsingContext& ctx, XML::Node const* element) -{ - VERIFY(element->as_element().name == tag_ol); - - AlgorithmStepList result; - - Vector step_expressions; - bool all_steps_parsed = true; - int step_number = 0; - - auto const& parent_scope = ctx.current_logical_scope(); - - for (auto const& child : element->as_element().children) { - child->content.visit( - [&](XML::Node::Element const& element) { - if (element.name == tag_li) { - auto step_creation_result = ctx.with_new_logical_scope([&] { - update_logical_scope_for_step(ctx, parent_scope, step_number); - return AlgorithmStep::create(ctx, child); - }); - if (!step_creation_result.has_value()) { - all_steps_parsed = false; - } else { - if (auto expression = step_creation_result.release_value().tree()) - step_expressions.append(expression.release_nonnull()); - } - ++step_number; - return; - } - - ctx.diag().error(ctx.location_from_xml_offset(child->offset), - "<{}> should not be a child of algorithm step list"sv, element.name); - }, - [&](XML::Node::Text const&) { - if (!contains_empty_text(child)) { - ctx.diag().error(ctx.location_from_xml_offset(child->offset), - "non-empty text node should not be a child of algorithm step list"); - } - }, - [&](auto const&) {}); - } - - if (!all_steps_parsed) - return {}; - - result.m_expression = make_ref_counted(move(step_expressions)); - return result; -} - -void AlgorithmStepList::update_logical_scope_for_step(SpecificationParsingContext& ctx, LogicalLocation const& parent_scope, int step_number) -{ - int nesting_level = ctx.step_list_nesting_level(); - String list_step_number; - - if (nesting_level == 0 || nesting_level == 3) { - list_step_number = MUST(String::formatted("{}", step_number + 1)); - } else if (nesting_level == 1 || nesting_level == 4) { - if (step_number < 26) - list_step_number = String::from_code_point('a' + step_number); - else - list_step_number = MUST(String::formatted("{}", step_number + 1)); - } else { - list_step_number = MUST(String::from_byte_string(ByteString::roman_number_from(step_number + 1).to_lowercase())); - } - - auto& scope = ctx.current_logical_scope(); - scope.section = parent_scope.section; - - if (parent_scope.step.is_empty()) - scope.step = list_step_number; - else - scope.step = MUST(String::formatted("{}.{}", parent_scope.step, list_step_number)); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/CppASTConverter.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/CppASTConverter.cpp deleted file mode 100644 index ad88947ec14..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/CppASTConverter.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -#include "Function.h" -#include "Parser/CppASTConverter.h" -#include "Parser/SpecificationParsing.h" - -namespace JSSpecCompiler { - -NonnullRefPtr CppASTConverter::convert() -{ - StringView name = m_function->name()->full_name(); - - Vector toplevel_statements; - for (auto const& statement : m_function->definition()->statements()) { - auto maybe_tree = as_nullable_tree(statement); - if (maybe_tree) - toplevel_statements.append(maybe_tree.release_nonnull()); - } - auto tree = make_ref_counted(move(toplevel_statements)); - - Vector arguments; - for (auto const& parameter : m_function->parameters()) - arguments.append({ .name = parameter->full_name() }); - - return make_ref_counted( - AbstractOperationDeclaration { - .name = MUST(FlyString::from_utf8(name)), - .arguments = move(arguments), - }, - Location {}, - tree); -} - -template<> -NullableTree CppASTConverter::convert_node(Cpp::VariableDeclaration const& variable_declaration) -{ - static Tree variable_declaration_present_error - = make_ref_counted("Encountered variable declaration with initial value"sv); - - if (variable_declaration.initial_value() != nullptr) - return variable_declaration_present_error; - return nullptr; -} - -template<> -NullableTree CppASTConverter::convert_node(Cpp::ReturnStatement const& return_statement) -{ - return make_ref_counted(as_tree(return_statement.value())); -} - -template<> -NullableTree CppASTConverter::convert_node(Cpp::FunctionCall const& function_call) -{ - Vector arguments; - for (auto const& argument : function_call.arguments()) - arguments.append(as_tree(argument)); - - return make_ref_counted(as_tree(function_call.callee()), move(arguments)); -} - -template<> -NullableTree CppASTConverter::convert_node(Cpp::Name const& name) -{ - return make_ref_counted(name.full_name()); -} - -template<> -NullableTree CppASTConverter::convert_node(Cpp::IfStatement const& if_statement) -{ - // NOTE: This is so complicated since we probably want to test IfBranchMergingPass, which - // expects standalone `IfBranch` and `ElseIfBranch` nodes. - - Vector trees; - Cpp::IfStatement const* current = &if_statement; - - while (true) { - auto predicate = as_tree(current->predicate()); - auto then_branch = as_possibly_empty_tree(current->then_statement()); - - if (trees.is_empty()) - trees.append(make_ref_counted(predicate, then_branch)); - else - trees.append(make_ref_counted(predicate, then_branch)); - - auto else_statement = dynamic_cast(current->else_statement()); - if (else_statement) - current = else_statement; - else - break; - } - - auto else_statement = current->else_statement(); - if (else_statement) - trees.append(make_ref_counted( - nullptr, as_possibly_empty_tree(else_statement))); - - return make_ref_counted(move(trees)); -} - -template<> -NullableTree CppASTConverter::convert_node(Cpp::BlockStatement const& block) -{ - Vector statements; - for (auto const& statement : block.statements()) { - auto maybe_tree = as_nullable_tree(statement); - if (maybe_tree) - statements.append(maybe_tree.release_nonnull()); - } - return make_ref_counted(move(statements)); -} - -template<> -NullableTree CppASTConverter::convert_node(Cpp::AssignmentExpression const& assignment) -{ - // NOTE: Later stages of the compilation process basically treat `BinaryOperator::Declaration` - // the same as `BinaryOperator::Assignment`, so variable shadowing is impossible. The only - // difference in their semantics is that "declarations" define names of local variables. - // Since we are effectively ignoring actual C++ variable declarations, we need to define - // locals somewhere else. Using "declarations" instead of "assignments" here does this job - // cleanly. - return make_ref_counted( - BinaryOperator::Declaration, as_tree(assignment.lhs()), as_tree(assignment.rhs())); -} - -template<> -NullableTree CppASTConverter::convert_node(Cpp::NumericLiteral const& literal) -{ - // TODO: Numerical literals are not limited to i64. - VERIFY(literal.value().to_number().has_value()); - return make_ref_counted(MUST(Crypto::BigFraction::from_string(literal.value()))); -} - -template<> -NullableTree CppASTConverter::convert_node(Cpp::StringLiteral const& literal) -{ - return make_ref_counted(literal.value()); -} - -template<> -NullableTree CppASTConverter::convert_node(Cpp::BinaryExpression const& expression) -{ - static constexpr auto operator_translation = []() consteval { - Array table; -#define ASSIGN_TRANSLATION(cpp_name, our_name) \ - table[to_underlying(Cpp::BinaryOp::cpp_name)] = BinaryOperator::our_name - ASSIGN_TRANSLATION(Addition, Plus); - ASSIGN_TRANSLATION(Subtraction, Minus); - ASSIGN_TRANSLATION(Multiplication, Multiplication); - ASSIGN_TRANSLATION(Division, Division); - ASSIGN_TRANSLATION(Modulo, Invalid); - ASSIGN_TRANSLATION(GreaterThan, CompareGreater); - ASSIGN_TRANSLATION(GreaterThanEquals, Invalid); - ASSIGN_TRANSLATION(LessThan, CompareLess); - ASSIGN_TRANSLATION(LessThanEquals, Invalid); - ASSIGN_TRANSLATION(BitwiseAnd, Invalid); - ASSIGN_TRANSLATION(BitwiseOr, Invalid); - ASSIGN_TRANSLATION(BitwiseXor, Invalid); - ASSIGN_TRANSLATION(LeftShift, Invalid); - ASSIGN_TRANSLATION(RightShift, Invalid); - ASSIGN_TRANSLATION(EqualsEquals, CompareEqual); - ASSIGN_TRANSLATION(NotEqual, CompareNotEqual); - ASSIGN_TRANSLATION(LogicalOr, Invalid); - ASSIGN_TRANSLATION(LogicalAnd, Invalid); - ASSIGN_TRANSLATION(Arrow, Invalid); -#undef ASSIGN_TRANSLATION - return table; - }(); - - auto translated_operator = operator_translation[to_underlying(expression.op())]; - // TODO: Print nicer error. - VERIFY(translated_operator != BinaryOperator::Invalid); - return make_ref_counted(translated_operator, as_tree(expression.lhs()), as_tree(expression.rhs())); -} - -NullableTree CppASTConverter::as_nullable_tree(Cpp::Statement const* statement) -{ - static Tree unknown_ast_node_error - = make_ref_counted("Encountered unknown C++ AST node"sv); - - Optional result; - - auto dispatch_convert_if_one_of = [&] { - (([&] { - if (result.has_value()) - return; - auto casted_ptr = dynamic_cast(statement); - if (casted_ptr != nullptr) - result = convert_node(*casted_ptr); - }).template operator()(), - ...); - }; - - dispatch_convert_if_one_of.operator()< - Cpp::VariableDeclaration, - Cpp::ReturnStatement, - Cpp::FunctionCall, - Cpp::Name, - Cpp::IfStatement, - Cpp::BlockStatement, - Cpp::AssignmentExpression, - Cpp::NumericLiteral, - Cpp::StringLiteral, - Cpp::BinaryExpression>(); - - if (result.has_value()) - return *result; - return unknown_ast_node_error; -} - -Tree CppASTConverter::as_tree(Cpp::Statement const* statement) -{ - static Tree empty_tree_error - = make_ref_counted("AST conversion unexpectedly produced empty tree"sv); - - auto result = as_nullable_tree(statement); - if (result) - return result.release_nonnull(); - return empty_tree_error; -} - -Tree CppASTConverter::as_possibly_empty_tree(Cpp::Statement const* statement) -{ - auto result = as_nullable_tree(statement); - if (result) - return result.release_nonnull(); - return make_ref_counted(Vector {}); -} - -CppParsingStep::CppParsingStep() - : CompilationStep("parser"sv) -{ -} - -CppParsingStep::~CppParsingStep() = default; - -void CppParsingStep::run(TranslationUnitRef translation_unit) -{ - auto filename = translation_unit->filename(); - - auto file = Core::File::open_file_or_standard_stream(filename, Core::File::OpenMode::Read).release_value_but_fixme_should_propagate_errors(); - m_input = file->read_until_eof().release_value_but_fixme_should_propagate_errors(); - - Cpp::Preprocessor preprocessor { filename, m_input }; - m_parser = adopt_own_if_nonnull(new Cpp::Parser { preprocessor.process_and_lex(), filename }); - - auto cpp_translation_unit = m_parser->parse(); - VERIFY(m_parser->errors().is_empty()); - - for (auto const& declaration : cpp_translation_unit->declarations()) { - if (declaration->is_function()) { - auto const* cpp_function = AK::verify_cast(declaration.ptr()); - translation_unit->adopt_function(CppASTConverter(cpp_function).convert()); - } - } -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/CppASTConverter.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/CppASTConverter.h deleted file mode 100644 index 65aea91ef2f..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/CppASTConverter.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -#include "CompilationPipeline.h" - -namespace JSSpecCompiler { - -class CppASTConverter { -public: - CppASTConverter(RefPtr const& function) - : m_function(function) - { - } - - NonnullRefPtr convert(); - -private: - template - NullableTree convert_node(T const&); - NullableTree as_nullable_tree(Cpp::Statement const* statement); - Tree as_tree(Cpp::Statement const* statement); - Tree as_possibly_empty_tree(Cpp::Statement const* statement); - - RefPtr m_function; -}; - -class CppParsingStep : public CompilationStep { -public: - CppParsingStep(); - ~CppParsingStep(); - - void run(TranslationUnitRef translation_unit) override; - -private: - OwnPtr m_parser; - ByteBuffer m_input; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Lexer.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Lexer.cpp deleted file mode 100644 index afd27449f45..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Lexer.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -#include "Parser/Lexer.h" -#include "Parser/SpecificationParsing.h" -#include "Parser/XMLUtils.h" - -namespace JSSpecCompiler { - -namespace { -Optional consume_number(LineTrackingLexer& lexer, Location& location) -{ - u64 start = lexer.tell(); - - if (lexer.next_is('-')) - lexer.consume(1); - - if (!lexer.next_is(is_ascii_digit)) { - lexer.retreat(lexer.tell() - start); - return {}; - } - - lexer.consume_while(is_ascii_digit); - - if (lexer.next_is('.')) { - lexer.consume(1); - if (lexer.consume_while(is_ascii_digit).length() == 0) - lexer.retreat(1); - } - - auto length = lexer.tell() - start; - lexer.retreat(length); - return { Token { TokenType::Number, lexer.consume(length), move(location) } }; -} - -bool can_end_word_token(char c) -{ - return is_ascii_space(c) || ".,"sv.contains(c); -} - -void tokenize_string(SpecificationParsingContext& ctx, XML::Node const* node, StringView view, Vector& tokens) -{ - static constexpr struct { - StringView text_to_match; - TokenType token_type; - } choices[] = { - { "-"sv, TokenType::AmbiguousMinus }, - { "}"sv, TokenType::BraceClose }, - { "{"sv, TokenType::BraceOpen }, - { ":"sv, TokenType::Colon }, - { ","sv, TokenType::Comma }, - { "/"sv, TokenType::Division }, - { ". "sv, TokenType::Dot }, - { ".\n"sv, TokenType::Dot }, - { "="sv, TokenType::Equals }, - { "is equal to"sv, TokenType::Equals }, - { "!"sv, TokenType::ExclamationMark }, - { ">"sv, TokenType::Greater }, - { "is"sv, TokenType::Is }, - { "<"sv, TokenType::Less }, - { "»"sv, TokenType::ListEnd }, - { "«"sv, TokenType::ListStart }, - { "."sv, TokenType::MemberAccess }, - { "×"sv, TokenType::Multiplication }, - { "is not equal to"sv, TokenType::NotEquals }, - { "≠"sv, TokenType::NotEquals }, - { ")"sv, TokenType::ParenClose }, - { "("sv, TokenType::ParenOpen }, - { "+"sv, TokenType::Plus }, - { "?"sv, TokenType::QuestionMark }, - { "]"sv, TokenType::SquareBracketClose }, - { "["sv, TokenType::SquareBracketOpen }, - { "NewTarget"sv, TokenType::WellKnownValue }, - }; - - LineTrackingLexer lexer(view, node->offset); - - while (!lexer.is_eof()) { - lexer.ignore_while(is_ascii_space); - - // FIXME: This is incorrect since we count text offset after XML reference resolution. To do - // this properly, we need support from XML::Parser. - Location token_location = ctx.location_from_xml_offset(lexer.position_for(lexer.tell())); - - if (auto result = consume_number(lexer, token_location); result.has_value()) { - tokens.append(result.release_value()); - continue; - } - - bool matched = false; - for (auto const& [text_to_match, token_type] : choices) { - if (lexer.consume_specific(text_to_match)) { - tokens.append({ token_type, text_to_match, move(token_location) }); - matched = true; - break; - } - } - if (matched) - continue; - - StringView word = lexer.consume_until(can_end_word_token); - if (word.length()) - tokens.append({ TokenType::Word, word, move(token_location) }); - } -} - -enum class TreeType { - AlgorithmStep, - NestedExpression, - Header, -}; - -struct TokenizerState { - Vector tokens; - XML::Node const* substeps = nullptr; - bool has_errors = false; -}; - -void tokenize_tree(SpecificationParsingContext& ctx, TokenizerState& state, XML::Node const* node, TreeType tree_type) -{ - // FIXME: Use structured binding once macOS Lagom CI updates to Clang >= 16. - auto& tokens = state.tokens; - auto& substeps = state.substeps; - auto& has_errors = state.has_errors; - - for (auto const& child : node->as_element().children) { - if (has_errors) - break; - - child->content.visit( - [&](XML::Node::Element const& element) -> void { - Location child_location = ctx.location_from_xml_offset(child->offset); - auto report_error = [&](AK::CheckedFormatString&& fmt, Parameters const&... parameters) { - ctx.diag().error(child_location, move(fmt), parameters...); - has_errors = true; - }; - - if (substeps) { - report_error("substeps list must be the last child of algorithm step"); - return; - } - - if (element.name == tag_var) { - auto variable_name = get_text_contents(child); - if (!variable_name.has_value()) - report_error("malformed subtree, expected single text child node"); - - tokens.append({ TokenType::Identifier, variable_name.value_or(""sv), move(child_location) }); - return; - } - - if (element.name == tag_emu_val) { - auto maybe_contents = get_text_contents(child); - if (!maybe_contents.has_value()) - report_error("malformed subtree, expected single text child node"); - - auto contents = maybe_contents.value_or(""sv); - - if (contents.length() >= 2 && contents.starts_with('"') && contents.ends_with('"')) - tokens.append({ TokenType::String, contents.substring_view(1, contents.length() - 2), move(child_location) }); - else if (contents.is_one_of("undefined", "null", "this", "true", "false")) - tokens.append({ TokenType::WellKnownValue, contents, move(child_location) }); - else - tokens.append({ TokenType::Identifier, contents, move(child_location) }); - return; - } - - if (element.name == tag_emu_xref) { - auto identifier = get_single_child_with_tag(child, "a"sv).map([](XML::Node const* node) { - return get_text_contents(node).value_or(""sv); - }); - if (!identifier.has_value() || identifier.value().is_empty()) - report_error("malformed subtree, expected with nested single text node"); - - tokens.append({ TokenType::Identifier, identifier.value_or(""sv), move(child_location) }); - return; - } - - if (element.name == tag_sup) { - tokens.append({ TokenType::Superscript, ""sv, move(child_location) }); - tokens.append({ TokenType::ParenOpen, ""sv, move(child_location) }); - tokenize_tree(ctx, state, child, TreeType::NestedExpression); - tokens.append({ TokenType::ParenClose, ""sv, move(child_location) }); - return; - } - - if (element.name == tag_emu_const) { - auto maybe_contents = get_text_contents(child); - if (!maybe_contents.has_value()) - report_error("malformed subtree, expected single text child node"); - - tokens.append({ TokenType::Enumerator, maybe_contents.value_or(""sv), move(child_location) }); - return; - } - - if (tree_type == TreeType::Header && element.name == tag_span) { - auto element_class = get_attribute_by_name(child, attribute_class); - if (element_class != class_secnum) - report_error("expected to have class='secnum' attribute"); - - auto section_number = get_text_contents(child); - if (!section_number.has_value()) - report_error("malformed section number span subtree, expected single text child node"); - - tokens.append({ TokenType::SectionNumber, section_number.value_or(""sv), move(child_location) }); - return; - } - - if (tree_type == TreeType::AlgorithmStep && element.name == tag_ol) { - substeps = child; - return; - } - - report_error("<{}> should not be a child of algorithm step", element.name); - }, - [&](XML::Node::Text const& text) { - auto view = text.builder.string_view(); - if (substeps != nullptr && !contains_empty_text(child)) { - ctx.diag().error(ctx.location_from_xml_offset(child->offset), - "substeps list must be the last child of algorithm step"); - } else { - tokenize_string(ctx, child, view, tokens); - } - }, - [&](auto const&) {}); - } - - if (tree_type == TreeType::AlgorithmStep && tokens.size() && tokens.last().type == TokenType::MemberAccess) - tokens.last().type = TokenType::Dot; -} -} - -StepTokenizationResult tokenize_step(SpecificationParsingContext& ctx, XML::Node const* node) -{ - TokenizerState state; - tokenize_tree(ctx, state, node, TreeType::AlgorithmStep); - return { - .tokens = state.has_errors ? OptionalNone {} : Optional> { move(state.tokens) }, - .substeps = state.substeps, - }; -} - -Optional> tokenize_header(SpecificationParsingContext& ctx, XML::Node const* node) -{ - TokenizerState state; - tokenize_tree(ctx, state, node, TreeType::Header); - return state.has_errors ? OptionalNone {} : Optional> { state.tokens }; -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Lexer.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Lexer.h deleted file mode 100644 index 1b6ba0dd363..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Lexer.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Parser/Token.h" - -namespace JSSpecCompiler { - -inline constexpr StringView tag_emu_alg = "emu-alg"sv; -inline constexpr StringView tag_emu_clause = "emu-clause"sv; -inline constexpr StringView tag_emu_const = "emu-const"sv; -inline constexpr StringView tag_emu_import = "emu-import"sv; -inline constexpr StringView tag_emu_intro = "emu-intro"sv; -inline constexpr StringView tag_emu_val = "emu-val"sv; -inline constexpr StringView tag_emu_xref = "emu-xref"sv; -inline constexpr StringView tag_h1 = "h1"sv; -inline constexpr StringView tag_li = "li"sv; -inline constexpr StringView tag_ol = "ol"sv; -inline constexpr StringView tag_p = "p"sv; -inline constexpr StringView tag_span = "span"sv; -inline constexpr StringView tag_specification = "specification"sv; -inline constexpr StringView tag_sup = "sup"sv; -inline constexpr StringView tag_var = "var"sv; - -inline constexpr StringView attribute_aoid = "aoid"sv; -inline constexpr StringView attribute_class = "class"sv; -inline constexpr StringView attribute_id = "id"sv; - -inline constexpr StringView class_secnum = "secnum"sv; - -struct StepTokenizationResult { - Optional> tokens; - XML::Node const* substeps = nullptr; -}; - -StepTokenizationResult tokenize_step(SpecificationParsingContext& ctx, XML::Node const* node); -Optional> tokenize_header(SpecificationParsingContext& ctx, XML::Node const* node); - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Specification.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Specification.cpp deleted file mode 100644 index 7dad575bfe3..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Specification.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2023-2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Parser/Lexer.h" -#include "Parser/SpecificationParsing.h" -#include "Parser/XMLUtils.h" - -namespace JSSpecCompiler { - -NonnullOwnPtr Specification::create(SpecificationParsingContext& ctx, XML::Node const* element) -{ - VERIFY(element->as_element().name == tag_specification); - - auto specification = make(); - specification->parse(ctx, element); - return specification; -} - -void Specification::collect_into(TranslationUnitRef translation_unit) -{ - for (auto& clause : m_clauses) - clause->collect_into(translation_unit); -} - -void Specification::parse(SpecificationParsingContext& ctx, XML::Node const* element) -{ - for (auto const& child : element->as_element().children) { - child->content.visit( - [&](XML::Node::Element const& element) { - if (element.name == tag_emu_intro) { - // Introductory comments are ignored. - } else if (element.name == tag_emu_clause) { - m_clauses.append(SpecificationClause::create(ctx, child)); - } else if (element.name == tag_emu_import) { - parse(ctx, child); - } else { - ctx.diag().error(ctx.location_from_xml_offset(child->offset), - "<{}> should not be a child of ", element.name); - } - }, - [&](XML::Node::Text const&) { - if (!contains_empty_text(child)) { - ctx.diag().error(ctx.location_from_xml_offset(child->offset), - "non-empty text node should not be a child of "); - } - }, - [&](auto) {}); - } -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationClause.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationClause.cpp deleted file mode 100644 index 1e03ce34fd4..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationClause.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2023-2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Parser/Lexer.h" -#include "Parser/SpecificationParsing.h" -#include "Parser/XMLUtils.h" - -namespace JSSpecCompiler { - -NonnullOwnPtr SpecificationClause::create(SpecificationParsingContext& ctx, XML::Node const* element) -{ - return ctx.with_new_logical_scope([&] { - VERIFY(element->as_element().name == tag_emu_clause); - - SpecificationClause specification_clause(ctx); - specification_clause.parse(element); - - OwnPtr result; - - specification_clause.m_header.header.visit( - [&](AK::Empty const&) { - result = make(move(specification_clause)); - }, - [&](OneOf auto const&) { - result = make(move(specification_clause)); - }, - [&](ClauseHeader::PropertiesList const&) { - result = make(move(specification_clause)); - }); - - if (!result->post_initialize(element)) - result = make(move(*result)); - - return result.release_nonnull(); - }); -} - -void SpecificationClause::collect_into(TranslationUnitRef translation_unit) -{ - do_collect(translation_unit); - for (auto& subclause : m_subclauses) - subclause->collect_into(translation_unit); -} - -Optional SpecificationClause::parse_header(XML::Node const* element) -{ - auto& ctx = *m_ctx_pointer; - VERIFY(element->as_element().name == tag_h1); - - auto maybe_tokens = tokenize_header(ctx, element); - if (!maybe_tokens.has_value()) - return {}; - - auto const& tokens = maybe_tokens.release_value(); - - TextParser parser(ctx, tokens, element); - auto parse_result = parser.parse_clause_header(m_clause_has_aoid_attribute); - if (parse_result.is_error()) { - // Still try to at least scavenge section number. - if (tokens.size() && tokens[0].type == TokenType::SectionNumber) - ctx.current_logical_scope().section = MUST(String::from_utf8(tokens[0].data)); - - return parser.get_diagnostic(); - } - - m_header = parse_result.release_value(); - ctx.current_logical_scope().section = MUST(String::from_utf8(m_header.section_number)); - return {}; -} - -void SpecificationClause::parse(XML::Node const* element) -{ - auto& ctx = context(); - u32 child_index = 0; - - bool node_ignored_warning_issued = false; - Optional header_parse_error; - - m_clause_has_aoid_attribute = element->as_element().attributes.get("aoid").has_value() - ? TextParser::ClauseHasAoidAttribute::Yes - : TextParser::ClauseHasAoidAttribute::No; - - for (auto const& child : element->as_element().children) { - child->content.visit( - [&](XML::Node::Element const& element) { - if (child_index == 0) { - if (element.name != tag_h1) { - ctx.diag().error(ctx.location_from_xml_offset(child->offset), - "

    must be the first child of "); - return; - } - header_parse_error = parse_header(child); - } else { - if (element.name == tag_h1) { - ctx.diag().error(ctx.location_from_xml_offset(child->offset), - "

    can only be the first child of "); - return; - } - - if (element.name == tag_emu_clause) { - m_subclauses.append(create(ctx, child)); - return; - } - if (!node_ignored_warning_issued && m_header.header.has()) { - node_ignored_warning_issued = true; - ctx.diag().warn(ctx.location_from_xml_offset(child->offset), - "node content will be ignored since section header was not parsed successfully"); - if (header_parse_error.has_value()) - ctx.diag().note(header_parse_error->location, "{}", header_parse_error->message); - } - } - ++child_index; - }, - [&](XML::Node::Text const&) { - if (!contains_empty_text(child)) { - ctx.diag().error(ctx.location_from_xml_offset(child->offset), - "non-empty text node should not be a child of "); - } - }, - [&](auto) {}); - } -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationFunction.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationFunction.cpp deleted file mode 100644 index 33a29c91ebb..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationFunction.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2023-2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Parser/Lexer.h" -#include "Parser/SpecificationParsing.h" -#include "Parser/XMLUtils.h" - -namespace JSSpecCompiler { - -bool SpecificationFunction::post_initialize(XML::Node const* element) -{ - VERIFY(element->as_element().name == tag_emu_clause); - - auto& ctx = context(); - m_location = ctx.location_from_xml_offset(element->offset); - - auto maybe_id = get_attribute_by_name(element, attribute_id); - if (!maybe_id.has_value()) { - ctx.diag().error(m_location, - "no id attribute"); - } else { - m_id = maybe_id.value(); - } - - m_header.header.visit( - [&](AbstractOperationDeclaration const& abstract_operation) { - m_declaration = abstract_operation; - - auto abstract_operation_id = get_attribute_by_name(element, attribute_aoid).value(); - - if (abstract_operation.name != abstract_operation_id) { - ctx.diag().warn(m_location, - "function name in header and [aoid] do not match"); - } - }, - [&](OneOf auto const& declaration) { - m_declaration = declaration; - }, - [&](auto const&) { - VERIFY_NOT_REACHED(); - }); - - Vector algorithm_nodes; - - for (auto const& child : element->as_element().children) { - child->content.visit( - [&](XML::Node::Element const& element) { - if (element.name == tag_h1) { - // Processed in SpecificationClause - } else if (element.name == tag_p) { - ctx.diag().warn(ctx.location_from_xml_offset(child->offset), - "prose is ignored"); - } else if (element.name == tag_emu_alg) { - algorithm_nodes.append(child); - } else { - ctx.diag().error(ctx.location_from_xml_offset(child->offset), - "<{}> should not be a child of specifing function"sv, element.name); - } - }, - [&](auto const&) {}); - } - - if (algorithm_nodes.size() != 1) { - ctx.diag().error(m_location, - " specifing function should have exactly one child"sv); - return false; - } - - auto maybe_algorithm = Algorithm::create(ctx, algorithm_nodes[0]); - if (maybe_algorithm.has_value()) { - m_algorithm = maybe_algorithm.release_value(); - return true; - } else { - return false; - } -} - -void SpecificationFunction::do_collect(TranslationUnitRef translation_unit) -{ - translation_unit->adopt_function(make_ref_counted(m_declaration.release_value(), m_location, m_algorithm.tree())); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationParsing.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationParsing.h deleted file mode 100644 index 088b654efef..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationParsing.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -#include "AST/AST.h" -#include "CompilationPipeline.h" -#include "Forward.h" -#include "Parser/TextParser.h" -#include "Parser/Token.h" - -namespace JSSpecCompiler { - -class SpecificationParsingContext { - AK_MAKE_NONCOPYABLE(SpecificationParsingContext); - AK_MAKE_NONMOVABLE(SpecificationParsingContext); - -public: - SpecificationParsingContext(TranslationUnitRef translation_unit) - : m_translation_unit(translation_unit) - { - } - - TranslationUnitRef translation_unit(); - DiagnosticEngine& diag(); - - template - auto with_new_logical_scope(Func&& func) - { - TemporaryChange> change(m_current_logical_scope, make_ref_counted()); - return func(); - } - - LogicalLocation& current_logical_scope(); - - template - auto with_new_step_list_nesting_level(Func&& func) - { - TemporaryChange change(m_step_list_nesting_level, m_step_list_nesting_level + 1); - return func(); - } - - int step_list_nesting_level() const; - - Location file_scope() const; - Location location_from_xml_offset(LineTrackingLexer::Position position) const; - -private: - TranslationUnitRef m_translation_unit; - RefPtr m_current_logical_scope; - int m_step_list_nesting_level = 0; -}; - -class AlgorithmStepList { -public: - static Optional create(SpecificationParsingContext& ctx, XML::Node const* element); - - Tree tree() const { return m_expression; } - -private: - static void update_logical_scope_for_step(SpecificationParsingContext& ctx, LogicalLocation const& parent_scope, int step_number); - - Tree m_expression = error_tree; -}; - -class AlgorithmStep { -public: - static Optional create(SpecificationParsingContext& ctx, XML::Node const* node); - - NullableTree tree() const { return m_expression; } - -private: - AlgorithmStep(SpecificationParsingContext& ctx) - : m_ctx(ctx) - { - } - - bool parse(); - - SpecificationParsingContext& m_ctx; - Vector m_tokens; - XML::Node const* m_node; - NullableTree m_expression = error_tree; - NullableTree m_substeps; -}; - -class Algorithm { -public: - static Optional create(SpecificationParsingContext& ctx, XML::Node const* element); - - Tree tree() const { return m_tree; } - -private: - Tree m_tree = error_tree; -}; - -class SpecificationClause { - AK_MAKE_DEFAULT_MOVABLE(SpecificationClause); - -public: - static NonnullOwnPtr create(SpecificationParsingContext& ctx, XML::Node const* element); - - virtual ~SpecificationClause() = default; - - void collect_into(TranslationUnitRef translation_unit); - -protected: - virtual bool post_initialize(XML::Node const* /*element*/) { return true; } - virtual void do_collect(TranslationUnitRef /*translation_unit*/) { } - - SpecificationParsingContext& context() { return *m_ctx_pointer; } - - ClauseHeader m_header; - -private: - SpecificationClause(SpecificationParsingContext& ctx) - : m_ctx_pointer(&ctx) - { - } - - Optional parse_header(XML::Node const* element); - void parse(XML::Node const* element); - - TextParser::ClauseHasAoidAttribute m_clause_has_aoid_attribute; - SpecificationParsingContext* m_ctx_pointer; - Vector> m_subclauses; -}; - -class SpecificationFunction : public SpecificationClause { -public: - SpecificationFunction(SpecificationClause&& clause) - : SpecificationClause(move(clause)) - { - } - -protected: - bool post_initialize(XML::Node const* element) override; - void do_collect(TranslationUnitRef translation_unit) override; - -private: - StringView m_id; - Optional m_declaration; - Location m_location; - Algorithm m_algorithm; -}; - -class ObjectProperties : public SpecificationClause { -public: - ObjectProperties(SpecificationClause&& clause) - : SpecificationClause(move(clause)) - { - } -}; - -class Specification { -public: - static NonnullOwnPtr create(SpecificationParsingContext& ctx, XML::Node const* element); - - void collect_into(TranslationUnitRef translation_unit); - -private: - void parse(SpecificationParsingContext& ctx, XML::Node const* element); - - Vector> m_clauses; -}; - -class SpecificationParsingStep : public CompilationStep { -public: - SpecificationParsingStep(); - ~SpecificationParsingStep(); - - void run(TranslationUnitRef translation_unit) override; - -private: - OwnPtr m_document; - OwnPtr m_specification; - - ByteBuffer m_input; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationParsingContext.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationParsingContext.cpp deleted file mode 100644 index c8e9382dbf4..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationParsingContext.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2023-2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Parser/SpecificationParsing.h" - -namespace JSSpecCompiler { - -TranslationUnitRef SpecificationParsingContext::translation_unit() -{ - return m_translation_unit; -} - -DiagnosticEngine& SpecificationParsingContext::diag() -{ - return m_translation_unit->diag(); -} - -LogicalLocation& SpecificationParsingContext::current_logical_scope() -{ - return *m_current_logical_scope; -} - -int SpecificationParsingContext::step_list_nesting_level() const -{ - return m_step_list_nesting_level; -} - -Location SpecificationParsingContext::file_scope() const -{ - return { .filename = m_translation_unit->filename() }; -} - -Location SpecificationParsingContext::location_from_xml_offset(LineTrackingLexer::Position position) const -{ - return { - .filename = m_translation_unit->filename(), - .line = position.line, - .column = position.column, - .logical_location = m_current_logical_scope, - }; -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationParsingStep.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationParsingStep.cpp deleted file mode 100644 index 92743e59987..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationParsingStep.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -#include "Function.h" -#include "Parser/Lexer.h" -#include "Parser/SpecificationParsing.h" -#include "Parser/TextParser.h" -#include "Parser/XMLUtils.h" - -namespace JSSpecCompiler { - -SpecificationParsingStep::SpecificationParsingStep() - : CompilationStep("parser"sv) -{ -} - -SpecificationParsingStep::~SpecificationParsingStep() = default; - -void SpecificationParsingStep::run(TranslationUnitRef translation_unit) -{ - SpecificationParsingContext ctx(translation_unit); - auto filename = translation_unit->filename(); - - auto file_or_error = Core::File::open_file_or_standard_stream(filename, Core::File::OpenMode::Read); - if (file_or_error.is_error()) { - ctx.diag().fatal_error(Location::global_scope(), - "unable to open '{}': {}", filename, file_or_error.error()); - return; - } - - auto input_or_error = file_or_error.value()->read_until_eof(); - if (input_or_error.is_error()) { - ctx.diag().fatal_error(Location::global_scope(), - "unable to read '{}': {}", filename, input_or_error.error()); - return; - } - m_input = input_or_error.release_value(); - - XML::Parser parser { m_input }; - auto document_or_error = parser.parse(); - if (document_or_error.is_error()) { - ctx.diag().fatal_error(ctx.file_scope(), - "XML::Parser failed to parse input: {}", document_or_error.error()); - ctx.diag().note(ctx.file_scope(), - "since XML::Parser backtracks on error, the message above is likely to point to the " - "first tag in the input - use external XML verifier to find out the exact cause of error"); - return; - } - m_document = make(document_or_error.release_value()); - - auto const& root = m_document->root(); - if (!root.is_element() || root.as_element().name != tag_specification) { - ctx.diag().fatal_error(ctx.location_from_xml_offset(root.offset), - "document root must be tag"); - return; - } - - m_specification = Specification::create(ctx, &root); - m_specification->collect_into(translation_unit); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp deleted file mode 100644 index e7f9ac30d19..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp +++ /dev/null @@ -1,868 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -#include "Parser/SpecificationParsing.h" -#include "Parser/TextParser.h" - -namespace JSSpecCompiler { - -void TextParser::save_error(Variant&& expected) -{ - if (expected.has() && expected.get() == TokenType::Invalid) - return; - if (m_max_parsed_tokens > m_next_token_index) - return; - if (m_max_parsed_tokens < m_next_token_index) - m_suitable_continuations.clear(); - m_max_parsed_tokens = m_next_token_index; - m_suitable_continuations.append(move(expected)); -} - -void TextParser::retreat() -{ - --m_next_token_index; -} - -auto TextParser::rollback_point() -{ - return ArmedScopeGuard { - [this, index = this->m_next_token_index] { - m_next_token_index = index; - } - }; -} - -Optional TextParser::peek_token() -{ - if (m_next_token_index == m_tokens.size()) - return {}; - return m_tokens[m_next_token_index]; -} - -Optional TextParser::consume_token() -{ - auto result = peek_token(); - if (result.has_value()) - ++m_next_token_index; - return result; -} - -TextParseErrorOr TextParser::consume_token_with_one_of_types(std::initializer_list types) -{ - auto token = peek_token(); - if (token.has_value()) { - for (TokenType type : types) { - if (token->type == type) { - (void)consume_token(); - return *token; - } else { - save_error(type); - } - } - } else { - for (TokenType type : types) - save_error(type); - } - - return TextParseError {}; -} - -TextParseErrorOr TextParser::consume_token_with_type(TokenType type) -{ - return consume_token_with_one_of_types({ type }); -} - -TextParseErrorOr TextParser::consume_token(TokenType type, StringView data) -{ - auto token = consume_token(); - if (!token.has_value() || token->type != type || !token->data.equals_ignoring_ascii_case(data)) { - retreat(); - save_error(data); - return TextParseError {}; - } - return {}; -} - -TextParseErrorOr TextParser::consume_word(StringView word) -{ - auto token = consume_token(); - if (!token.has_value() || token->type != TokenType::Word || !token->data.equals_ignoring_ascii_case(word)) { - retreat(); - save_error(word); - return TextParseError {}; - } - return {}; -} - -TextParseErrorOr TextParser::consume_words(std::initializer_list words) -{ - for (auto word : words) - TRY(consume_word(word)); - return {}; -} - -bool TextParser::is_eof() const -{ - return m_next_token_index == m_tokens.size(); -} - -TextParseErrorOr TextParser::expect_eof() -{ - if (!is_eof()) { - save_error(CustomMessage { "EOF"sv }); - return TextParseError {}; - } - return {}; -} - -// :== (the)? { (: ,)* } -TextParseErrorOr TextParser::parse_record_direct_list_initialization() -{ - auto rollback = rollback_point(); - - (void)consume_word("the"sv); - - auto identifier = TRY(consume_token_with_type(TokenType::Identifier)); - TRY(consume_token_with_type(TokenType::BraceOpen)); - Vector arguments; - while (true) { - auto name = TRY(consume_token_with_one_of_types({ TokenType::Identifier, TokenType::BraceClose })); - - if (name.is_bracket()) { - break; - } else { - TRY(consume_token_with_type(TokenType::Colon)); - auto value = TRY(parse_expression()); - (void)consume_token_with_type(TokenType::Comma); - arguments.append({ make_ref_counted(name.data), value }); - } - } - - rollback.disarm(); - return make_ref_counted( - make_ref_counted(identifier.data), move(arguments)); -} - -// :== '(' ( (, )* )? ')' -TextParseErrorOr> TextParser::parse_function_arguments() -{ - auto rollback = rollback_point(); - - TRY(consume_token_with_type(TokenType::ParenOpen)); - - if (!consume_token_with_type(TokenType::ParenClose).is_error()) { - rollback.disarm(); - return Vector {}; - } - - Vector arguments; - while (true) { - arguments.append(TRY(parse_expression())); - - auto token = TRY(consume_token_with_one_of_types({ TokenType::ParenClose, TokenType::Comma })); - if (token.type == TokenType::ParenClose) - break; - } - rollback.disarm(); - return arguments; -} - -// :== « ( (, )*)? » -TextParseErrorOr TextParser::parse_list_initialization() -{ - auto rollback = rollback_point(); - - TRY(consume_token_with_type(TokenType::ListStart)); - - if (!consume_token_with_type(TokenType::ListEnd).is_error()) { - rollback.disarm(); - return make_ref_counted(Vector {}); - } - - Vector elements; - while (true) { - elements.append(TRY(parse_expression())); - - auto token = TRY(consume_token_with_one_of_types({ TokenType::ListEnd, TokenType::Comma })); - if (token.type == TokenType::ListEnd) - break; - } - rollback.disarm(); - return make_ref_counted(move(elements)); -} - -TextParseErrorOr TextParser::parse_the_this_value() -{ - auto rollback = rollback_point(); - - TRY(consume_word("the"sv)); - TRY(consume_token(TokenType::WellKnownValue, "this"sv)); - TRY(consume_word("value"sv)); - - rollback.disarm(); - return make_ref_counted(WellKnownNode::Type::This); -} - -// :== | | | | | | -TextParseErrorOr TextParser::parse_value() -{ - if (auto identifier = consume_token_with_type(TokenType::Identifier); !identifier.is_error()) - return make_ref_counted(identifier.release_value().data); - - if (auto well_known_value = consume_token_with_type(TokenType::WellKnownValue); !well_known_value.is_error()) { - static constexpr struct { - StringView name; - WellKnownNode::Type type; - } translations[] = { - { "false"sv, WellKnownNode::Type::False }, - { "NewTarget"sv, WellKnownNode::Type::NewTarget }, - { "null"sv, WellKnownNode::Type::Null }, - { "this"sv, WellKnownNode::Type::This }, - { "true"sv, WellKnownNode::Type::True }, - { "undefined"sv, WellKnownNode::Type::Undefined }, - }; - for (auto [name, type] : translations) - if (well_known_value.value().data == name) - return make_ref_counted(type); - VERIFY_NOT_REACHED(); - } - - if (auto enumerator = consume_token_with_type(TokenType::Enumerator); !enumerator.is_error()) - return m_ctx.translation_unit()->get_node_for_enumerator_value(enumerator.value().data); - - if (auto number = consume_token_with_type(TokenType::Number); !number.is_error()) - return make_ref_counted(MUST(Crypto::BigFraction::from_string(number.value().data))); - - if (auto string = consume_token_with_type(TokenType::String); !string.is_error()) - return make_ref_counted(string.value().data); - - if (auto list_initialization = parse_list_initialization(); !list_initialization.is_error()) - return list_initialization.release_value(); - - if (auto record_initialization = parse_record_direct_list_initialization(); !record_initialization.is_error()) - return record_initialization.release_value(); - - if (auto the_this_value = parse_the_this_value(); !the_this_value.is_error()) - return the_this_value.release_value(); - - return TextParseError {}; -} - -// -TextParseErrorOr TextParser::parse_expression() -{ - auto rollback = rollback_point(); - -#define THROW_PARSE_ERROR_IF(expr) \ - do { \ - if (expr) { \ - save_error(CustomMessage { "valid expression continuation (not valid because " #expr ")"##sv }); \ - return TextParseError {}; \ - } \ - } while (false) -#define THROW_PARSE_ERROR THROW_PARSE_ERROR_IF(true) - - Vector> stack; - - auto merge_stack = [&](i32 precedence) { - if (!stack.last().has()) - return; - - while (stack.size() >= 2) { - auto const& maybe_operator = stack[stack.size() - 2]; - if (!maybe_operator.has()) - break; - auto last_operator = maybe_operator.get(); - - auto right = stack.last().get(); - - if (last_operator.is_unary_operator()) { - auto operation = make_ref_counted(last_operator.as_unary_operator(), right); - stack.shrink(stack.size() - 2); - stack.empend(operation); - } else if (last_operator.is_binary_operator() && last_operator.precedence() < precedence) { - auto left = stack[stack.size() - 3].get(); - auto operation = make_ref_counted(last_operator.as_binary_operator(), left, right); - stack.shrink(stack.size() - 3); - stack.empend(operation); - } else { - break; - } - } - }; - - auto merge_pre_merged = [&] { - if (stack.size() < 3) - return; - - auto const& maybe_left = stack[stack.size() - 3]; - auto const& maybe_operator = stack[stack.size() - 2]; - auto const& maybe_right = stack.last(); - - if (!maybe_left.has() || !maybe_operator.has() || !maybe_right.has()) - return; - - auto last_operator = maybe_operator.get(); - if (!last_operator.is_pre_merged_binary_operator()) - return; - - auto expression = make_ref_counted(last_operator.as_binary_operator(), maybe_left.get(), maybe_right.get()); - - stack.shrink(stack.size() - 3); - stack.empend(expression); - }; - - i32 bracket_balance = 0; - - while (true) { - auto token_or_error = peek_token(); - if (!token_or_error.has_value()) - break; - auto token = token_or_error.release_value(); - bool is_consumed = false; - - enum { - NoneType, - ExpressionType, - PreMergedBinaryOperatorType, - UnaryOperatorType, - BinaryOperatorType, - BracketType, - } last_element_type; - - if (stack.is_empty()) - last_element_type = NoneType; - else if (stack.last().has()) - last_element_type = ExpressionType; - else if (stack.last().get().is_pre_merged_binary_operator()) - last_element_type = PreMergedBinaryOperatorType; - else if (stack.last().get().is_unary_operator()) - last_element_type = UnaryOperatorType; - else if (stack.last().get().is_binary_operator()) - last_element_type = BinaryOperatorType; - else if (stack.last().get().is_bracket()) - last_element_type = BracketType; - else - VERIFY_NOT_REACHED(); - - if (token.is_ambiguous_operator()) { - if (token.type == TokenType::AmbiguousMinus) - token.type = last_element_type == ExpressionType ? TokenType::BinaryMinus : TokenType::UnaryMinus; - else - VERIFY_NOT_REACHED(); - } - - bracket_balance += token.is_opening_bracket(); - bracket_balance -= token.is_closing_bracket(); - - if (bracket_balance < 0) - break; - - if (token.type == TokenType::ParenOpen) { - if (last_element_type == ExpressionType) { - // This is a function call. - auto arguments = TRY(parse_function_arguments()); - is_consumed = true; - stack.append(Tree { make_ref_counted(stack.take_last().get(), move(arguments)) }); - --bracket_balance; - } else { - // This is just an opening '(' in expression. - stack.append(token); - } - } else if (token.is_pre_merged_binary_operator()) { - THROW_PARSE_ERROR_IF(last_element_type != ExpressionType); - stack.append(token); - } else if (token.is_unary_operator()) { - THROW_PARSE_ERROR_IF(last_element_type == PreMergedBinaryOperatorType); - stack.append(token); - } else if (token.is_binary_operator() || token.is_closing_bracket()) { - if (bracket_balance == 0 && token.type == TokenType::Comma) - break; - - THROW_PARSE_ERROR_IF(last_element_type != ExpressionType); - - merge_stack(token.precedence()); - if (token.is_closing_bracket()) { - THROW_PARSE_ERROR_IF(stack.size() == 1); - THROW_PARSE_ERROR_IF(!stack[stack.size() - 2].get().matches_with(token)); - stack.remove(stack.size() - 2); - merge_pre_merged(); - } else { - stack.append(token); - } - } else { - if (auto expression = parse_value(); !expression.is_error()) { - is_consumed = true; - THROW_PARSE_ERROR_IF(last_element_type == ExpressionType); - stack.append(expression.release_value()); - merge_pre_merged(); - } else { - break; - } - } - - if (!is_consumed) - VERIFY(consume_token().has_value()); - } - - THROW_PARSE_ERROR_IF(stack.is_empty()); - merge_stack(closing_bracket_precedence); - THROW_PARSE_ERROR_IF(stack.size() != 1 || !stack[0].has()); - - rollback.disarm(); - return stack[0].get(); -#undef THROW_PARSE_ERROR -#undef THROW_PARSE_ERROR_IF -} - -// :== | ( is (or )?) -TextParseErrorOr TextParser::parse_condition() -{ - auto rollback = rollback_point(); - auto expression = TRY(parse_expression()); - - if (!consume_token_with_type(TokenType::Is).is_error()) { - Vector compare_values { TRY(parse_expression()) }; - if (!consume_word("or"sv).is_error()) - compare_values.append(TRY(parse_expression())); - - rollback.disarm(); - return make_ref_counted(expression, move(compare_values)); - } - - rollback.disarm(); - return expression; -} - -// return -TextParseErrorOr TextParser::parse_return_statement() -{ - auto rollback = rollback_point(); - - TRY(consume_word("return"sv)); - auto return_value = TRY(parse_expression()); - - rollback.disarm(); - return make_ref_counted(return_value); -} - -// assert: -TextParseErrorOr TextParser::parse_assert() -{ - auto rollback = rollback_point(); - - TRY(consume_token(TokenType::Identifier, "assert"sv)); - TRY(consume_token_with_type(TokenType::Colon)); - auto condition = TRY(parse_condition()); - - rollback.disarm(); - return make_ref_counted(condition); -} - -// (let be ) | (set to ) -TextParseErrorOr TextParser::parse_assignment() -{ - auto rollback = rollback_point(); - - bool is_let = !consume_word("let"sv).is_error(); - if (!is_let) - TRY(consume_word("set"sv)); - auto lvalue = TRY(parse_expression()); - TRY(consume_word(is_let ? "be"sv : "to"sv)); - auto rvalue = TRY(parse_expression()); - - rollback.disarm(); - auto op = is_let ? BinaryOperator::Declaration : BinaryOperator::Assignment; - return make_ref_counted(op, lvalue, rvalue); -} - -// perform -TextParseErrorOr TextParser::parse_perform() -{ - auto rollback = rollback_point(); - - TRY(consume_word("perform"sv)); - auto value = TRY(parse_expression()); - - rollback.disarm(); - return value; -} - -// -TextParseErrorOr TextParser::parse_simple_step_or_inline_if_branch() -{ - auto rollback = rollback_point(); - - // Return .$ - if (auto result = parse_return_statement(); !result.is_error()) { - TRY(consume_token_with_type(TokenType::Dot)); - TRY(expect_eof()); - rollback.disarm(); - return result.release_value(); - } - - // Assert: .$ - if (auto result = parse_assert(); !result.is_error()) { - TRY(consume_token_with_type(TokenType::Dot)); - TRY(expect_eof()); - rollback.disarm(); - return result.release_value(); - } - - // Let be .$ - // Set to .$ - if (auto result = parse_assignment(); !result.is_error()) { - TRY(consume_token_with_type(TokenType::Dot)); - TRY(expect_eof()); - rollback.disarm(); - return result.release_value(); - } - - // Perform .$ - if (auto result = parse_perform(); !result.is_error()) { - TRY(consume_token_with_type(TokenType::Dot)); - TRY(expect_eof()); - rollback.disarm(); - return result.release_value(); - } - - return TextParseError {}; -} - -// :== (If ) | (Else) | (Else if ), -TextParseErrorOr TextParser::parse_if_beginning() -{ - auto rollback = rollback_point(); - - bool is_if_branch = !consume_word("if"sv).is_error(); - NullableTree condition = nullptr; - if (is_if_branch) { - condition = TRY(parse_condition()); - } else { - TRY(consume_word("else"sv)); - if (!consume_word("if"sv).is_error()) - condition = TRY(parse_condition()); - } - TRY(consume_token_with_type(TokenType::Comma)); - - rollback.disarm(); - return IfConditionParseResult { is_if_branch, condition }; -} - -// :== .$ -TextParseErrorOr TextParser::parse_inline_if_else() -{ - auto rollback = rollback_point(); - - auto [is_if_branch, condition] = TRY(parse_if_beginning()); - auto then_branch = TRY(parse_simple_step_or_inline_if_branch()); - - rollback.disarm(); - if (is_if_branch) - return make_ref_counted(condition.release_nonnull(), then_branch); - return make_ref_counted(condition, then_branch); -} - -// :== then$ -TextParseErrorOr TextParser::parse_if(Tree then_branch) -{ - auto rollback = rollback_point(); - - auto [is_if_branch, condition] = TRY(parse_if_beginning()); - TRY(consume_word("then"sv)); - TRY(expect_eof()); - - rollback.disarm(); - if (is_if_branch) - return make_ref_counted(*condition, then_branch); - else - return make_ref_counted(condition, then_branch); -} - -// :== Else,$ -TextParseErrorOr TextParser::parse_else(Tree else_branch) -{ - auto rollback = rollback_point(); - - TRY(consume_word("else"sv)); - TRY(consume_token_with_type(TokenType::Comma)); - TRY(expect_eof()); - - rollback.disarm(); - return make_ref_counted(nullptr, else_branch); -} - -// | -TextParseErrorOr TextParser::parse_step_without_substeps() -{ - auto rollback = rollback_point(); - - // NOTE: ... - if (auto result = consume_word("NOTE:"sv); !result.is_error()) { - rollback.disarm(); - return nullptr; - } - - // - if (auto result = parse_simple_step_or_inline_if_branch(); !result.is_error()) { - rollback.disarm(); - return result.release_value(); - } - - // - if (auto result = parse_inline_if_else(); !result.is_error()) { - rollback.disarm(); - return result.release_value(); - } - - return TextParseError {}; -} - -// | -TextParseErrorOr TextParser::parse_step_with_substeps(Tree substeps) -{ - auto rollback = rollback_point(); - - // - if (auto result = parse_if(substeps); !result.is_error()) { - rollback.disarm(); - return result.release_value(); - } - - // - if (auto result = parse_else(substeps); !result.is_error()) { - rollback.disarm(); - return result.release_value(); - } - - return TextParseError {}; -} - -// :== (. )* -TextParseErrorOr TextParser::parse_qualified_name() -{ - Vector qualified_name; - qualified_name.append(TRY(consume_token_with_type(TokenType::Word)).data); - while (true) { - auto token_or_error = consume_token_with_type(TokenType::MemberAccess); - if (token_or_error.is_error()) - return QualifiedName { qualified_name }; - qualified_name.append(TRY(consume_token_with_type(TokenType::Word)).data); - } -} - -// :== '(' ( (, )*)? ')' -TextParseErrorOr> TextParser::parse_function_arguments_in_declaration() -{ - TRY(consume_token_with_type(TokenType::ParenOpen)); - - Vector arguments; - size_t optional_arguments_group = 0; - - while (true) { - Token token = TRY(consume_token_with_one_of_types({ - TokenType::SquareBracketOpen, - arguments.is_empty() ? TokenType::Identifier : TokenType::Comma, - !optional_arguments_group ? TokenType::ParenClose : TokenType::Invalid, - optional_arguments_group ? TokenType::SquareBracketClose : TokenType::Invalid, - })); - - StringView identifier; - - if (token.type == TokenType::SquareBracketClose) { - VERIFY(optional_arguments_group != 0); - for (size_t i = 1; i < optional_arguments_group; ++i) - TRY(consume_token_with_type(TokenType::SquareBracketClose)); - TRY(consume_token_with_type(TokenType::ParenClose)); - break; - } else if (token.type == TokenType::ParenClose) { - VERIFY(optional_arguments_group == 0); - break; - } else if (token.type == TokenType::SquareBracketOpen) { - ++optional_arguments_group; - if (!arguments.is_empty()) - TRY(consume_token_with_type(TokenType::Comma)); - identifier = TRY(consume_token_with_type(TokenType::Identifier)).data; - } else if (token.type == TokenType::Comma) { - identifier = TRY(consume_token_with_type(TokenType::Identifier)).data; - } else { - VERIFY(token.type == TokenType::Identifier); - identifier = token.data; - } - - arguments.append({ identifier, optional_arguments_group }); - } - - return arguments; -} - -// :== $ -TextParseErrorOr TextParser::parse_abstract_operation_declaration() -{ - auto rollback = rollback_point(); - - auto name = TRY(consume_token_with_type(TokenType::Word)).data; - - AbstractOperationDeclaration function_definition; - function_definition.name = MUST(FlyString::from_utf8(name)); - function_definition.arguments = TRY(parse_function_arguments_in_declaration()); - TRY(expect_eof()); - - rollback.disarm(); - return function_definition; -} - -// :== get $ -TextParseErrorOr TextParser::parse_accessor_declaration() -{ - auto rollback = rollback_point(); - - TRY(consume_word("get"sv)); - AccessorDeclaration accessor; - accessor.name = TRY(parse_qualified_name()); - TRY(expect_eof()); - - rollback.disarm(); - return accessor; -} - -// :== | Properties of the Prototype Object $ -// | Properties of the Constructor $ -// | Properties of Instances $ -// | The Constructor $ -TextParseErrorOr TextParser::parse_properties_list_declaration() -{ - auto rollback = rollback_point(); - - ClauseHeader::PropertiesList properties_list; - - if (!consume_word("The"sv).is_error()) { - properties_list.name = TRY(parse_qualified_name()); - properties_list.object_type = ClauseHeader::ObjectType::Constructor; - TRY(consume_word("Constructor"sv)); - } else { - TRY(consume_words({ "Properties"sv, "of"sv })); - - bool has_the = !consume_word("the"sv).is_error(); - - properties_list.name = TRY(parse_qualified_name()); - - if (!has_the) { - TRY(consume_word("Instances"sv)); - properties_list.object_type = ClauseHeader::ObjectType::Instance; - } else { - if (consume_word("Prototype"sv).is_error()) { - TRY(consume_word("Constructor"sv)); - properties_list.object_type = ClauseHeader::ObjectType::Constructor; - } else { - TRY(consume_word("Object"sv)); - properties_list.object_type = ClauseHeader::ObjectType::Prototype; - } - } - } - - TRY(expect_eof()); - - rollback.disarm(); - return properties_list; -} - -TextParseErrorOr TextParser::parse_method_declaration() -{ - auto rollback = rollback_point(); - - MethodDeclaration method; - method.name = TRY(parse_qualified_name()); - method.arguments = TRY(parse_function_arguments_in_declaration()); - TRY(expect_eof()); - - rollback.disarm(); - return method; -} - -// :== | -TextParseErrorOr TextParser::parse_clause_header(ClauseHasAoidAttribute clause_has_aoid_attribute) -{ - ClauseHeader result; - - auto section_number_token = TRY(consume_token_with_type(TokenType::SectionNumber)); - result.section_number = section_number_token.data; - - if (clause_has_aoid_attribute == ClauseHasAoidAttribute::Yes) { - if (auto ao_declaration = parse_abstract_operation_declaration(); !ao_declaration.is_error()) { - result.header = ao_declaration.release_value(); - return result; - } - } else { - if (auto accessor = parse_accessor_declaration(); !accessor.is_error()) { - result.header = accessor.release_value(); - return result; - } else if (auto method = parse_method_declaration(); !method.is_error()) { - result.header = method.release_value(); - return result; - } else if (auto properties_list = parse_properties_list_declaration(); !properties_list.is_error()) { - result.header = properties_list.release_value(); - return result; - } - } - return TextParseError {}; -} - -FailedTextParseDiagnostic TextParser::get_diagnostic() const -{ - StringBuilder message; - - message.append("unexpected "sv); - - if (m_max_parsed_tokens == m_tokens.size()) { - message.append("EOF"sv); - } else { - auto token = m_tokens[m_max_parsed_tokens]; - if (token.type == TokenType::Word) - message.appendff("'{}'", token.data); - else if (token.type == TokenType::Identifier) - message.appendff("identifier '{}'", token.data); - else - message.append(token.name_for_diagnostic()); - } - - message.appendff(", expected "); - - size_t size = m_suitable_continuations.size(); - VERIFY(size > 0); - - for (size_t i = 0; i < size; ++i) { - m_suitable_continuations[i].visit( - [&](TokenType type) { message.append(token_info[to_underlying(type)].name_for_diagnostic); }, - [&](StringView word) { message.appendff("'{}'", word); }, - [&](CustomMessage continuation) { message.append(continuation.message); }); - - if (i + 1 != size) { - if (size == 2) - message.append(" or "sv); - else if (i + 2 == size) - message.append(", or "sv); - else - message.append(", "sv); - } - } - - Location location = Location::global_scope(); - - if (m_max_parsed_tokens < m_tokens.size()) { - location = m_tokens[m_max_parsed_tokens].location; - } else { - // FIXME: Would be nice to point to the closing tag not the opening one. This is also the - // only place where we use m_location. - location = m_ctx.location_from_xml_offset(m_node->offset); - } - - return { location, MUST(message.to_string()) }; -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.h deleted file mode 100644 index b7793fbb235..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "AST/AST.h" -#include "Function.h" -#include "Parser/Token.h" - -namespace JSSpecCompiler { - -struct ClauseHeader { - enum class ObjectType { - Constructor, - Prototype, - Instance, - }; - - struct PropertiesList { - QualifiedName name; - ObjectType object_type; - }; - - StringView section_number; - Variant header; -}; - -struct TextParseError { }; - -struct FailedTextParseDiagnostic { - Location location; - String message; -}; - -template -using TextParseErrorOr = ErrorOr; - -class TextParser { -public: - enum class ClauseHasAoidAttribute { - No, - Yes, - }; - - TextParser(SpecificationParsingContext& ctx, Vector const& tokens, XML::Node const* node) - : m_ctx(ctx) - , m_tokens(tokens) - , m_node(node) - { - } - - TextParseErrorOr parse_clause_header(ClauseHasAoidAttribute clause_has_aoid_attribute); - TextParseErrorOr parse_step_without_substeps(); - TextParseErrorOr parse_step_with_substeps(Tree substeps); - - FailedTextParseDiagnostic get_diagnostic() const; - -private: - struct IfConditionParseResult { - bool is_if_branch; - NullableTree condition; - }; - - struct CustomMessage { - StringView message; - }; - - void save_error(Variant&& expected); - - void retreat(); - [[nodiscard]] auto rollback_point(); - Optional peek_token(); - Optional consume_token(); - TextParseErrorOr consume_token_with_one_of_types(std::initializer_list types); - TextParseErrorOr consume_token_with_type(TokenType type); - TextParseErrorOr consume_token(TokenType type, StringView data); - TextParseErrorOr consume_word(StringView word); - TextParseErrorOr consume_words(std::initializer_list words); - bool is_eof() const; - TextParseErrorOr expect_eof(); - - TextParseErrorOr parse_record_direct_list_initialization(); - TextParseErrorOr> parse_function_arguments(); - TextParseErrorOr parse_list_initialization(); - TextParseErrorOr parse_the_this_value(); - TextParseErrorOr parse_value(); - TextParseErrorOr parse_expression(); - TextParseErrorOr parse_condition(); - TextParseErrorOr parse_return_statement(); - TextParseErrorOr parse_assert(); - TextParseErrorOr parse_assignment(); - TextParseErrorOr parse_perform(); - TextParseErrorOr parse_simple_step_or_inline_if_branch(); - TextParseErrorOr parse_if_beginning(); - TextParseErrorOr parse_inline_if_else(); - TextParseErrorOr parse_if(Tree then_branch); - TextParseErrorOr parse_else(Tree else_branch); - - TextParseErrorOr parse_qualified_name(); - TextParseErrorOr> parse_function_arguments_in_declaration(); - TextParseErrorOr parse_abstract_operation_declaration(); - TextParseErrorOr parse_method_declaration(); - TextParseErrorOr parse_accessor_declaration(); - TextParseErrorOr parse_properties_list_declaration(); - - SpecificationParsingContext& m_ctx; - Vector const& m_tokens; - size_t m_next_token_index = 0; - XML::Node const* m_node; - - size_t m_max_parsed_tokens = 0; - Vector, 8> m_suitable_continuations; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Token.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Token.h deleted file mode 100644 index 67b4b4ebc34..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Token.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -#include "AST/AST.h" -#include "DiagnosticEngine.h" - -namespace JSSpecCompiler { - -constexpr i32 ambiguous_operator_precedence = -2; -constexpr i32 pre_merged_operator_precedence = 2; -constexpr i32 unary_operator_precedence = 3; -constexpr i32 closing_bracket_precedence = 18; - -// NOTE: Operator precedence is generally the same as in -// https://en.cppreference.com/w/cpp/language/operator_precedence (common sense applies). -#define ENUMERATE_TOKENS(F) \ - F(Invalid, -1, Invalid, Invalid, Invalid, "") \ - F(AmbiguousMinus, -2, Invalid, Invalid, Invalid, "minus") \ - F(BinaryMinus, 6, Invalid, Minus, Invalid, "binary minus") \ - F(BraceClose, 18, Invalid, Invalid, BraceOpen, "'}'") \ - F(BraceOpen, -1, Invalid, Invalid, BraceClose, "'{'") \ - F(Colon, -1, Invalid, Invalid, Invalid, "':'") \ - F(Comma, 17, Invalid, Comma, Invalid, "','") \ - F(Division, 5, Invalid, Division, Invalid, "division") \ - F(Dot, -1, Invalid, Invalid, Invalid, "punctuation mark '.'") \ - F(Enumerator, -1, Invalid, Invalid, Invalid, "enumerator") \ - F(Equals, 10, Invalid, CompareEqual, Invalid, "equals") \ - F(ExclamationMark, 3, AssertCompletion, Invalid, Invalid, "exclamation mark") \ - F(Greater, 9, Invalid, CompareGreater, Invalid, "greater than") \ - F(Identifier, -1, Invalid, Invalid, Invalid, "identifier") \ - F(Is, -1, Invalid, Invalid, Invalid, "operator is") \ - F(Less, 9, Invalid, CompareLess, Invalid, "less than") \ - F(ListEnd, -1, Invalid, Invalid, Invalid, "»") \ - F(ListStart, -1, Invalid, Invalid, Invalid, "«") \ - F(MemberAccess, 2, Invalid, MemberAccess, Invalid, "member access operator '.'") \ - F(Multiplication, 5, Invalid, Multiplication, Invalid, "multiplication") \ - F(NotEquals, 10, Invalid, CompareNotEqual, Invalid, "not equals") \ - F(Number, -1, Invalid, Invalid, Invalid, "number") \ - F(ParenClose, 18, Invalid, Invalid, ParenOpen, "')'") \ - F(ParenOpen, -1, Invalid, Invalid, ParenClose, "'('") \ - F(Plus, 6, Invalid, Plus, Invalid, "plus") \ - F(QuestionMark, 3, ReturnIfAbrubt, Invalid, Invalid, "question mark") \ - F(SectionNumber, -1, Invalid, Invalid, Invalid, "section number") \ - F(SquareBracketClose, -1, Invalid, Invalid, Invalid, "']'") \ - F(SquareBracketOpen, -1, Invalid, Invalid, Invalid, "'['") \ - F(String, -1, Invalid, Invalid, Invalid, "string literal") \ - F(Superscript, 4, Invalid, Power, Invalid, "subscript") \ - F(UnaryMinus, 3, Minus, Invalid, Invalid, "unary minus") \ - F(WellKnownValue, -1, Invalid, Invalid, Invalid, "constant") \ - F(Word, -1, Invalid, Invalid, Invalid, "word") - -enum class TokenType { -#define ID(name, precedence, unary_name, binary_name, matching_bracket, name_for_diagnostic) name, - ENUMERATE_TOKENS(ID) -#undef ID -}; - -constexpr struct TokenInfo { - StringView name; - i32 precedence; - UnaryOperator as_unary_operator; - BinaryOperator as_binary_operator; - TokenType matching_bracket; - StringView name_for_diagnostic; -} token_info[] = { -#define TOKEN_INFO(name, precedence, unary_name, binary_name, matching_bracket, name_for_diagnostic) \ - { \ - #name##sv, \ - precedence, \ - UnaryOperator::unary_name, \ - BinaryOperator::binary_name, \ - TokenType::matching_bracket, \ - name_for_diagnostic##sv \ - }, - ENUMERATE_TOKENS(TOKEN_INFO) -#undef TOKEN_INFO -}; - -struct Token { - TokenInfo const& info() const { return token_info[to_underlying(type)]; } - - StringView name() const { return info().name; } - StringView name_for_diagnostic() const { return info().name_for_diagnostic; } - i32 precedence() const { return info().precedence; } - bool is_operator() const { return precedence() > 0 && precedence() < closing_bracket_precedence; } - bool is_ambiguous_operator() const { return precedence() == ambiguous_operator_precedence; } - bool is_pre_merged_binary_operator() const { return precedence() == pre_merged_operator_precedence; } - bool is_unary_operator() const { return precedence() == unary_operator_precedence; } - bool is_binary_operator() const { return is_operator() && !is_unary_operator(); } - bool is_bracket() const { return info().matching_bracket != TokenType::Invalid; } - bool is_opening_bracket() const { return is_bracket() && precedence() == -1; } - bool is_closing_bracket() const { return is_bracket() && precedence() == closing_bracket_precedence; } - - UnaryOperator as_unary_operator() const - { - VERIFY(is_unary_operator()); - return info().as_unary_operator; - } - - BinaryOperator as_binary_operator() const - { - VERIFY(is_binary_operator()); - return info().as_binary_operator; - } - - bool matches_with(Token const& bracket) - { - VERIFY(is_bracket()); - return info().matching_bracket == bracket.type; - } - - TokenType type; - StringView data; - Location location; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/XMLUtils.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/XMLUtils.cpp deleted file mode 100644 index 5d45e3fb307..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/XMLUtils.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -#include "Parser/XMLUtils.h" - -namespace JSSpecCompiler { - -bool contains_empty_text(XML::Node const* node) -{ - return node->as_text().builder.string_view().trim_whitespace().is_empty(); -} - -Optional get_attribute_by_name(XML::Node const* node, StringView attribute_name) -{ - auto const& attribute = node->as_element().attributes.get(attribute_name); - - if (!attribute.has_value()) - return {}; - return attribute.value(); -} - -Optional get_text_contents(XML::Node const* node) -{ - auto const& children = node->as_element().children; - if (children.size() != 1 || !children[0]->is_text()) - return {}; - return children[0]->as_text().builder.string_view(); -} - -Optional get_single_child_with_tag(XML::Node const* element, StringView tag_name) -{ - XML::Node const* result = nullptr; - - for (auto const& child : element->as_element().children) { - auto is_valid = child->content.visit( - [&](XML::Node::Element const& element) { - result = child; - return result != nullptr || element.name != tag_name; - }, - [&](XML::Node::Text const&) { - return contains_empty_text(child); - }, - [&](auto const&) { return true; }); - if (!is_valid) - return {}; - } - - if (result == nullptr) - return {}; - return result; -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/XMLUtils.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/XMLUtils.h deleted file mode 100644 index b0cbd5889d3..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/XMLUtils.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace JSSpecCompiler { - -bool contains_empty_text(XML::Node const* node); - -Optional get_attribute_by_name(XML::Node const* node, StringView attribute_name); - -Optional get_text_contents(XML::Node const* node); - -Optional get_single_child_with_tag(XML::Node const* element, StringView tag_name); - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Printer.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Printer.h deleted file mode 100644 index e296fa4e6d1..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Printer.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace JSSpecCompiler { - -class Printer { -public: - template - void block(Func&& func, StringView start = "{"sv, StringView end = "}"sv) - { - formatln("{}", start); - ++indent_level; - func(); - --indent_level; - format("{}", end); - } - - template - void format(AK::CheckedFormatString&& fmtstr, Parameters const&... parameters) - { - if (builder.string_view().ends_with('\n')) - builder.append_repeated(' ', indent_level * 4); - builder.appendff(move(fmtstr), forward(parameters)...); - } - - template - void formatln(AK::CheckedFormatString&& fmtstr, Parameters const&... parameters) - { - format(move(fmtstr), forward(parameters)...); - builder.append("\n"sv); - } - - StringView view() const { return builder.string_view(); } - -private: - StringBuilder builder; - size_t indent_level = 0; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Cell.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Cell.h deleted file mode 100644 index a4db70705e7..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Cell.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Forward.h" -#include "Printer.h" - -namespace JSSpecCompiler::Runtime { - -class Cell { -public: - virtual ~Cell() { } - - virtual StringView type_name() const = 0; - - void dump(Printer& printer) const - { - // FIXME: Handle cyclic references. - return do_dump(printer); - } - -protected: - virtual void do_dump(Printer& printer) const = 0; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Object.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Object.cpp deleted file mode 100644 index a266736347b..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Object.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Runtime/Object.h" -#include "Function.h" - -namespace JSSpecCompiler::Runtime { - -Optional Property::get_data_property_or_diagnose(Realm* realm, QualifiedName name, Location current_location) -{ - if (!has()) { - realm->diag().error(current_location, - "{} must be a data property", name.to_string()); - realm->diag().note(location(), - "defined as an accessor property here"); - return {}; - } - return get(); -} - -static StringView well_known_symbol_to_sv(WellKnownSymbol symbol) -{ - static Array string_value = { -#define STRING_VALUE(enum_name, spec_name) "@@" #spec_name##sv, - ENUMERATE_WELL_KNOWN_SYMBOLS(STRING_VALUE) -#undef STRING_VALUE - }; - return string_value[to_underlying(symbol)]; -} - -void Object::do_dump(Printer& printer) const -{ - printer.block([&] { - for (auto const& [key, value] : m_properties) { - key.visit( - [&](Slot const& slot) { printer.format("[[{}]]", slot.key); }, - [&](StringPropertyKey const& string_property) { printer.format("{}", string_property.key); }, - [&](WellKnownSymbol const& symbol) { printer.format("{}", well_known_symbol_to_sv(symbol)); }); - printer.format(": "); - value.visit( - [&](DataProperty const& data) { - printer.format( - "[{}{}{}] ", - data.is_configurable ? "c" : "", - data.is_enumerable ? "e" : "", - data.is_writable ? "w" : ""); - data.value->dump(printer); - }, - [&](AccessorProperty const& accessor) { - printer.format( - "[{}{}] AccessorProperty", - accessor.is_configurable ? "c" : "", - accessor.is_enumerable ? "e" : ""); - printer.block([&] { - if (accessor.getter.has_value()) - printer.formatln("get: {},", accessor.getter.value()->name()); - if (accessor.setter.has_value()) - printer.formatln("set: {},", accessor.setter.value()->name()); - }); - }); - printer.formatln(","); - } - }); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Object.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Object.h deleted file mode 100644 index 371b7bb56e9..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Object.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -#include "DiagnosticEngine.h" -#include "Function.h" -#include "Runtime/ObjectType.h" - -namespace JSSpecCompiler::Runtime { - -struct Slot { - bool operator==(Slot const&) const = default; - - FlyString key; -}; - -struct StringPropertyKey { - bool operator==(StringPropertyKey const&) const = default; - - FlyString key; -}; - -#define ENUMERATE_WELL_KNOWN_SYMBOLS(F) \ - F(InstanceType, _instanceType) \ - F(ToStringTag, toStringTag) - -enum class WellKnownSymbol { -#define ID(enum_name, spec_name) enum_name, - ENUMERATE_WELL_KNOWN_SYMBOLS(ID) -#undef ID -}; - -class PropertyKey : public Variant { -public: - using Variant::Variant; -}; - -struct DataProperty { - template - bool is() const - { - return ::is(value); - } - - template - T* as() const - { - return verify_cast(value); - } - - template - Optional get_or_diagnose(Realm* realm, QualifiedName name, Location location) - { - if (!is()) { - realm->diag().error(location, - "{} must be a {}", name.to_string(), T::TYPE_NAME); - realm->diag().note(this->location, - "set to {} here", value->type_name()); - return {}; - } - return verify_cast(value); - } - - Cell* value; - Location location; - - bool is_writable = true; - bool is_enumerable = false; - bool is_configurable = true; -}; - -struct AccessorProperty { - Optional getter; - Optional setter; - Location location; - - bool is_enumerable = false; - bool is_configurable = true; -}; - -class Property : public Variant { -public: - using Variant::Variant; - - Location location() const - { - return visit([&](auto const& value) { return value.location; }); - } - - Optional get_data_property_or_diagnose(Realm* realm, QualifiedName name, Location location); -}; - -class Object : public Runtime::Cell { -public: - static constexpr StringView TYPE_NAME = "object"sv; - - static Object* create(Realm* realm) - { - return realm->adopt_cell(new Object {}); - } - - StringView type_name() const override { return TYPE_NAME; } - - auto& type() { return m_type; } - auto& properties() { return m_properties; } - - bool has(PropertyKey const& key) const - { - return m_properties.contains(key); - } - - Property& get(PropertyKey const& key) - { - return m_properties.get(key).value(); - } - - void set(PropertyKey const& key, Property&& property) - { - auto insertion_result = m_properties.set(key, move(property)); - VERIFY(insertion_result == HashSetResult::InsertedNewEntry); - } - -protected: - void do_dump(Printer& printer) const override; - -private: - Object() = default; - - Optional m_type; - HashMap m_properties; -}; - -} - -template<> -struct AK::Traits : public DefaultTraits { - static unsigned hash(JSSpecCompiler::Runtime::PropertyKey const& key) - { - using namespace JSSpecCompiler::Runtime; - return key.visit( - [](Slot const& slot) { return pair_int_hash(1, slot.key.hash()); }, - [](StringPropertyKey const& string_key) { return pair_int_hash(2, string_key.key.hash()); }, - [](WellKnownSymbol const& symbol) { return pair_int_hash(3, to_underlying(symbol)); }); - } -}; diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/ObjectType.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/ObjectType.cpp deleted file mode 100644 index 53d510dd12c..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/ObjectType.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Runtime/ObjectType.h" - -namespace JSSpecCompiler::Runtime { - -void ObjectType::do_dump(Printer& printer) const -{ - printer.format("ObjectType"); -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/ObjectType.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/ObjectType.h deleted file mode 100644 index e6a0dd5b668..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/ObjectType.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Runtime/Realm.h" - -namespace JSSpecCompiler::Runtime { - -class ObjectType : public Cell { -public: - static constexpr StringView TYPE_NAME = "type"sv; - - static ObjectType* create(Realm* realm) - { - return realm->adopt_cell(new ObjectType {}); - } - - StringView type_name() const override { return TYPE_NAME; } - -protected: - void do_dump(Printer& printer) const override; - -private: - ObjectType() = default; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Realm.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Realm.cpp deleted file mode 100644 index 6f04059fcd3..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Realm.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Runtime/Realm.h" -#include "Runtime/Object.h" - -namespace JSSpecCompiler::Runtime { - -Realm::Realm(DiagnosticEngine& diag) - : m_diag(diag) - , m_global_object(Object::create(this)) -{ -} - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Realm.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Realm.h deleted file mode 100644 index f9b65bbd1f1..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Runtime/Realm.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -#include "Runtime/Cell.h" - -namespace JSSpecCompiler::Runtime { - -class Realm { -public: - Realm(DiagnosticEngine& diag); - - Runtime::Object* global_object() { return m_global_object; } - - template - T* adopt_cell(T* cell) - { - m_cells.append(NonnullOwnPtr { NonnullOwnPtr::AdoptTag::Adopt, *cell }); - return cell; - } - - DiagnosticEngine& diag() { return m_diag; } - -private: - DiagnosticEngine& m_diag; - Vector> m_cells; - - Runtime::Object* m_global_object; -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/simple.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/simple.cpp deleted file mode 100644 index a166e436f19..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/simple.cpp +++ /dev/null @@ -1,18 +0,0 @@ -auto f(auto cond1, auto cond2) -{ - int a; - int b; - - if (cond1) { - a = 1; - if (cond2) { - b = a; - } else { - b = 3; - } - } else { - b = 4; - } - - return b; -} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/simple.cpp.expectation b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/simple.cpp.expectation deleted file mode 100644 index 1bff94b123a..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/simple.cpp.expectation +++ /dev/null @@ -1,360 +0,0 @@ -===== AST after parser ===== -f(cond1, cond2): -TreeList - IfBranch - UnresolvedReference cond1 - TreeList - BinaryOperation Declaration - UnresolvedReference a - MathematicalConstant 1 - IfBranch - UnresolvedReference cond2 - TreeList - BinaryOperation Declaration - UnresolvedReference b - UnresolvedReference a - ElseIfBranch Else - TreeList - BinaryOperation Declaration - UnresolvedReference b - MathematicalConstant 3 - ElseIfBranch Else - TreeList - BinaryOperation Declaration - UnresolvedReference b - MathematicalConstant 4 - ReturnNode - UnresolvedReference b - -===== AST after if-branch-merging ===== -f(cond1, cond2): -TreeList - IfElseIfChain - UnresolvedReference cond1 - TreeList - BinaryOperation Declaration - UnresolvedReference a - MathematicalConstant 1 - IfElseIfChain - UnresolvedReference cond2 - TreeList - BinaryOperation Declaration - UnresolvedReference b - UnresolvedReference a - TreeList - BinaryOperation Declaration - UnresolvedReference b - MathematicalConstant 3 - TreeList - BinaryOperation Declaration - UnresolvedReference b - MathematicalConstant 4 - ReturnNode - UnresolvedReference b - -===== AST after reference-resolving ===== -f(cond1, cond2): -TreeList - IfElseIfChain - Var cond1 - TreeList - BinaryOperation Assignment - Var a - MathematicalConstant 1 - IfElseIfChain - Var cond2 - TreeList - BinaryOperation Assignment - Var b - Var a - TreeList - BinaryOperation Assignment - Var b - MathematicalConstant 3 - TreeList - BinaryOperation Assignment - Var b - MathematicalConstant 4 - ReturnNode - Var b - -===== AST after cfg-building ===== -f(cond1, cond2): -TreeList - IfElseIfChain - Var cond1 - TreeList - BinaryOperation Assignment - Var a - MathematicalConstant 1 - IfElseIfChain - Var cond2 - TreeList - BinaryOperation Assignment - Var b - Var a - TreeList - BinaryOperation Assignment - Var b - MathematicalConstant 3 - TreeList - BinaryOperation Assignment - Var b - MathematicalConstant 4 - ReturnNode - Var b - -===== CFG after cfg-building ===== -f(cond1, cond2): -0: -ControlFlowBranch true=3 false=7 - Var cond1 - -1: -ControlFlowFunctionReturn - Var $return - -2: -BinaryOperation Assignment - Var $return - Var b -ControlFlowJump jump=1 - -3: -BinaryOperation Assignment - Var a - MathematicalConstant 1 -ControlFlowBranch true=5 false=6 - Var cond2 - -4: -ControlFlowJump jump=2 - -5: -BinaryOperation Assignment - Var b - Var a -ControlFlowJump jump=4 - -6: -BinaryOperation Assignment - Var b - MathematicalConstant 3 -ControlFlowJump jump=4 - -7: -BinaryOperation Assignment - Var b - MathematicalConstant 4 -ControlFlowJump jump=2 - -8: -BinaryOperation Assignment - Var $return - Error "" -ControlFlowJump jump=1 - -===== AST after cfg-simplification ===== -f(cond1, cond2): -TreeList - IfElseIfChain - Var cond1 - TreeList - BinaryOperation Assignment - Var a - MathematicalConstant 1 - IfElseIfChain - Var cond2 - TreeList - BinaryOperation Assignment - Var b - Var a - TreeList - BinaryOperation Assignment - Var b - MathematicalConstant 3 - TreeList - BinaryOperation Assignment - Var b - MathematicalConstant 4 - ReturnNode - Var b - -===== CFG after cfg-simplification ===== -f(cond1, cond2): -0: -ControlFlowBranch true=3 false=6 - Var cond1 - -1: -ControlFlowFunctionReturn - Var $return - -2: -BinaryOperation Assignment - Var $return - Var b -ControlFlowJump jump=1 - -3: -BinaryOperation Assignment - Var a - MathematicalConstant 1 -ControlFlowBranch true=4 false=5 - Var cond2 - -4: -BinaryOperation Assignment - Var b - Var a -ControlFlowJump jump=2 - -5: -BinaryOperation Assignment - Var b - MathematicalConstant 3 -ControlFlowJump jump=2 - -6: -BinaryOperation Assignment - Var b - MathematicalConstant 4 -ControlFlowJump jump=2 - -===== AST after ssa-building ===== -f(cond1, cond2): -TreeList - IfElseIfChain - Var cond1@0 - TreeList - BinaryOperation Assignment - Var a@1 - MathematicalConstant 1 - IfElseIfChain - Var cond2@0 - TreeList - BinaryOperation Assignment - Var b@1 - Var a@1 - TreeList - BinaryOperation Assignment - Var b@3 - MathematicalConstant 3 - TreeList - BinaryOperation Assignment - Var b@4 - MathematicalConstant 4 - ReturnNode - Var b@2 - -===== CFG after ssa-building ===== -f(cond1, cond2): -0: -ControlFlowBranch true=1 false=6 - Var cond1@0 - -1: -BinaryOperation Assignment - Var a@1 - MathematicalConstant 1 -ControlFlowBranch true=2 false=5 - Var cond2@0 - -2: -BinaryOperation Assignment - Var b@1 - Var a@1 -ControlFlowJump jump=3 - -3: -a@2 = phi(2: a@1, 5: a@1, 6: a@0) -b@2 = phi(2: b@1, 5: b@3, 6: b@4) -BinaryOperation Assignment - Var $return@1 - Var b@2 -ControlFlowJump jump=4 - -4: -ControlFlowFunctionReturn - Var $return@1 - -5: -BinaryOperation Assignment - Var b@3 - MathematicalConstant 3 -ControlFlowJump jump=3 - -6: -BinaryOperation Assignment - Var b@4 - MathematicalConstant 4 -ControlFlowJump jump=3 - -===== AST after dce ===== -f(cond1, cond2): -TreeList - IfElseIfChain - Var cond1@0 - TreeList - BinaryOperation Assignment - Var a@1 - MathematicalConstant 1 - IfElseIfChain - Var cond2@0 - TreeList - BinaryOperation Assignment - Var b@1 - Var a@1 - TreeList - BinaryOperation Assignment - Var b@3 - MathematicalConstant 3 - TreeList - BinaryOperation Assignment - Var b@4 - MathematicalConstant 4 - ReturnNode - Var b@2 - -===== CFG after dce ===== -f(cond1, cond2): -0: -ControlFlowBranch true=1 false=6 - Var cond1@0 - -1: -BinaryOperation Assignment - Var a@1 - MathematicalConstant 1 -ControlFlowBranch true=2 false=5 - Var cond2@0 - -2: -BinaryOperation Assignment - Var b@1 - Var a@1 -ControlFlowJump jump=3 - -3: -b@2 = phi(2: b@1, 5: b@3, 6: b@4) -BinaryOperation Assignment - Var $return@1 - Var b@2 -ControlFlowJump jump=4 - -4: -ControlFlowFunctionReturn - Var $return@1 - -5: -BinaryOperation Assignment - Var b@3 - MathematicalConstant 3 -ControlFlowJump jump=3 - -6: -BinaryOperation Assignment - Var b@4 - MathematicalConstant 4 -ControlFlowJump jump=3 - diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-headers.xml b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-headers.xml deleted file mode 100644 index f68524d6513..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-headers.xml +++ /dev/null @@ -1,17 +0,0 @@ -]> - - -

    1 get Foo.Bar.baz

    -
    1. Return unused.
    -
    - - -

    2 TestAbstractOperation ( a )

    -
    1. Return unused.
    -
    - - -

    3 Foo.Bar.foo ( a )

    -
    1. Return unused.
    -
    -
    diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-headers.xml.expectation b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-headers.xml.expectation deleted file mode 100644 index 836837fd80b..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-headers.xml.expectation +++ /dev/null @@ -1,16 +0,0 @@ -===== AST after reference-resolving ===== -%get Foo.Bar.baz%(): -TreeList - ReturnNode - Enumerator unused - -TestAbstractOperation(a): -TreeList - ReturnNode - Enumerator unused - -%Foo.Bar.foo%(a): -TreeList - ReturnNode - Enumerator unused - diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-no-new-line-after-dot.xml b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-no-new-line-after-dot.xml deleted file mode 100644 index 18a443406cb..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-no-new-line-after-dot.xml +++ /dev/null @@ -1,19 +0,0 @@ -]> - - - -

    1 The Celestial Object

    - -

    1.1 Abstract Operations

    - -

    1.1.1 Foo ( a )

    - -
      -
    1. Return a.[[b]].
    2. -
    -
    -
    -
    -
    -
    -
    diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-no-new-line-after-dot.xml.expectation b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-no-new-line-after-dot.xml.expectation deleted file mode 100644 index b84a41a8bed..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-no-new-line-after-dot.xml.expectation +++ /dev/null @@ -1,8 +0,0 @@ -===== AST after reference-resolving ===== -Foo(a): -TreeList - ReturnNode - BinaryOperation MemberAccess - Var a - Slot b - diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-optional-arguments.xml b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-optional-arguments.xml deleted file mode 100644 index f6ed3c5648f..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-optional-arguments.xml +++ /dev/null @@ -1,12 +0,0 @@ -]> - - -

    1 TestOptionalArgumentsGroups1 ( [a, b[, c]] )

    -
    1. Return unused.
    -
    - - -

    2 TestOptionalArgumentsGroups2 ( a, b[, c, d] )

    -
    1. Return unused.
    -
    -
    diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-optional-arguments.xml.expectation b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-optional-arguments.xml.expectation deleted file mode 100644 index b67d640eb61..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-optional-arguments.xml.expectation +++ /dev/null @@ -1,11 +0,0 @@ -===== AST after reference-resolving ===== -TestOptionalArgumentsGroups1([a, b, [c]]): -TreeList - ReturnNode - Enumerator unused - -TestOptionalArgumentsGroups2(a, b, [c, d]): -TreeList - ReturnNode - Enumerator unused - diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml deleted file mode 100644 index 5c639632844..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml +++ /dev/null @@ -1,85 +0,0 @@ -]> - - -

    1 ArbitrarilyLargeNumbers ( a )

    - -
      -
    1. Let a be 1.
    2. -
    3. Let b be 3.6.
    4. -
    5. Let c be -3.6.
    6. -
    7. Let d be -1000000000000000000000.
    8. -
    9. Let e be 1.0000001.
    10. -
    11. Return a+b+c+d+e.
    12. -
    -
    -
    - -

    2 WellKnownConstants ( a )

    - -
      -
    1. - If a is undefined, then -
        -
      1. Let b be null.
      2. -
      3. Return true.
      4. -
      -
    2. -
    3. Else, -
        -
      1. Let c be this.
      2. -
      3. Return false.
      4. -
      -
    4. -
    -
    -
    - -

    3 TestReturnIfAbrupt ( a )

    - -
      -
    1. Return ? WellKnownConstants(a).
    2. -
    - - - -

    4 Enumerators ( )

    - -
      -
    1. Return ? WellKnownConstants(enumerator).
    2. -
    -
    -
    - -

    - 5 Lists ( a, b ) -

    - -
      -
    1. Let a be « ».
    2. -
    3. Set a to « 1 ».
    4. -
    5. Set a to « 1, 2 ».
    6. -
    7. Set a to « 1, 2, 3 + 4 ».
    8. -
    9. Return unused.
    10. -
    -
    -
    - -

    6 get Temporal.PlainDateTime.prototype.inLeapYear

    - -
      -
    1. Let dateTime be the this value.
    2. -
    3. Perform ? RequireInternalSlot(dateTime, [[A]]).
    4. -
    5. Return undefined.
    6. -
    -
    -
    - -

    7 Notes ( )

    - -
      -
    1. NOTE: This abstract operation returns unused in case you didn't notice.
    2. -
    3. Return unused.
    4. -
    -
    -
    - diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml.expectation b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml.expectation deleted file mode 100644 index d892367e241..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml.expectation +++ /dev/null @@ -1,107 +0,0 @@ -===== AST after reference-resolving ===== -ArbitrarilyLargeNumbers(a): -TreeList - BinaryOperation Assignment - Var a - MathematicalConstant 1 - BinaryOperation Assignment - Var b - MathematicalConstant 3.6 - BinaryOperation Assignment - Var c - MathematicalConstant -3.6 - BinaryOperation Assignment - Var d - MathematicalConstant -1000000000000000000000 - BinaryOperation Assignment - Var e - MathematicalConstant 10000001/10000000 - ReturnNode - BinaryOperation Plus - Var a - BinaryOperation Plus - Var b - BinaryOperation Plus - Var c - BinaryOperation Plus - Var d - Var e - -WellKnownConstants(a): -TreeList - IfElseIfChain - IsOneOf - Var a - WellKnownNode Undefined - TreeList - BinaryOperation Assignment - Var b - WellKnownNode Null - ReturnNode - WellKnownNode True - TreeList - BinaryOperation Assignment - Var c - WellKnownNode This - ReturnNode - WellKnownNode False - -TestReturnIfAbrupt(a): -TreeList - ReturnNode - UnaryOperation ReturnIfAbrubt - FunctionCall - Func "WellKnownConstants" - Var a - -Enumerators(): -TreeList - ReturnNode - UnaryOperation ReturnIfAbrubt - FunctionCall - Func "WellKnownConstants" - Enumerator enumerator - -Lists(a, b): -TreeList - BinaryOperation Assignment - Var a - List - BinaryOperation Assignment - Var a - List - Enumerator 1 - BinaryOperation Assignment - Var a - List - Enumerator 1 - Enumerator 2 - BinaryOperation Assignment - Var a - List - Enumerator 1 - Enumerator 2 - BinaryOperation Plus - MathematicalConstant 3 - MathematicalConstant 4 - ReturnNode - Enumerator unused - -%get Temporal.PlainDateTime.prototype.inLeapYear%(): -TreeList - BinaryOperation Assignment - Var dateTime - WellKnownNode This - UnaryOperation ReturnIfAbrubt - FunctionCall - UnresolvedReference RequireInternalSlot - Var dateTime - Slot A - ReturnNode - WellKnownNode Undefined - -Notes(): -TreeList - ReturnNode - Enumerator unused - diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-single-function-simple.xml b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-single-function-simple.xml deleted file mode 100644 index 1b2c231f64b..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-single-function-simple.xml +++ /dev/null @@ -1,35 +0,0 @@ -]> - - - -

    2 The Celestial.Now Object

    - -

    2.3 Abstract Operations

    - -

    2.3.2 SystemUTCEpochMilliseconds ( )

    - -
      -
    1. - Let global be - GetGlobalObject - (). -
    2. -
    3. - Let nowNs be - HostSystemUTCEpochNanoseconds - (global). -
    4. -
    5. - Return - 𝔽 - ( - floor - (nowNs / 106)). -
    6. -
    -
    -
    -
    -
    -
    -
    diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-single-function-simple.xml.expectation b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-single-function-simple.xml.expectation deleted file mode 100644 index cdc17c6de01..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-single-function-simple.xml.expectation +++ /dev/null @@ -1,23 +0,0 @@ -===== AST after reference-resolving ===== -SystemUTCEpochMilliseconds(): -TreeList - BinaryOperation Assignment - Var global - FunctionCall - UnresolvedReference GetGlobalObject - BinaryOperation Assignment - Var nowNs - FunctionCall - UnresolvedReference HostSystemUTCEpochNanoseconds - Var global - ReturnNode - FunctionCall - UnresolvedReference 𝔽 - FunctionCall - UnresolvedReference floor - BinaryOperation Division - Var nowNs - BinaryOperation Power - MathematicalConstant 10 - MathematicalConstant 6 - diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/main.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/main.cpp deleted file mode 100644 index 663ddddec81..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/main.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -#include "Compiler/Passes/CFGBuildingPass.h" -#include "Compiler/Passes/CFGSimplificationPass.h" -#include "Compiler/Passes/DeadCodeEliminationPass.h" -#include "Compiler/Passes/IfBranchMergingPass.h" -#include "Compiler/Passes/ReferenceResolvingPass.h" -#include "Compiler/Passes/SSABuildingPass.h" -#include "Function.h" -#include "Parser/CppASTConverter.h" -#include "Parser/SpecificationParsing.h" - -using namespace JSSpecCompiler; - -struct CompilationStepWithDumpOptions { - OwnPtr step; - bool dump_ast = false; - bool dump_cfg = false; -}; - -class CompilationPipeline { -public: - template - void add_compilation_pass() - { - auto func = +[](TranslationUnitRef translation_unit) { - T { translation_unit }.run(); - }; - add_step(adopt_own_if_nonnull(new NonOwningCompilationStep(T::name, func))); - } - - template - void for_each_step_in(StringView pass_list, T&& func) - { - HashTable selected_steps; - for (auto pass : pass_list.split_view(',')) { - if (pass == "all") { - for (auto const& step : m_pipeline) - selected_steps.set(step.step->name()); - } else if (pass == "last") { - selected_steps.set(m_pipeline.last().step->name()); - } else if (pass.starts_with('-')) { - VERIFY(selected_steps.remove(pass.substring_view(1))); - } else { - selected_steps.set(pass); - } - } - - for (auto& step : m_pipeline) - if (selected_steps.contains(step.step->name())) - func(step); - } - - void add_step(OwnPtr&& step) - { - m_pipeline.append({ move(step) }); - } - - auto const& pipeline() const { return m_pipeline; } - -private: - Vector m_pipeline; -}; - -template<> -struct AK::Formatter> : AK::Formatter { - ErrorOr format(FormatBuilder& builder, ReadonlySpan const& arguments) - { - size_t previous_optional_group = 0; - for (size_t i = 0; i < arguments.size(); ++i) { - if (previous_optional_group != arguments[i].optional_arguments_group) { - previous_optional_group = arguments[i].optional_arguments_group; - TRY(builder.put_string("["sv)); - } - TRY(builder.put_string(arguments[i].name)); - if (i + 1 != arguments.size()) - TRY(builder.put_literal(", "sv)); - } - TRY(builder.put_string(TRY(String::repeated(']', previous_optional_group)))); - return {}; - } -}; - -ErrorOr serenity_main(Main::Arguments arguments) -{ - Core::ArgsParser args_parser; - - StringView filename; - args_parser.add_positional_argument(filename, "File to compile", "file"); - - constexpr StringView language_spec = "spec"sv; - constexpr StringView language_cpp = "c++"sv; - StringView language = language_spec; - args_parser.add_option(Core::ArgsParser::Option { - .argument_mode = Core::ArgsParser::OptionArgumentMode::Optional, - .help_string = "Specify the language of the input file.", - .short_name = 'x', - .value_name = "{c++|spec}", - .accept_value = [&](StringView value) { - language = value; - return language.is_one_of(language_spec, language_cpp); - }, - }); - - StringView passes_to_dump_ast; - args_parser.add_option(passes_to_dump_ast, "Dump AST after specified passes.", "dump-ast", 0, "{all|last||-[,...]}"); - - StringView passes_to_dump_cfg; - args_parser.add_option(passes_to_dump_cfg, "Dump CFG after specified passes.", "dump-cfg", 0, "{all|last||-[,...]}"); - - bool silence_diagnostics = false; - args_parser.add_option(silence_diagnostics, "Silence all diagnostics.", "silence-diagnostics"); - - args_parser.parse(arguments); - - CompilationPipeline pipeline; - if (language == language_cpp) - pipeline.add_step(adopt_own_if_nonnull(new CppParsingStep())); - else - pipeline.add_step(adopt_own_if_nonnull(new SpecificationParsingStep())); - pipeline.add_compilation_pass(); - pipeline.add_compilation_pass(); - pipeline.add_compilation_pass(); - pipeline.add_compilation_pass(); - pipeline.add_compilation_pass(); - pipeline.add_compilation_pass(); - - pipeline.for_each_step_in(passes_to_dump_ast, [](CompilationStepWithDumpOptions& step) { - step.dump_ast = true; - }); - pipeline.for_each_step_in(passes_to_dump_cfg, [](CompilationStepWithDumpOptions& step) { - step.dump_cfg = true; - }); - - TranslationUnit translation_unit(filename); - - for (auto const& step : pipeline.pipeline()) { - step.step->run(&translation_unit); - - if (translation_unit.diag().has_fatal_errors()) { - translation_unit.diag().print_diagnostics(); - return 1; - } - - if (step.dump_ast) { - outln(stderr, "===== AST after {} =====", step.step->name()); - for (auto const& function : translation_unit.functions_to_compile()) { - outln(stderr, "{}({}):", function->name(), function->arguments()); - outln(stderr, "{}", function->m_ast); - } - } - if (step.dump_cfg && translation_unit.functions_to_compile().size() && translation_unit.functions_to_compile()[0]->m_cfg != nullptr) { - outln(stderr, "===== CFG after {} =====", step.step->name()); - for (auto const& function : translation_unit.functions_to_compile()) { - outln(stderr, "{}({}):", function->name(), function->arguments()); - outln(stderr, "{}", *function->m_cfg); - } - } - } - - if (!silence_diagnostics) - translation_unit.diag().print_diagnostics(); - - return 0; -} diff --git a/Meta/Lagom/Tools/CodeGenerators/LibGL/CMakeLists.txt b/Meta/Lagom/Tools/CodeGenerators/LibGL/CMakeLists.txt deleted file mode 100644 index 682d056e3b0..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/LibGL/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -lagom_tool(GenerateGLAPIWrapper SOURCES GenerateGLAPIWrapper.cpp LIBS LibMain) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibGL/GenerateGLAPIWrapper.cpp b/Meta/Lagom/Tools/CodeGenerators/LibGL/GenerateGLAPIWrapper.cpp deleted file mode 100644 index 823e5070dfe..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/LibGL/GenerateGLAPIWrapper.cpp +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct ArgumentDefinition { - Optional name; - Optional cpp_type; - ByteString expression; - Optional cast_to; -}; - -struct FunctionDefinition { - ByteString name; - ByteString return_type; - Vector arguments; - ByteString implementation; - bool unimplemented; - ByteString variant_gl_type; -}; - -struct VariantType { - ByteString encoded_type; - Optional implementation; - bool unimplemented; -}; - -struct Variants { - Vector api_suffixes { "" }; - Vector argument_counts { NumericLimits::max() }; - Vector argument_defaults { "" }; - bool convert_range { false }; - Vector types { - { - .encoded_type = "", - .implementation = Optional {}, - .unimplemented = false, - } - }; - ByteString pointer_argument { "" }; -}; - -struct EncodedTypeEntry { - StringView encoded_type; - StringView cpp_type; - StringView gl_type; -}; - -// clang-format off -constexpr static Array type_definitions = { - EncodedTypeEntry { "b"sv, "GLbyte"sv, "GL_BYTE"sv }, - EncodedTypeEntry { "d"sv, "GLdouble"sv, "GL_DOUBLE"sv }, - EncodedTypeEntry { "f"sv, "GLfloat"sv, "GL_FLOAT"sv }, - EncodedTypeEntry { "i"sv, "GLint"sv, "GL_INT"sv }, - EncodedTypeEntry { "s"sv, "GLshort"sv, "GL_SHORT"sv }, - EncodedTypeEntry { "ub"sv, "GLubyte"sv, "GL_UNSIGNED_BYTE"sv }, - EncodedTypeEntry { "ui"sv, "GLuint"sv, "GL_UNSIGNED_INT"sv }, - EncodedTypeEntry { "us"sv, "GLushort"sv, "GL_UNSIGNED_SHORT"sv }, - EncodedTypeEntry { "x"sv, "GLfixed"sv, "GL_INT"sv }, -}; -// clang-format on - -struct EncodedType { - EncodedTypeEntry type_entry; - ByteString cpp_type; - ByteString function_name_suffix; - bool is_pointer; - bool is_const_pointer; -}; - -Vector get_name_list(Optional name_definition) -{ - if (!name_definition.has_value() || name_definition->is_null()) - return {}; - - Vector names; - if (name_definition->is_string()) { - names.append(name_definition->as_string()); - } else if (name_definition->is_array()) { - name_definition->as_array().for_each([&names](auto& value) { - VERIFY(value.is_string()); - names.append(value.as_string()); - }); - } else { - VERIFY_NOT_REACHED(); - } - return names; -} - -Optional get_encoded_type(ByteString encoded_type) -{ - bool is_const_pointer = !encoded_type.ends_with('!'); - if (!is_const_pointer) - encoded_type = encoded_type.substring_view(0, encoded_type.length() - 1); - ByteString function_name_suffix = encoded_type; - - bool is_pointer = encoded_type.ends_with('v'); - if (is_pointer) - encoded_type = encoded_type.substring_view(0, encoded_type.length() - 1); - - VERIFY(is_const_pointer || is_pointer); - - Optional type_definition; - for (size_t i = 0; i < type_definitions.size(); ++i) { - if (type_definitions[i].encoded_type == encoded_type) { - type_definition = type_definitions[i]; - break; - } - } - - if (!type_definition.has_value()) - return {}; - - return EncodedType { - .type_entry = type_definition.value(), - .cpp_type = ByteString::formatted( - "{}{}{}", - type_definition->cpp_type, - is_pointer && is_const_pointer ? " const" : "", - is_pointer ? "*" : ""), - .function_name_suffix = function_name_suffix, - .is_pointer = is_pointer, - .is_const_pointer = is_const_pointer, - }; -} - -ByteString wrap_expression_in_range_conversion(ByteString source_type, ByteString target_type, ByteString expression) -{ - VERIFY(target_type == "GLfloat" || target_type == "GLdouble"); - - // No range conversion required - if (source_type == target_type || source_type == "GLdouble") - return expression; - - if (source_type == "GLbyte") - return ByteString::formatted("({} + 128.) / 127.5 - 1.", expression); - else if (source_type == "GLfloat") - return ByteString::formatted("static_cast({})", expression); - else if (source_type == "GLint") - return ByteString::formatted("({} + 2147483648.) / 2147483647.5 - 1.", expression); - else if (source_type == "GLshort") - return ByteString::formatted("({} + 32768.) / 32767.5 - 1.", expression); - else if (source_type == "GLubyte") - return ByteString::formatted("{} / 255.", expression); - else if (source_type == "GLuint") - return ByteString::formatted("{} / 4294967296.", expression); - else if (source_type == "GLushort") - return ByteString::formatted("{} / 65536.", expression); - VERIFY_NOT_REACHED(); -} - -Variants read_variants_settings(JsonObject const& variants_obj) -{ - Variants variants; - - if (variants_obj.has_array("argument_counts"sv)) { - variants.argument_counts.clear_with_capacity(); - variants_obj.get_array("argument_counts"sv)->for_each([&](auto const& argument_count_value) { - variants.argument_counts.append(argument_count_value.get_u32().value()); - }); - } - if (variants_obj.has_array("argument_defaults"sv)) { - variants.argument_defaults.clear_with_capacity(); - variants_obj.get_array("argument_defaults"sv)->for_each([&](auto const& argument_default_value) { - variants.argument_defaults.append(argument_default_value.as_string()); - }); - } - if (variants_obj.has_bool("convert_range"sv)) { - variants.convert_range = variants_obj.get_bool("convert_range"sv).value(); - } - if (variants_obj.has_array("api_suffixes"sv)) { - variants.api_suffixes.clear_with_capacity(); - variants_obj.get_array("api_suffixes"sv)->for_each([&](auto const& suffix_value) { - variants.api_suffixes.append(suffix_value.as_string()); - }); - } - if (variants_obj.has_string("pointer_argument"sv)) { - variants.pointer_argument = variants_obj.get_byte_string("pointer_argument"sv).value(); - } - if (variants_obj.has_object("types"sv)) { - variants.types.clear_with_capacity(); - variants_obj.get_object("types"sv)->for_each_member([&](auto const& key, auto const& type_value) { - auto const& type = type_value.as_object(); - variants.types.append(VariantType { - .encoded_type = key, - .implementation = type.get_byte_string("implementation"sv), - .unimplemented = type.get_bool("unimplemented"sv).value_or(false), - }); - }); - } - - return variants; -} - -Vector copy_arguments_for_variant(Vector arguments, Variants variants, - u32 argument_count, EncodedType encoded_type) -{ - Vector variant_arguments = arguments; - auto base_cpp_type = encoded_type.type_entry.cpp_type; - - size_t variadic_index = 0; - for (size_t i = 0; i < variant_arguments.size(); ++i) { - // Skip arguments with a fixed type - if (variant_arguments[i].cpp_type.has_value()) - continue; - - variant_arguments[i].cpp_type = encoded_type.cpp_type; - auto cast_to = variant_arguments[i].cast_to; - - // Pointer argument - if (encoded_type.is_pointer) { - variant_arguments[i].name = (variadic_index == 0) ? variants.pointer_argument : Optional {}; - - if (variadic_index >= argument_count) { - // If this variable argument is past the argument count, fall back to the defaults - variant_arguments[i].expression = variants.argument_defaults[variadic_index]; - variant_arguments[i].cast_to = Optional {}; - - } else if (argument_count == 1 && variants.argument_counts.size() == 1) { - // Otherwise, if the pointer is the only variadic argument, pass it through unchanged - variant_arguments[i].cast_to = Optional {}; - - } else { - // Otherwise, index into the pointer argument - auto indexed_expression = ByteString::formatted("{}[{}]", variants.pointer_argument, variadic_index); - if (variants.convert_range && cast_to.has_value()) - indexed_expression = wrap_expression_in_range_conversion(base_cpp_type, cast_to.value(), indexed_expression); - variant_arguments[i].expression = indexed_expression; - } - - } else { - // Regular argument - if (variadic_index >= argument_count) { - // If the variable argument is past the argument count, fall back to the defaults - variant_arguments[i].name = Optional {}; - variant_arguments[i].expression = variants.argument_defaults[variadic_index]; - variant_arguments[i].cast_to = Optional {}; - - } else if (variants.convert_range && cast_to.has_value()) { - // Otherwise, if we need to convert the input values, wrap the expression in a range conversion - variant_arguments[i].expression = wrap_expression_in_range_conversion( - base_cpp_type, - cast_to.value(), - variant_arguments[i].expression); - } - } - - // Determine if we can skip casting to the target type - if (cast_to == base_cpp_type || (variants.convert_range && cast_to == "GLdouble")) - variant_arguments[i].cast_to = Optional {}; - - variadic_index++; - } - - return variant_arguments; -} - -Vector create_function_definitions(ByteString function_name, JsonObject const& function_definition) -{ - // A single function definition can expand to multiple generated functions by way of: - // - differing API suffices (ARB, EXT, etc.); - // - differing argument counts; - // - differing argument types. - // These can all be combined. - - // Parse base argument definitions first; these may later be modified by variants - Vector argument_definitions; - JsonArray const& arguments = function_definition.get_array("arguments"sv).value_or(JsonArray {}); - arguments.for_each([&argument_definitions](auto const& argument_value) { - VERIFY(argument_value.is_object()); - auto const& argument = argument_value.as_object(); - - auto type = argument.get_byte_string("type"sv); - auto argument_names = get_name_list(argument.get("name"sv)); - auto expression = argument.get_byte_string("expression"sv).value_or("@argument_name@"); - auto cast_to = argument.get_byte_string("cast_to"sv); - - // Add an empty dummy name when all we have is an expression - if (argument_names.is_empty() && !expression.is_empty()) - argument_names.append(""); - - for (auto const& argument_name : argument_names) { - argument_definitions.append({ .name = argument_name.is_empty() ? Optional {} : argument_name, - .cpp_type = type, - .expression = expression, - .cast_to = cast_to }); - } - }); - - // Create functions for each name and/or variant - Vector functions; - - function_name = function_definition.get_byte_string("name"sv).value_or(function_name); - auto return_type = function_definition.get_byte_string("return_type"sv).value_or("void"); - auto function_implementation = function_definition.get_byte_string("implementation"sv).value_or(function_name.to_snakecase()); - auto function_unimplemented = function_definition.get_bool("unimplemented"sv).value_or(false); - - if (!function_definition.has("variants"sv)) { - functions.append({ - .name = function_name, - .return_type = return_type, - .arguments = argument_definitions, - .implementation = function_implementation, - .unimplemented = function_unimplemented, - .variant_gl_type = "", - }); - return functions; - } - - // Read variants settings for this function - auto variants_obj = function_definition.get_object("variants"sv).value(); - auto variants = read_variants_settings(variants_obj); - - for (auto argument_count : variants.argument_counts) { - for (auto const& variant_type : variants.types) { - auto encoded_type = get_encoded_type(variant_type.encoded_type); - auto variant_arguments = encoded_type.has_value() - ? copy_arguments_for_variant(argument_definitions, variants, argument_count, encoded_type.value()) - : argument_definitions; - auto variant_type_implementation = variant_type.implementation.has_value() - ? variant_type.implementation.value() - : function_implementation; - - for (auto const& api_suffix : variants.api_suffixes) { - functions.append({ - .name = ByteString::formatted( - "{}{}{}{}", - function_name, - variants.argument_counts.size() > 1 ? ByteString::formatted("{}", argument_count) : "", - encoded_type.has_value() && variants.types.size() > 1 ? encoded_type->function_name_suffix : "", - api_suffix), - .return_type = return_type, - .arguments = variant_arguments, - .implementation = variant_type_implementation, - .unimplemented = variant_type.unimplemented || function_unimplemented, - .variant_gl_type = encoded_type.has_value() ? encoded_type->type_entry.gl_type : ""sv, - }); - } - } - } - - return functions; -} - -ErrorOr generate_header_file(JsonObject& api_data, Core::File& file) -{ - StringBuilder builder; - SourceGenerator generator { builder }; - - generator.appendln("#pragma once"); - generator.append("\n"); - generator.appendln("#include "); - generator.append("\n"); - generator.appendln("#ifdef __cplusplus"); - generator.appendln("extern \"C\" {"); - generator.appendln("#endif"); - generator.append("\n"); - - api_data.for_each_member([&](auto& function_name, auto& value) { - VERIFY(value.is_object()); - auto const& function = value.as_object(); - auto function_definitions = create_function_definitions(function_name, function); - - for (auto const& function_definition : function_definitions) { - auto function_generator = generator.fork(); - - function_generator.set("name", function_definition.name); - function_generator.set("return_type", function_definition.return_type); - - function_generator.append("GLAPI @return_type@ gl@name@("); - - bool first = true; - for (auto const& argument_definition : function_definition.arguments) { - if (!argument_definition.name.has_value() || !argument_definition.cpp_type.has_value()) - continue; - - auto argument_generator = function_generator.fork(); - argument_generator.set("argument_type", argument_definition.cpp_type.value()); - argument_generator.set("argument_name", argument_definition.name.value()); - - if (!first) - argument_generator.append(", "); - first = false; - argument_generator.append("@argument_type@ @argument_name@"); - } - - function_generator.appendln(");"); - } - }); - - generator.appendln("#ifdef __cplusplus"); - generator.appendln("}"); - generator.appendln("#endif"); - - TRY(file.write_until_depleted(generator.as_string_view().bytes())); - return {}; -} - -ErrorOr generate_implementation_file(JsonObject& api_data, Core::File& file) -{ - StringBuilder builder; - SourceGenerator generator { builder }; - - generator.appendln("#include "); - generator.appendln("#include "); - generator.append("\n"); - generator.appendln("extern GL::GLContext* g_gl_context;"); - generator.append("\n"); - - api_data.for_each_member([&](auto& function_name, auto& value) { - VERIFY(value.is_object()); - JsonObject const& function = value.as_object(); - auto function_definitions = create_function_definitions(function_name, function); - - for (auto const& function_definition : function_definitions) { - auto function_generator = generator.fork(); - auto return_type = function_definition.return_type; - - function_generator.set("name"sv, function_definition.name); - function_generator.set("return_type"sv, return_type); - function_generator.set("implementation"sv, function_definition.implementation); - function_generator.set("variant_gl_type"sv, function_definition.variant_gl_type); - - function_generator.append("@return_type@ gl@name@("); - - bool first = true; - for (auto const& argument_definition : function_definition.arguments) { - if (!argument_definition.name.has_value() || !argument_definition.cpp_type.has_value()) - continue; - - auto argument_generator = function_generator.fork(); - argument_generator.set("argument_type", argument_definition.cpp_type.value()); - argument_generator.set("argument_name", argument_definition.name.value()); - - if (!first) - argument_generator.append(", "); - first = false; - argument_generator.append("@argument_type@ @argument_name@"); - } - function_generator.appendln(")"); - function_generator.appendln("{"); - - if (function_definition.unimplemented) { - function_generator.append(" dbgln(\"gl@name@("); - - first = true; - for (auto const& argument_definition : function_definition.arguments) { - if (!argument_definition.name.has_value()) - continue; - if (!first) - function_generator.append(", "); - first = false; - if (argument_definition.cpp_type.value().ends_with('*')) - function_generator.append("{:p}"); - else if (argument_definition.cpp_type.value() == "GLenum") - function_generator.append("{:#x}"); - else - function_generator.append("{}"); - } - - function_generator.append("): unimplemented\""); - - for (auto const& argument_definition : function_definition.arguments) { - if (!argument_definition.name.has_value()) - continue; - - function_generator.append(", "); - function_generator.append(argument_definition.name.value()); - } - - function_generator.appendln(");"); - function_generator.appendln(" TODO();"); - } else { - function_generator.appendln(" if (!g_gl_context)"); - if (return_type.ends_with('*')) - function_generator.appendln(" return nullptr;"); - else if (return_type == "GLboolean"sv) - function_generator.appendln(" return GL_FALSE;"); - else if (return_type == "GLenum"sv) - function_generator.appendln(" return GL_INVALID_OPERATION;"); - else if (return_type == "GLuint"sv) - function_generator.appendln(" return 0;"); - else if (return_type == "void"sv) - function_generator.appendln(" return;"); - else - VERIFY_NOT_REACHED(); - function_generator.append(" "); - if (return_type != "void"sv) - function_generator.append("return "); - function_generator.append("g_gl_context->gl_@implementation@("); - - first = true; - for (auto const& argument_definition : function_definition.arguments) { - auto argument_generator = function_generator.fork(); - - auto cast_to = argument_definition.cast_to; - argument_generator.set("argument_name", argument_definition.name.value_or("")); - argument_generator.set("cast_to", cast_to.value_or("")); - - if (!first) - argument_generator.append(", "); - first = false; - - if (cast_to.has_value()) - argument_generator.append("static_cast<@cast_to@>("); - argument_generator.append(argument_definition.expression); - if (cast_to.has_value()) - argument_generator.append(")"); - } - - function_generator.appendln(");"); - } - - function_generator.appendln("}"); - function_generator.append("\n"); - } - }); - - TRY(file.write_until_depleted(generator.as_string_view().bytes())); - return {}; -} - -ErrorOr read_entire_file_as_json(StringView filename) -{ - auto file = TRY(Core::File::open(filename, Core::File::OpenMode::Read)); - auto json_size = TRY(file->size()); - auto json_data = TRY(ByteBuffer::create_uninitialized(json_size)); - TRY(file->read_until_filled(json_data.bytes())); - return JsonValue::from_string(json_data); -} - -ErrorOr serenity_main(Main::Arguments arguments) -{ - StringView generated_header_path; - StringView generated_implementation_path; - StringView api_json_path; - - Core::ArgsParser args_parser; - args_parser.add_option(generated_header_path, "Path to the OpenGL API header file to generate", "generated-header-path", 'h', "generated-header-path"); - args_parser.add_option(generated_implementation_path, "Path to the OpenGL API implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path"); - args_parser.add_option(api_json_path, "Path to the JSON file to read from", "json-path", 'j', "json-path"); - args_parser.parse(arguments); - - auto json = TRY(read_entire_file_as_json(api_json_path)); - VERIFY(json.is_object()); - auto api_data = json.as_object(); - - auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write)); - auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write)); - - TRY(generate_header_file(api_data, *generated_header_file)); - TRY(generate_implementation_file(api_data, *generated_implementation_file)); - - return 0; -} diff --git a/Meta/check-newlines-at-eof.py b/Meta/check-newlines-at-eof.py index c79ab0cd9a3..3f6960807fd 100755 --- a/Meta/check-newlines-at-eof.py +++ b/Meta/check-newlines-at-eof.py @@ -12,12 +12,6 @@ RE_RELEVANT_FILE_EXTENSION = re.compile('\\.(cpp|h|gml|html|js|css|sh|py|json|tx def should_check_file(filename): if not RE_RELEVANT_FILE_EXTENSION.search(filename): return False - if filename.startswith('Userland/Libraries/LibCodeComprehension/Cpp/Tests/'): - return False - if filename.startswith('Userland/Libraries/LibCpp/Tests/parser/'): - return False - if filename.startswith('Userland/Libraries/LibCpp/Tests/preprocessor/'): - return False if filename.startswith('Tests/LibWeb/Layout/'): return False if filename.endswith('.txt'): diff --git a/Meta/check-style.py b/Meta/check-style.py index 17fd328e649..bdae76eb040 100755 --- a/Meta/check-style.py +++ b/Meta/check-style.py @@ -23,12 +23,7 @@ GOOD_LICENSE_HEADER_PATTERN = re.compile( LICENSE_HEADER_CHECK_EXCLUDES = { 'AK/Checked.h', 'AK/Function.h', - 'Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/', 'Userland/Libraries/LibJS/SafeFunction.h', - 'Userland/Libraries/LibELF/ELFABI.h', - 'Userland/Libraries/LibCodeComprehension/Cpp/Tests/', - 'Userland/Libraries/LibCpp/Tests/parser/', - 'Userland/Libraries/LibCpp/Tests/preprocessor/' } # We check that "#pragma once" is present @@ -53,13 +48,9 @@ SYSTEM_INCLUDE_PATTERN = re.compile("^ *# *include *<([^>]+)>(?: /[*/].*)?$") LOCAL_INCLUDE_PATTERN = re.compile('^ *# *include *"([^>]+)"(?: /[*/].*)?$') INCLUDE_CHECK_EXCLUDES = { - "Userland/Libraries/LibCodeComprehension/Cpp/Tests/", - "Userland/Libraries/LibCpp/Tests/parser/", - "Userland/Libraries/LibCpp/Tests/preprocessor/", } LOCAL_INCLUDE_ROOT_OVERRIDES = { - "Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/", } LOCAL_INCLUDE_SUFFIX_EXCLUDES = [ diff --git a/Meta/gn/secondary/AK/BUILD.gn b/Meta/gn/secondary/AK/BUILD.gn index 8ee89fc3205..bf2f6c02b53 100644 --- a/Meta/gn/secondary/AK/BUILD.gn +++ b/Meta/gn/secondary/AK/BUILD.gn @@ -201,7 +201,6 @@ shared_library("AK") { "TypeList.h", "TypedTransfer.h", "Types.h", - "UBSanitizer.h", "UFixedBigInt.h", "UFixedBigIntDivision.h", "UUID.cpp", diff --git a/Meta/gn/secondary/Kernel/BUILD.gn b/Meta/gn/secondary/Kernel/BUILD.gn deleted file mode 100644 index a42d13e5bd7..00000000000 --- a/Meta/gn/secondary/Kernel/BUILD.gn +++ /dev/null @@ -1,863 +0,0 @@ -import("//Meta/gn/build/serenity_target.gni") -import("//Meta/gn/build/sysroot.gni") -import("//Meta/gn/build/write_cmake_config.gni") - -assert(current_os == "serenity") - -declare_args() { - # Turn off optimizations and up debug symbols for the kernel only - enable_extra_kernel_debug_symbols = true - - # Enable UBSAN for kernel objects. Detects undefined behavior and traps. - enable_kernel_undefined_sanitizer = true -} - -group("Kernel") { - deps = [ ":install_kernel" ] -} - -write_cmake_config("kernel_debug_gen") { - input = "Debug.h.in" - output = "$target_gen_dir/Debug.h" - deps = [ "//AK:ak_debug_gen" ] - values = [ - "AC97_DEBUG=", - "AHCI_DEBUG=", - "ACPI_DEBUG=", - "APIC_DEBUG=", - "APIC_SMP_DEBUG=", - "ARP_DEBUG=", - "ATA_DEBUG=", - "BBFS_DEBUG=", - "BXVGA_DEBUG=", - "COMMIT_DEBUG=", - "CONTEXT_SWITCH_DEBUG=", - "DUMP_REGIONS_ON_CRASH=", - "E1000_DEBUG=", - "ETHERNET_DEBUG=", - "EXEC_DEBUG=", - "EXT2_BLOCKLIST_DEBUG=", - "EXT2_DEBUG=", - "EXT2_VERY_DEBUG=", - "FAT_DEBUG=", - "FORK_DEBUG=", - "FUTEX_DEBUG=", - "FUTEXQUEUE_DEBUG=", - "HPET_COMPARATOR_DEBUG=", - "HPET_DEBUG=", - "ICMP_DEBUG=", - "INTEL_GRAPHICS_DEBUG=", - "INTEL_HDA_DEBUG=", - "INTERRUPT_DEBUG=", - "IO_DEBUG=", - "IOAPIC_DEBUG=", - "ISO9660_DEBUG=", - "ISO9660_VERY_DEBUG=", - "IPV4_DEBUG=", - "IPV4_SOCKET_DEBUG=", - "IRQ_DEBUG=", - "KEYBOARD_DEBUG=", - "KMALLOC_DEBUG=", - "KMALLOC_VERIFY_NO_SPINLOCK_HELD=", - "LOCAL_SOCKET_DEBUG=", - "LOCK_DEBUG=", - "LOCK_IN_CRITICAL_DEBUG=", - "LOCK_RANK_ENFORCEMENT=", - "LOCK_RESTORE_DEBUG=", - "LOCK_SHARED_UPGRADE_DEBUG=", - "LOCK_TRACE_DEBUG=", - "LOOPBACK_DEBUG=", - "MASTERPTY_DEBUG=", - "MOUSE_DEBUG=", - "MEMORY_DEVICE_DEBUG=", - "MULTIPROCESSOR_DEBUG=", - "NETWORK_TASK_DEBUG=", - "NVME_DEBUG=", - "OFFD_DEBUG=", - "PAGE_FAULT_DEBUG=", - "PATA_DEBUG=", - "PCI_DEBUG=", - "POLL_SELECT_DEBUG=", - "PROCESS_DEBUG=", - "PROCFS_DEBUG=", - "PS2MOUSE_DEBUG=", - "PTMX_DEBUG=", - "ROUTING_DEBUG=", - "RTL8168_DEBUG=", - "SCHEDULER_DEBUG=", - "SCHEDULER_RUNNABLE_DEBUG=", - "SIGNAL_DEBUG=", - "SLAVEPTY_DEBUG=", - "SMP_DEBUG=", - "SOCKET_DEBUG=", - "STORAGE_DEVICE_DEBUG=", - "SYSFS_DEBUG=", - "TCP_DEBUG=", - "TCP_SOCKET_DEBUG=", - "THREAD_DEBUG=", - "TTY_DEBUG=", - "UDP_DEBUG=", - "UHCI_DEBUG=", - "UHCI_VERBOSE_DEBUG=", - "USB_DEBUG=", - "VFS_DEBUG=", - "VMWARE_BACKDOOR_DEBUG=", - "VIRTIO_DEBUG=", - "VIRTUAL_CONSOLE_DEBUG=", - "WAITBLOCK_DEBUG=", - "WAITQUEUE_DEBUG=", - ] -} - -config("Kernel_config") { - configs = [ "//AK:ak_headers" ] - include_dirs = [ "//Userland/Libraries" ] - - cflags_cc = [] - ldflags = [] - - defines = [ - "KERNEL", - "ENABLE_COMPILETIME_FORMAT_CHECK", - "SANITIZE_PTRS", - ] - - if (enable_extra_kernel_debug_symbols) { - cflags_cc += [ - "-Og", - "-ggdb3", - ] - } else { - cflags_cc += [ "-O2" ] - } - - if (enable_kernel_undefined_sanitizer) { - cflags_cc += [ "-fsanitize=undefined" ] - ldflags = [ "-fsanitize=undefined" ] - } - - cflags_cc += [ - "-fsigned-char", - "-Wno-unknown-warning-option", - "-fno-rtti", - "-ffreestanding", - "-fbuiltin", - "-fno-asynchronous-unwind-tables", - "-fstack-protector-strong", - "-fno-exceptions", - "-fno-delete-null-pointer-checks", - "-fno-semantic-interposition", - "-fsized-deallocation", - "-Wvla", - "-nostdlib", - ] - ldflags += [ - "-Wl,-z,notext", - "-nostdlib", - ] - - # Toolchain-specific flags - if (serenity_toolchain == "GNU") { - cflags_cc += [ - "-fzero-call-used-regs=used-gpr", - "-fstack-clash-protection", - "-Wno-address-of-packed-member", - "-Wno-dangling-reference", - ] - lib_dirs = [ - "$toolchain_root/$serenity_arch-pc-serenity/lib", - "$toolchain_root/lib/gcc/$serenity_arch-pc-serenity/$serenity_compiler_version", - ] - ldflags += [ "-Wl,-z,pack-relative-relocs" ] - libs = [ "gcc" ] - } else { - assert(serenity_toolchain == "Clang", "") - cflags_cc += [ - "-Wno-address-of-packed-member", - "-faligned-allocation", - "-Wno-unused-const-variable", - ] - ldflags += [ - "-Wl,--build-id=none", - "-Wl,--pack-dyn-relocs=relr", - ] - - # FIXME: Why doesn't the cmake need this path anymore? - lib_dirs = [ "$toolchain_root/lib/clang/$serenity_compiler_version/lib/$serenity_arch-pc-serenity/" ] - libs = [ "clang_rt.builtins" ] - } - - # Architecture-specific flags - if (current_cpu == "aarch64") { - cflags_cc += [ - "-mno-outline-atomics", - "-Wno-nonnull", # FIXME: Remove once MemoryManager.cpp doesn't need it - "-mgeneral-regs-only", - "-fno-threadsafe-statics", - - # Unaligned memory access will cause a trap, so to make sure the compiler doesn't generate - # those unaligned accesses, these flags are added. - "-mstrict-align", - "-Wno-cast-align", - ] - libs = [ "atomic" ] - } else if (current_cpu == "x86_64") { - cflags_cc += [ - "-mno-80387", - "-mno-mmx", - "-mno-sse", - "-mno-sse2", - - # Auto initialize trivial types on the stack, we use "pattern" as - # it's the only option portable across compilers going forward. - # - # This is designed to help avoid uninitialized variables bugs and - # information disclosures coming from the kernel stack. - # - # FIXME: It appears to conflict with something during the boot of the - # aarch64 kernel, we should investigate and remove this special case. - "-ftrivial-auto-var-init=pattern", - - "-mcmodel=large", - "-mno-red-zone", - ] - if (serenity_toolchain == "GNU") { - cflags_cc += [ - "-faligned-new=8", - "-mpreferred-stack-boundary=3", - ] - } else { - assert(serenity_toolchain == "Clang", "") - cflags_cc += [ - "-fnew-alignment=8", - "-mstack-alignment=8", - ] - } - } - - # FIXME: KCOV flags - # FIXME: Source based code coverage flags - # FIXME: KASAN/KUBSAN flags - # FIXME: IPO flags -} - -source_set("kernel_heap") { - configs += [ ":Kernel_config" ] - sources = [ "Heap/kmalloc.cpp" ] - deps = [ - ":kernel_debug_gen", - "//Userland/Libraries/LibC:install_libc_headers", - ] -} - -source_set("aarch64_no_mmu") { - deps = [ - ":kernel_debug_gen", - "//Userland/Libraries/LibC:install_libc_headers", - ] - - configs += [ ":Kernel_config" ] - sources = [ - "Arch/aarch64/Exceptions.cpp", - "Arch/aarch64/MMU.cpp", - "Arch/aarch64/RPi/MMIO.cpp", - "Arch/aarch64/pre_init.cpp", - ] - - # NOTE: These files cannot use a stack protector and sanitizers, as these will cause accesses to global variables to be inserted - # by the compiler. The CPU cannot access global variables without the MMU as the kernel is linked for a virtual address in high memory. - cflags_cc = [ - "-fno-stack-protector", - "-fno-sanitize=all", - ] -} - -source_set("mini_stdlib_sources") { - deps = [ - ":kernel_debug_gen", - "//Userland/Libraries/LibC:install_libc_headers", - ] - - configs += [ ":Kernel_config" ] - sources = [ "Library/MiniStdLib.cpp" ] - - if (serenity_toolchain == "GNU") { - # Prevent naively implemented string functions (like strlen) from being "optimized" into a call to themselves. - cflags_cc = [ - "-fno-tree-loop-distribution", - "-fno-tree-loop-distribute-patterns", - ] - } -} - -source_set("arch_sources") { - deps = [ - ":kernel_debug_gen", - "//Userland/Libraries/LibC:install_libc_headers", - "//Userland/Libraries/LibVT:generate_vt_state_machine(//Meta/gn/build/toolchain:serenity)", - ] - - configs += [ ":Kernel_config" ] - if (current_cpu == "x86_64") { - sources = [ - "Arch/Processor.cpp", - "Arch/x86_64/ASM_wrapper.cpp", - "Arch/x86_64/Boot/ap_setup.S", - "Arch/x86_64/CMOS.cpp", - "Arch/x86_64/CPU.cpp", - "Arch/x86_64/CPUID.cpp", - "Arch/x86_64/CurrentTime.cpp", - "Arch/x86_64/DebugOutput.cpp", - "Arch/x86_64/Delay.cpp", - "Arch/x86_64/Firmware/ACPI/StaticParsing.cpp", - "Arch/x86_64/Firmware/MultiProcessor/Parser.cpp", - "Arch/x86_64/Firmware/PCBIOS/Mapper.cpp", - "Arch/x86_64/Firmware/PCBIOS/SysFSComponent.cpp", - "Arch/x86_64/Firmware/PCBIOS/SysFSDirectory.cpp", - "Arch/x86_64/Hypervisor/BochsDisplayConnector.cpp", - "Arch/x86_64/Hypervisor/VMWareBackdoor.cpp", - "Arch/x86_64/I8042Reboot.cpp", - "Arch/x86_64/ISABus/HID/VMWareMouseDevice.cpp", - "Arch/x86_64/ISABus/I8042Controller.cpp", - "Arch/x86_64/ISABus/SerialDevice.cpp", - "Arch/x86_64/InterruptEntry.cpp", - "Arch/x86_64/InterruptManagement.cpp", - "Arch/x86_64/Interrupts.cpp", - "Arch/x86_64/Interrupts/APIC.cpp", - "Arch/x86_64/Interrupts/IOAPIC.cpp", - "Arch/x86_64/Interrupts/PIC.cpp", - "Arch/x86_64/PCI/Controller/PIIX4HostBridge.cpp", - "Arch/x86_64/PCI/Initializer.cpp", - "Arch/x86_64/PCI/MSI.cpp", - "Arch/x86_64/PCSpeaker.cpp", - "Arch/x86_64/PageDirectory.cpp", - "Arch/x86_64/PowerState.cpp", - "Arch/x86_64/Processor.cpp", - "Arch/x86_64/ProcessorInfo.cpp", - "Arch/x86_64/RTC.cpp", - "Arch/x86_64/SafeMem.cpp", - "Arch/x86_64/Shutdown.cpp", - "Arch/x86_64/SmapDisabler.cpp", - "Arch/x86_64/SyscallEntry.cpp", - "Arch/x86_64/Time/APICTimer.cpp", - "Arch/x86_64/Time/HPET.cpp", - "Arch/x86_64/Time/HPETComparator.cpp", - "Arch/x86_64/Time/PIT.cpp", - "Arch/x86_64/Time/RTC.cpp", - "Arch/x86_64/TrapFrame.cpp", - "Arch/x86_64/VGA/IOArbiter.cpp", - - # TODO: Share these with the aarch64 build - "Interrupts/SpuriousInterruptHandler.cpp", - "kprintf.cpp", - ] - } else { - assert(current_cpu == "aarch64", "") - deps = [ ":aarch64_no_mmu" ] - sources = [ - "Arch/Processor.cpp", - "Arch/aarch64/BootPPMParser.cpp", - "Arch/aarch64/CPUID.cpp", - "Arch/aarch64/CurrentTime.cpp", - "Arch/aarch64/Dummy.cpp", - "Arch/aarch64/Firmware/ACPI/StaticParsing.cpp", - "Arch/aarch64/InterruptManagement.cpp", - "Arch/aarch64/Interrupts.cpp", - "Arch/aarch64/MainIdRegister.cpp", - "Arch/aarch64/PageDirectory.cpp", - "Arch/aarch64/Panic.cpp", - "Arch/aarch64/PowerState.cpp", - "Arch/aarch64/Processor.cpp", - "Arch/aarch64/RPi/DebugOutput.cpp", - "Arch/aarch64/RPi/Framebuffer.cpp", - "Arch/aarch64/RPi/GPIO.cpp", - "Arch/aarch64/RPi/InterruptController.cpp", - "Arch/aarch64/RPi/Mailbox.cpp", - "Arch/aarch64/RPi/MiniUART.cpp", - "Arch/aarch64/RPi/SDHostController.cpp", - "Arch/aarch64/RPi/Timer.cpp", - "Arch/aarch64/RPi/UART.cpp", - "Arch/aarch64/RPi/Watchdog.cpp", - "Arch/aarch64/SafeMem.cpp", - "Arch/aarch64/SmapDisabler.cpp", - "Arch/aarch64/TrapFrame.cpp", - "Arch/aarch64/boot.S", - "Arch/aarch64/kprintf.cpp", - "Arch/aarch64/vector_table.S", - ] - } -} - -source_set("lib_sources") { - deps = [ - ":kernel_debug_gen", - "//Userland/Libraries/LibC:install_libc_headers", - "//Userland/Libraries/LibVT:generate_vt_state_machine(//Meta/gn/build/toolchain:serenity)", - ] - - configs += [ ":Kernel_config" ] - sources = [ - "//AK/DOSPackedTime.cpp", - "//AK/Error.cpp", - "//AK/Format.cpp", - "//AK/GenericLexer.cpp", - "//AK/Hex.cpp", - "//AK/MemoryStream.cpp", - "//AK/Stream.cpp", - "//AK/StringBuilder.cpp", - "//AK/StringUtils.cpp", - "//AK/StringView.cpp", - "//AK/Time.cpp", - "//AK/UUID.cpp", - "//Userland/Libraries/LibCrypto/Cipher/AES.cpp", - "//Userland/Libraries/LibCrypto/Hash/SHA2.cpp", - "//Userland/Libraries/LibEDID/DMT.cpp", - "//Userland/Libraries/LibEDID/EDID.cpp", - "//Userland/Libraries/LibEDID/VIC.cpp", - "//Userland/Libraries/LibELF/Image.cpp", - "//Userland/Libraries/LibELF/Validation.cpp", - "//Userland/Libraries/LibPartition/DiskPartitionMetadata.cpp", - "//Userland/Libraries/LibPartition/EBRPartitionTable.cpp", - "//Userland/Libraries/LibPartition/GUIDPartitionTable.cpp", - "//Userland/Libraries/LibPartition/MBRPartitionTable.cpp", - "//Userland/Libraries/LibPartition/PartitionTable.cpp", - "//Userland/Libraries/LibPartition/PartitionableDevice.cpp", - "//Userland/Libraries/LibVT/EscapeSequenceParser.cpp", - "//Userland/Libraries/LibVT/Line.cpp", - "//Userland/Libraries/LibVT/Terminal.cpp", - ] -} - -action("generate_version_header") { - script = "//Meta/gn/secondary/Kernel/generate_version_header.py" - outputs = [ "$target_gen_dir/Version.h" ] - args = [ rebase_path(outputs[0], root_build_dir) ] -} - -if (current_cpu == "x86_64") { - action("preprocess_linker_script") { - script = "//Meta/gn/build/invoke_process_with_args.py" - inputs = [ "Arch/x86_64/linker.ld" ] - outputs = [ "$target_gen_dir/linker.ld" ] - args = [ - "$serenity_cxx", - "-E", - "-P", - "-x", - "c", - rebase_path(inputs[0], root_build_dir), - "-o", - rebase_path(outputs[0], root_build_dir), - ] - } -} - -executable("Kernel_bin") { - configs += [ ":Kernel_config" ] - deps = [ - ":arch_sources", - ":generate_version_header", - ":kernel_debug_gen", - ":kernel_heap", - ":lib_sources", - ":mini_stdlib_sources", - "//Userland/Libraries/LibC:install_libc_headers", - ] - ldflags = [ "-static-pie" ] - if (serenity_arch == "x86_64") { - deps += [ ":preprocess_linker_script" ] - ldflags += - [ "-Wl,-T," + rebase_path("$target_gen_dir/linker.ld", root_build_dir) ] - } else { - assert(serenity_arch == "aarch64") - ldflags += - [ "-Wl,-T," + rebase_path("Arch/aarch64/linker.ld", root_build_dir) ] - } - sources = [ - "Arch/DeferredCallPool.cpp", - "Arch/PageFault.cpp", - "Arch/init.cpp", - "Boot/CommandLine.cpp", - "Bus/PCI/API.cpp", - "Bus/PCI/Access.cpp", - "Bus/PCI/Controller/HostController.cpp", - "Bus/PCI/Controller/MemoryBackedHostBridge.cpp", - "Bus/PCI/Controller/VolumeManagementDevice.cpp", - "Bus/PCI/Device.cpp", - "Bus/PCI/DeviceIdentifier.cpp", - "Bus/USB/UHCI/UHCIController.cpp", - "Bus/USB/UHCI/UHCIRootHub.cpp", - "Bus/USB/USBConfiguration.cpp", - "Bus/USB/USBController.cpp", - "Bus/USB/USBDevice.cpp", - "Bus/USB/USBHub.cpp", - "Bus/USB/USBManagement.cpp", - "Bus/USB/USBPipe.cpp", - "Bus/USB/USBTransfer.cpp", - "Bus/VirtIO/Device.cpp", - "Bus/VirtIO/Queue.cpp", - "Devices/AsyncDeviceRequest.cpp", - "Devices/Audio/AC97/AC97.cpp", - "Devices/Audio/Channel.cpp", - "Devices/Audio/IntelHDA/Codec.cpp", - "Devices/Audio/IntelHDA/Controller.cpp", - "Devices/Audio/IntelHDA/Format.cpp", - "Devices/Audio/IntelHDA/InterruptHandler.cpp", - "Devices/Audio/IntelHDA/Stream.cpp", - "Devices/Audio/Management.cpp", - "Devices/BlockDevice.cpp", - "Devices/CharacterDevice.cpp", - "Devices/Device.cpp", - "Devices/DeviceManagement.cpp", - "Devices/GPU/Bochs/GraphicsAdapter.cpp", - "Devices/GPU/Bochs/QEMUDisplayConnector.cpp", - "Devices/GPU/Console/BootFramebufferConsole.cpp", - "Devices/GPU/Console/ContiguousFramebufferConsole.cpp", - "Devices/GPU/Console/GenericFramebufferConsole.cpp", - "Devices/GPU/DisplayConnector.cpp", - "Devices/GPU/Generic/DisplayConnector.cpp", - "Devices/GPU/Intel/Auxiliary/GMBusConnector.cpp", - "Devices/GPU/Intel/DisplayConnectorGroup.cpp", - "Devices/GPU/Intel/NativeDisplayConnector.cpp", - "Devices/GPU/Intel/NativeGraphicsAdapter.cpp", - "Devices/GPU/Intel/Plane/DisplayPlane.cpp", - "Devices/GPU/Intel/Plane/G33DisplayPlane.cpp", - "Devices/GPU/Intel/Transcoder/AnalogDisplayTranscoder.cpp", - "Devices/GPU/Intel/Transcoder/DisplayTranscoder.cpp", - "Devices/GPU/Intel/Transcoder/PLL.cpp", - "Devices/GPU/Management.cpp", - "Devices/GPU/VMWare/Console.cpp", - "Devices/GPU/VMWare/DisplayConnector.cpp", - "Devices/GPU/VMWare/GraphicsAdapter.cpp", - "Devices/GPU/VirtIO/Console.cpp", - "Devices/GPU/VirtIO/DisplayConnector.cpp", - "Devices/GPU/VirtIO/GPU3DDevice.cpp", - "Devices/GPU/VirtIO/GraphicsAdapter.cpp", - "Devices/Generic/ConsoleDevice.cpp", - "Devices/Generic/DeviceControlDevice.cpp", - "Devices/Generic/FullDevice.cpp", - "Devices/Generic/MemoryDevice.cpp", - "Devices/Generic/NullDevice.cpp", - "Devices/Generic/RandomDevice.cpp", - "Devices/Generic/SelfTTYDevice.cpp", - "Devices/Generic/ZeroDevice.cpp", - "Devices/HID/KeyboardDevice.cpp", - "Devices/HID/Management.cpp", - "Devices/HID/MouseDevice.cpp", - "Devices/HID/PS2/KeyboardDevice.cpp", - "Devices/HID/PS2/MouseDevice.cpp", - "Devices/KCOVDevice.cpp", - "Devices/KCOVInstance.cpp", - "Devices/Serial/VirtIO/Console.cpp", - "Devices/Serial/VirtIO/ConsolePort.cpp", - "Devices/SerialDevice.cpp", - "Devices/Storage/AHCI/ATAController.cpp", - "Devices/Storage/AHCI/ATADevice.cpp", - "Devices/Storage/AHCI/ATADiskDevice.cpp", - "Devices/Storage/AHCI/Controller.cpp", - "Devices/Storage/AHCI/InterruptHandler.cpp", - "Devices/Storage/AHCI/Port.cpp", - "Devices/Storage/DiskPartition.cpp", - "Devices/Storage/NVMe/NVMeController.cpp", - "Devices/Storage/NVMe/NVMeInterruptQueue.cpp", - "Devices/Storage/NVMe/NVMeNameSpace.cpp", - "Devices/Storage/NVMe/NVMePollQueue.cpp", - "Devices/Storage/NVMe/NVMeQueue.cpp", - "Devices/Storage/SD/PCISDHostController.cpp", - "Devices/Storage/SD/SDHostController.cpp", - "Devices/Storage/SD/SDMemoryCard.cpp", - "Devices/Storage/StorageController.cpp", - "Devices/Storage/StorageDevice.cpp", - "Devices/Storage/StorageManagement.cpp", - "FileSystem/AnonymousFile.cpp", - "FileSystem/BlockBasedFileSystem.cpp", - "FileSystem/Custody.cpp", - "FileSystem/DevPtsFS/FileSystem.cpp", - "FileSystem/DevPtsFS/Inode.cpp", - "FileSystem/Ext2FS/FileSystem.cpp", - "FileSystem/Ext2FS/Inode.cpp", - "FileSystem/FATFS/FileSystem.cpp", - "FileSystem/FATFS/Inode.cpp", - "FileSystem/FIFO.cpp", - "FileSystem/File.cpp", - "FileSystem/FileBackedFileSystem.cpp", - "FileSystem/FileSystem.cpp", - "FileSystem/ISO9660FS/DirectoryIterator.cpp", - "FileSystem/ISO9660FS/FileSystem.cpp", - "FileSystem/ISO9660FS/Inode.cpp", - "FileSystem/Inode.cpp", - "FileSystem/InodeFile.cpp", - "FileSystem/InodeMetadata.cpp", - "FileSystem/InodeWatcher.cpp", - "FileSystem/Mount.cpp", - "FileSystem/MountFile.cpp", - "FileSystem/OpenFileDescription.cpp", - "FileSystem/Plan9FS/FileSystem.cpp", - "FileSystem/Plan9FS/Inode.cpp", - "FileSystem/Plan9FS/Message.cpp", - "FileSystem/ProcFS/FileSystem.cpp", - "FileSystem/ProcFS/Inode.cpp", - "FileSystem/ProcFS/ProcessExposed.cpp", - "FileSystem/RAMFS/FileSystem.cpp", - "FileSystem/RAMFS/Inode.cpp", - "FileSystem/SysFS/Component.cpp", - "FileSystem/SysFS/DirectoryInode.cpp", - "FileSystem/SysFS/FileSystem.cpp", - "FileSystem/SysFS/Inode.cpp", - "FileSystem/SysFS/LinkInode.cpp", - "FileSystem/SysFS/Registry.cpp", - "FileSystem/SysFS/RootDirectory.cpp", - "FileSystem/SysFS/Subsystems/Bus/Directory.cpp", - "FileSystem/SysFS/Subsystems/Bus/PCI/BusDirectory.cpp", - "FileSystem/SysFS/Subsystems/Bus/PCI/DeviceAttribute.cpp", - "FileSystem/SysFS/Subsystems/Bus/PCI/DeviceDirectory.cpp", - "FileSystem/SysFS/Subsystems/Bus/PCI/DeviceExpansionROM.cpp", - "FileSystem/SysFS/Subsystems/Bus/USB/BusDirectory.cpp", - "FileSystem/SysFS/Subsystems/Bus/USB/DeviceInformation.cpp", - "FileSystem/SysFS/Subsystems/DeviceIdentifiers/BlockDevicesDirectory.cpp", - "FileSystem/SysFS/Subsystems/DeviceIdentifiers/CharacterDevicesDirectory.cpp", - "FileSystem/SysFS/Subsystems/DeviceIdentifiers/DeviceComponent.cpp", - "FileSystem/SysFS/Subsystems/DeviceIdentifiers/Directory.cpp", - "FileSystem/SysFS/Subsystems/DeviceIdentifiers/SymbolicLinkDeviceComponent.cpp", - "FileSystem/SysFS/Subsystems/Devices/Directory.cpp", - "FileSystem/SysFS/Subsystems/Devices/Graphics/Directory.cpp", - "FileSystem/SysFS/Subsystems/Devices/Graphics/DisplayConnector/DeviceAttribute.cpp", - "FileSystem/SysFS/Subsystems/Devices/Graphics/DisplayConnector/DeviceDirectory.cpp", - "FileSystem/SysFS/Subsystems/Devices/Graphics/DisplayConnector/Directory.cpp", - "FileSystem/SysFS/Subsystems/Devices/Storage/DeviceAttribute.cpp", - "FileSystem/SysFS/Subsystems/Devices/Storage/DeviceDirectory.cpp", - "FileSystem/SysFS/Subsystems/Devices/Storage/Directory.cpp", - "FileSystem/SysFS/Subsystems/Firmware/Directory.cpp", - "FileSystem/SysFS/Subsystems/Kernel/CPUInfo.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Constants/ConstantInformation.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Constants/Directory.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Directory.cpp", - "FileSystem/SysFS/Subsystems/Kernel/DiskUsage.cpp", - "FileSystem/SysFS/Subsystems/Kernel/GlobalInformation.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Interrupts.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Jails.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Keymap.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Log.cpp", - "FileSystem/SysFS/Subsystems/Kernel/MemoryStatus.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Network/ARP.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Network/Adapters.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Network/Directory.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Network/Local.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Network/Route.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Network/TCP.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Network/UDP.cpp", - "FileSystem/SysFS/Subsystems/Kernel/PowerStateSwitch.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Processes.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Profile.cpp", - "FileSystem/SysFS/Subsystems/Kernel/RequestPanic.cpp", - "FileSystem/SysFS/Subsystems/Kernel/SystemStatistics.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Uptime.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Variables/CapsLockRemap.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Variables/CoredumpDirectory.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Variables/Directory.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Variables/DumpKmallocStack.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Variables/StringVariable.cpp", - "FileSystem/SysFS/Subsystems/Kernel/Variables/UBSANDeadly.cpp", - "FileSystem/VirtualFileSystem.cpp", - "Firmware/ACPI/Initialize.cpp", - "Firmware/ACPI/Parser.cpp", - "Firmware/ACPI/StaticParsing.cpp", - "Interrupts/GenericInterruptHandler.cpp", - "Interrupts/IRQHandler.cpp", - "Interrupts/PCIIRQHandler.cpp", - "Interrupts/SharedIRQHandler.cpp", - "Interrupts/UnhandledInterruptHandler.cpp", - "KSyms.cpp", - "Library/DoubleBuffer.cpp", - "Library/IOWindow.cpp", - "Library/KBufferBuilder.cpp", - "Library/KLexicalPath.cpp", - "Library/KString.cpp", - "Library/Panic.cpp", - "Library/ScopedCritical.cpp", - "Library/StdLib.cpp", - "Library/UserOrKernelBuffer.cpp", - "Locking/LockRank.cpp", - "Locking/Mutex.cpp", - "Memory/AddressSpace.cpp", - "Memory/AnonymousVMObject.cpp", - "Memory/InodeVMObject.cpp", - "Memory/MemoryManager.cpp", - "Memory/PhysicalPage.cpp", - "Memory/PhysicalRegion.cpp", - "Memory/PhysicalZone.cpp", - "Memory/PrivateInodeVMObject.cpp", - "Memory/Region.cpp", - "Memory/RegionTree.cpp", - "Memory/RingBuffer.cpp", - "Memory/ScatterGatherList.cpp", - "Memory/ScopedAddressSpaceSwitcher.cpp", - "Memory/SharedFramebufferVMObject.cpp", - "Memory/SharedInodeVMObject.cpp", - "Memory/VMObject.cpp", - "Memory/VirtualRange.cpp", - "Net/IPv4Socket.cpp", - "Net/Intel/E1000ENetworkAdapter.cpp", - "Net/Intel/E1000NetworkAdapter.cpp", - "Net/LocalSocket.cpp", - "Net/LoopbackAdapter.cpp", - "Net/NetworkAdapter.cpp", - "Net/NetworkTask.cpp", - "Net/NetworkingManagement.cpp", - "Net/Realtek/RTL8168NetworkAdapter.cpp", - "Net/Routing.cpp", - "Net/Socket.cpp", - "Net/TCPSocket.cpp", - "Net/UDPSocket.cpp", - "Net/VirtIO/VirtIONetworkAdapter.cpp", - "SanCov.cpp", - "Security/AddressSanitizer.cpp", - "Security/Credentials.cpp", - "Security/Jail.cpp", - "Security/Random.cpp", - "Security/Random/VirtIO/RNG.cpp", - "Security/UBSanitizer.cpp", - "Syscalls/SyscallHandler.cpp", - "Syscalls/alarm.cpp", - "Syscalls/anon_create.cpp", - "Syscalls/beep.cpp", - "Syscalls/chdir.cpp", - "Syscalls/chmod.cpp", - "Syscalls/chown.cpp", - "Syscalls/clock.cpp", - "Syscalls/debug.cpp", - "Syscalls/disown.cpp", - "Syscalls/dup2.cpp", - "Syscalls/emuctl.cpp", - "Syscalls/execve.cpp", - "Syscalls/exit.cpp", - "Syscalls/faccessat.cpp", - "Syscalls/fallocate.cpp", - "Syscalls/fcntl.cpp", - "Syscalls/fork.cpp", - "Syscalls/fsync.cpp", - "Syscalls/ftruncate.cpp", - "Syscalls/futex.cpp", - "Syscalls/get_dir_entries.cpp", - "Syscalls/get_stack_bounds.cpp", - "Syscalls/getrandom.cpp", - "Syscalls/getuid.cpp", - "Syscalls/hostname.cpp", - "Syscalls/inode_watcher.cpp", - "Syscalls/ioctl.cpp", - "Syscalls/jail.cpp", - "Syscalls/keymap.cpp", - "Syscalls/kill.cpp", - "Syscalls/link.cpp", - "Syscalls/lseek.cpp", - "Syscalls/mkdir.cpp", - "Syscalls/mknod.cpp", - "Syscalls/mmap.cpp", - "Syscalls/mount.cpp", - "Syscalls/open.cpp", - "Syscalls/perf_event.cpp", - "Syscalls/pipe.cpp", - "Syscalls/pledge.cpp", - "Syscalls/poll.cpp", - "Syscalls/prctl.cpp", - "Syscalls/process.cpp", - "Syscalls/profiling.cpp", - "Syscalls/ptrace.cpp", - "Syscalls/purge.cpp", - "Syscalls/read.cpp", - "Syscalls/readlink.cpp", - "Syscalls/realpath.cpp", - "Syscalls/rename.cpp", - "Syscalls/resource.cpp", - "Syscalls/rmdir.cpp", - "Syscalls/sched.cpp", - "Syscalls/sendfd.cpp", - "Syscalls/setpgid.cpp", - "Syscalls/setuid.cpp", - "Syscalls/sigaction.cpp", - "Syscalls/socket.cpp", - "Syscalls/stat.cpp", - "Syscalls/statvfs.cpp", - "Syscalls/sync.cpp", - "Syscalls/sysconf.cpp", - "Syscalls/thread.cpp", - "Syscalls/times.cpp", - "Syscalls/umask.cpp", - "Syscalls/uname.cpp", - "Syscalls/unlink.cpp", - "Syscalls/unveil.cpp", - "Syscalls/utime.cpp", - "Syscalls/utimensat.cpp", - "Syscalls/waitid.cpp", - "Syscalls/write.cpp", - "TTY/ConsoleManagement.cpp", - "TTY/MasterPTY.cpp", - "TTY/PTYMultiplexer.cpp", - "TTY/SlavePTY.cpp", - "TTY/TTY.cpp", - "TTY/VirtualConsole.cpp", - "Tasks/Coredump.cpp", - "Tasks/CrashHandler.cpp", - "Tasks/FinalizerTask.cpp", - "Tasks/FutexQueue.cpp", - "Tasks/PerformanceEventBuffer.cpp", - "Tasks/PowerStateSwitchTask.cpp", - "Tasks/Process.cpp", - "Tasks/ProcessGroup.cpp", - "Tasks/ProcessList.cpp", - "Tasks/Scheduler.cpp", - "Tasks/SyncTask.cpp", - "Tasks/Thread.cpp", - "Tasks/ThreadBlockers.cpp", - "Tasks/ThreadTracer.cpp", - "Tasks/WaitQueue.cpp", - "Tasks/WorkQueue.cpp", - "Time/TimeManagement.cpp", - "Time/TimerQueue.cpp", - ] - sources += get_target_outputs(":generate_version_header") -} - -action("postprocess_kernel") { - script = "//Meta/gn/secondary/Kernel/post_process_kernel.py" - deps = [ ":Kernel_bin" ] - inputs = [ "$target_out_dir/Kernel_bin" ] - outputs = [ - "$target_out_dir/Kernel", - "$target_out_dir/Kernel.debug", - "$target_out_dir/kernel.map", - ] - args = [ - "--nm", - serenity_nm, - "--objcopy", - serenity_objcopy, - rebase_path(inputs[0], root_build_dir), - ] -} - -group("install_kernel") { - deps = [ - ":install_kernel_binaries", - ":install_kernel_data", - ] - if (serenity_arch == "x86_64") { - deps += [ "Prekernel:install_prekernel" ] - } -} - -copy("install_kernel_binaries") { - deps = [ ":postprocess_kernel" ] - sources = [ - "$target_out_dir/Kernel", - "$target_out_dir/Kernel.debug", - ] - outputs = [ "$sysroot/boot/{{source_file_part}}" ] -} - -copy("install_kernel_data") { - deps = [ ":postprocess_kernel" ] - sources = [ "$target_out_dir/kernel.map" ] - outputs = [ "$sysroot/res/{{source_file_part}}" ] -} diff --git a/Meta/gn/secondary/Kernel/Prekernel/BUILD.gn b/Meta/gn/secondary/Kernel/Prekernel/BUILD.gn deleted file mode 100644 index 1a0d50e4ad3..00000000000 --- a/Meta/gn/secondary/Kernel/Prekernel/BUILD.gn +++ /dev/null @@ -1,51 +0,0 @@ -import("//Meta/gn/build/serenity_target.gni") -import("//Meta/gn/build/sysroot.gni") - -assert(current_os == "serenity") -assert(current_cpu == "x86_64") - -group("Prekernel") { - deps = [ ":install_prekernel" ] -} - -executable("Prekernel_bin") { - configs += [ "//Kernel:Kernel_config" ] - deps = [ "//Userland/Libraries/LibC:install_libc_headers" ] - cflags = [ - "-fno-pic", - "-fno-pie", - ] - ldflags = [ - "-static", - "-fno-pie", - "-Wl,-T" + rebase_path("linker.ld", root_build_dir), - ] - sources = [ - "//Kernel//Library/MiniStdLib.cpp", - "//Userland/Libraries/LibELF/Relocation.cpp", - "UBSanitizer.cpp", - "boot.S", - "init.cpp", - "multiboot.S", - ] -} - -action("postprocess_prekernel") { - script = "//Meta/gn/build/invoke_process_with_args.py" - inputs = [ "$target_out_dir/Prekernel_bin" ] - outputs = [ "$target_gen_dir/Prekernel" ] - deps = [ ":Prekernel_bin" ] - args = [ - "$serenity_objcopy", - "-O", - "elf32-i386", - rebase_path(inputs[0], root_build_dir), - rebase_path(outputs[0], root_build_dir), - ] -} - -copy("install_prekernel") { - deps = [ ":postprocess_prekernel" ] - sources = [ "$target_gen_dir/Prekernel" ] - outputs = [ "$sysroot/boot/{{source_file_part}}" ] -} diff --git a/Meta/gn/secondary/Kernel/generate_version_header.py b/Meta/gn/secondary/Kernel/generate_version_header.py deleted file mode 100755 index a7ff40f23a8..00000000000 --- a/Meta/gn/secondary/Kernel/generate_version_header.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 - -import subprocess -import sys - -short_hash = subprocess.check_output(['git', 'rev-parse', '--short=8', 'HEAD']).decode().strip() -if subprocess.check_output(['git', 'status', '--porcelain=v2']) and short_hash: - short_hash += "-modified" - -if not short_hash: - short_hash = "unknown" - -with open(sys.argv[1], 'w') as f: - f.write(fr'''/* - * Automatically generated by Kernel/generate_version_header.py - */ - -#pragma once -#include - -namespace Kernel {{ - -constexpr unsigned SERENITY_MAJOR_REVISION = 1; -constexpr unsigned SERENITY_MINOR_REVISION = 0; -constexpr StringView SERENITY_VERSION = "{short_hash}"sv; - -}} -''') diff --git a/Meta/gn/secondary/Kernel/post_process_kernel.py b/Meta/gn/secondary/Kernel/post_process_kernel.py deleted file mode 100644 index 26eae91aa17..00000000000 --- a/Meta/gn/secondary/Kernel/post_process_kernel.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import shutil -import subprocess -import sys -from functools import cmp_to_key -from pathlib import Path - - -def main(): - parser = argparse.ArgumentParser( - epilog=__doc__, - formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument('kernel', help='kernel binary location') - parser.add_argument('-n', '--nm', required=True, help='path to nm') - parser.add_argument('-o', '--objcopy', required=True, help='path to objcopy') - args = parser.parse_args() - - kernel_path = Path(args.kernel) - binary_directory = kernel_path.parent - - # Write out kernel.map, which contains kernel symbols and their addresses - symbols = subprocess.check_output([args.nm, '-C', '-n', str(kernel_path)]) - if not symbols: - print(f"Unable to dump symbols from {kernel_path}", file=sys.stderr) - return 1 - - def filter_symbol(s): - return s and not (".Lubsan_data" in s or s.split()[1] == "a") - - symbols = filter(filter_symbol, symbols.decode().split('\n')) - symbols = list(set(symbols)) - - def sort_symbols(s1, s2): - return int(s1.split()[0], base=16) - int(s2.split()[0], base=16) - symbols = sorted(symbols, key=cmp_to_key(sort_symbols)) - - kernel_map = binary_directory / "kernel.map" - with open(kernel_map, 'w') as out: - out.write(f'{len(symbols):#x}\n') - out.write('\n'.join(symbols)) - out.write('\0') - - kernel_final = binary_directory / "Kernel" - - shutil.copyfile(kernel_path, kernel_final) - - kernel_final = str(kernel_final) - - subprocess.check_call([args.objcopy, "--update-section", f".ksyms={kernel_map}", kernel_final]) - subprocess.check_call([args.objcopy, "--only-keep-debug", kernel_final, kernel_final + ".debug"]) - subprocess.check_call([args.objcopy, "--strip-debug", kernel_final]) - subprocess.check_call([args.objcopy, f"--add-gnu-debuglink={kernel_final}.debug", kernel_final]) - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/Meta/gn/secondary/Ladybird/BUILD.gn b/Meta/gn/secondary/Ladybird/BUILD.gn index f533cc6189a..b9e09dfc6f1 100644 --- a/Meta/gn/secondary/Ladybird/BUILD.gn +++ b/Meta/gn/secondary/Ladybird/BUILD.gn @@ -385,17 +385,12 @@ if (current_os != "mac") { "//Userland/Libraries/LibCrypto", "//Userland/Libraries/LibDiff", "//Userland/Libraries/LibFileSystem", - "//Userland/Libraries/LibGL", - "//Userland/Libraries/LibGLSL", - "//Userland/Libraries/LibGPU", - "//Userland/Libraries/LibGUI", "//Userland/Libraries/LibGemini", "//Userland/Libraries/LibGfx", "//Userland/Libraries/LibHTTP", "//Userland/Libraries/LibIDL", "//Userland/Libraries/LibIPC", "//Userland/Libraries/LibImageDecoderClient", - "//Userland/Libraries/LibJIT", "//Userland/Libraries/LibJS", "//Userland/Libraries/LibLine", "//Userland/Libraries/LibMarkdown", @@ -403,7 +398,6 @@ if (current_os != "mac") { "//Userland/Libraries/LibRIFF", "//Userland/Libraries/LibRegex", "//Userland/Libraries/LibSQL", - "//Userland/Libraries/LibSoftGPU", "//Userland/Libraries/LibSyntax", "//Userland/Libraries/LibTLS", "//Userland/Libraries/LibTextCodec", @@ -428,22 +422,16 @@ if (current_os != "mac") { "$root_out_dir/lib/liblagom-filesystem.dylib", "$root_out_dir/lib/liblagom-gemini.dylib", "$root_out_dir/lib/liblagom-gfx.dylib", - "$root_out_dir/lib/liblagom-gl.dylib", - "$root_out_dir/lib/liblagom-glsl.dylib", - "$root_out_dir/lib/liblagom-gpu.dylib", - "$root_out_dir/lib/liblagom-gui.dylib", "$root_out_dir/lib/liblagom-http.dylib", "$root_out_dir/lib/liblagom-idl.dylib", "$root_out_dir/lib/liblagom-imagedecoderclient.dylib", "$root_out_dir/lib/liblagom-ipc.dylib", - "$root_out_dir/lib/liblagom-jit.dylib", "$root_out_dir/lib/liblagom-js.dylib", "$root_out_dir/lib/liblagom-line.dylib", "$root_out_dir/lib/liblagom-markdown.dylib", "$root_out_dir/lib/liblagom-protocol.dylib", "$root_out_dir/lib/liblagom-regex.dylib", "$root_out_dir/lib/liblagom-riff.dylib", - "$root_out_dir/lib/liblagom-softgpu.dylib", "$root_out_dir/lib/liblagom-sql.dylib", "$root_out_dir/lib/liblagom-syntax.dylib", "$root_out_dir/lib/liblagom-textcodec.dylib", diff --git a/Meta/gn/secondary/Meta/Lagom/Contrib/MacPDF/BUILD.gn b/Meta/gn/secondary/Meta/Lagom/Contrib/MacPDF/BUILD.gn deleted file mode 100644 index a1d00ba7fb3..00000000000 --- a/Meta/gn/secondary/Meta/Lagom/Contrib/MacPDF/BUILD.gn +++ /dev/null @@ -1,108 +0,0 @@ -import("//Meta/gn/build/mac/compile_xib_resources.gni") - -assert(current_os == "mac", "This application is macOS specific") - -group("MacPDF") { - deps = [ ":MacPDF.app" ] -} - -compile_xib_resources("pdf_nibs") { - sources = [ "MainMenu.xib" ] -} - -executable("MacPDF_executable") { - include_dirs = [ - "//Userland/Libraries", - "//Userland/Services", - ] - defines = [ "AK_DONT_REPLACE_STD" ] - cflags_objcc = [ "-fobjc-arc" ] - deps = [ - ":pdf_nibs", - "//AK", - "//Userland/Libraries/LibCore", - "//Userland/Libraries/LibGfx", - "//Userland/Libraries/LibPDF", - ] - frameworks = [ - "Cocoa.framework", - "UniformTypeIdentifiers.framework", - ] - sources = [ - "AppDelegate.mm", - "MacPDFDocument.mm", - "MacPDFOutlineViewDataSource.mm", - "MacPDFView.mm", - "MacPDFWindowController.mm", - "main.mm", - ] - output_name = "MacPDF" -} - -bundle_data("pdf_bundle_info_plist") { - sources = [ "Info.plist" ] - outputs = [ "{{bundle_contents_dir}}/Info.plist" ] -} - -bundle_data("pdf_bundle_executables") { - public_deps = [ ":MacPDF_executable" ] - sources = [ "$root_out_dir/bin/MacPDF" ] - outputs = [ "{{bundle_executable_dir}}/{{source_file_part}}" ] -} - -bundle_data("pdf_bundle_libs") { - public_deps = [ - "//AK", - "//Userland/Libraries/LibCompress", - "//Userland/Libraries/LibCore", - "//Userland/Libraries/LibCrypto", - "//Userland/Libraries/LibFileSystem", - "//Userland/Libraries/LibGfx", - "//Userland/Libraries/LibIPC", - "//Userland/Libraries/LibPDF", - "//Userland/Libraries/LibRIFF", - "//Userland/Libraries/LibTextCodec", - ] - sources = [ - "$root_out_dir/lib/liblagom-ak.dylib", - "$root_out_dir/lib/liblagom-compress.dylib", - "$root_out_dir/lib/liblagom-core.dylib", - "$root_out_dir/lib/liblagom-crypto.dylib", - "$root_out_dir/lib/liblagom-filesystem.dylib", - "$root_out_dir/lib/liblagom-gfx.dylib", - "$root_out_dir/lib/liblagom-ipc.dylib", - "$root_out_dir/lib/liblagom-pdf.dylib", - "$root_out_dir/lib/liblagom-riff.dylib", - "$root_out_dir/lib/liblagom-textcodec.dylib", - ] - outputs = [ "{{bundle_contents_dir}}/lib/{{source_file_part}}" ] -} - -bundle_data("pdf_bundle_nibs") { - public_deps = [ ":pdf_nibs" ] - sources = get_target_outputs(":pdf_nibs") - outputs = [ "{{bundle_resources_dir}}" + "{{source_file_part}}" ] -} - -bundle_data("pdf_resources") { - # FIXME: Don't list directories here, list out the files directly - sources = [ "//Base/res/fonts" ] - outputs = [ "{{bundle_resources_dir}}/res/" + "{{source_file_part}}" ] -} - -create_bundle("MacPDF.app") { - product_type = "com.apple.product-type.application" - - bundle_root_dir = "$root_build_dir/$target_name" - bundle_contents_dir = "$bundle_root_dir/Contents" - bundle_resources_dir = "$bundle_contents_dir/Resources" - bundle_executable_dir = "$bundle_contents_dir/MacOS" - - deps = [ - ":pdf_bundle_executables", - ":pdf_bundle_info_plist", - ":pdf_bundle_libs", - ":pdf_bundle_nibs", - ":pdf_resources", - ] -} diff --git a/Meta/gn/secondary/Userland/Libraries/LibC/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibC/BUILD.gn deleted file mode 100644 index 7f2e47f460e..00000000000 --- a/Meta/gn/secondary/Userland/Libraries/LibC/BUILD.gn +++ /dev/null @@ -1,21 +0,0 @@ -import("//Meta/gn/build/sysroot.gni") -import("libc_headers.gni") - -copy("install_libelf_sysroot_headers") { - sources = [ "../LibELF/ELFABI.h" ] - outputs = [ "$sysroot/usr/include/LibELF/{{source_file_part}}" ] -} - -copy("install_libregex_sysroot_headers") { - sources = [ "../LibRegex/RegexDefs.h" ] - outputs = [ "$sysroot/usr/include/LibRegex/{{source_file_part}}" ] -} - -copy("install_libc_headers") { - deps = [ - ":install_libelf_sysroot_headers", - ":install_libregex_sysroot_headers", - ] - sources = libc_headers - outputs = [ "$sysroot/usr/include/{{source_target_relative}}" ] -} diff --git a/Meta/gn/secondary/Userland/Libraries/LibC/libc_headers.gni b/Meta/gn/secondary/Userland/Libraries/LibC/libc_headers.gni deleted file mode 100644 index 655ec51ac65..00000000000 --- a/Meta/gn/secondary/Userland/Libraries/LibC/libc_headers.gni +++ /dev/null @@ -1,118 +0,0 @@ -libc_headers = [ - "time.h", - "semaphore.h", - "pwd.h", - "utime.h", - "termcap.h", - "pty.h", - "inttypes.h", - "resolv.h", - "stdlib.h", - "ulimit.h", - "net/route.h", - "net/if_arp.h", - "net/if.h", - "float.h", - "locale.h", - "langinfo.h", - "limits.h", - "fd_set.h", - "endian.h", - "unistd.h", - "wctype.h", - "fcntl.h", - "signal.h", - "dirent.h", - "stdio_ext.h", - "spawn.h", - "regex.h", - "arpa/inet.h", - "syslog.h", - "netinet/tcp.h", - "netinet/ip_icmp.h", - "netinet/if_ether.h", - "netinet/in.h", - "netinet/ip.h", - "netinet/in_systm.h", - "libgen.h", - "setjmp.h", - "elf.h", - "getopt.h", - "dlfcn.h", - "strings.h", - "fnmatch.h", - "errno_codes.h", - "serenity.h", - "byteswap.h", - "alloca.h", - "sys/time.h", - "sys/ioctl.h", - "sys/statvfs.h", - "sys/uio.h", - "sys/types.h", - "sys/times.h", - "sys/wait.h", - "sys/file.h", - "sys/stat.h", - "sys/internals.h", - "sys/mman.h", - "sys/un.h", - "sys/utsname.h", - "sys/auxv.h", - "sys/sysmacros.h", - "sys/param.h", - "sys/prctl.h", - "sys/ptrace.h", - "sys/arch/regs.h", - "sys/arch/aarch64/regs.h", - "sys/arch/x86_64/regs.h", - "sys/ttydefaults.h", - "sys/resource.h", - "sys/cdefs.h", - "sys/poll.h", - "sys/socket.h", - "sys/select.h", - "utmp.h", - "bits/stdio_file_implementation.h", - "bits/wchar_size.h", - "bits/pthread_cancel.h", - "bits/sighow.h", - "bits/FILE.h", - "bits/posix1_lim.h", - "bits/pthread_integration.h", - "bits/wchar.h", - "bits/mutex_locker.h", - "bits/utimens.h", - "bits/dlfcn_integration.h", - "bits/search.h", - "bits/stdint.h", - "fenv.h", - "grp.h", - "mallocdefs.h", - "ctype.h", - "nl_types.h", - "paths.h", - "wchar.h", - "mntent.h", - "sched.h", - "shadow.h", - "netdb.h", - "pthread.h", - "math.h", - "memory.h", - "errno.h", - "termios.h", - "poll.h", - "stdio.h", - "stdarg.h", - "link.h", - "search.h", - "assert.h", - "glob.h", - "ifaddrs.h", - "stdint.h", - "complex.h", - "ucontext.h", - "sysexits.h", - "string.h", -] diff --git a/Meta/gn/secondary/Userland/Libraries/LibELF/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibELF/BUILD.gn deleted file mode 100644 index ba5621203eb..00000000000 --- a/Meta/gn/secondary/Userland/Libraries/LibELF/BUILD.gn +++ /dev/null @@ -1,22 +0,0 @@ -shared_library("LibELF") { - output_name = "elf" - include_dirs = [ "//Userland/Libraries" ] - sources = [ - "AuxiliaryVector.h", - "Core.h", - "ELFABI.h", - "ELFBuild.cpp", - "ELFBuild.h", - "Hashes.h", - "Image.cpp", - "Image.h", - "Relocation.cpp", - "Relocation.h", - "Validation.cpp", - "Validation.h", - ] - deps = [ - "//AK", - "//Userland/Libraries/LibCore", - ] -} diff --git a/Meta/gn/secondary/Userland/Libraries/LibGL/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibGL/BUILD.gn deleted file mode 100644 index fa3a04d6674..00000000000 --- a/Meta/gn/secondary/Userland/Libraries/LibGL/BUILD.gn +++ /dev/null @@ -1,58 +0,0 @@ -import("//Meta/gn/build/compiled_action.gni") - -compiled_action("generate_glapi") { - tool = "//Meta/Lagom/Tools/CodeGenerators/LibGL:GenerateGLAPIWrapper" - inputs = [ "GLAPI.json" ] - outputs = [ - "$target_gen_dir/GL/glapi.h", - "$target_gen_dir/GLAPI.cpp", - ] - args = [ - "-h", - rebase_path(outputs[0], root_build_dir), - "-c", - rebase_path(outputs[1], root_build_dir), - "-j", - rebase_path(inputs[0], root_build_dir), - ] - - # FIXME: install header into $prefix/include/LibGL/GL on serenity -} - -config("gl_headers") { - include_dirs = [ "$target_gen_dir/.." ] -} - -shared_library("LibGL") { - output_name = "gl" - include_dirs = [ "//Userland/Libraries" ] - public_configs = [ ":gl_headers" ] - sources = [ - "Blending.cpp", - "Buffer.cpp", - "Buffer/Buffer.cpp", - "ClipPlane.cpp", - "ContextParameter.cpp", - "GLContext.cpp", - "Image.cpp", - "Lighting.cpp", - "List.cpp", - "Matrix.cpp", - "NameAllocator.cpp", - "Shader.cpp", - "Shaders/Program.cpp", - "Shaders/Shader.cpp", - "Stencil.cpp", - "Tex/Texture2D.cpp", - "Texture.cpp", - "Vertex.cpp", - ] - sources += get_target_outputs(":generate_glapi") - deps = [ - ":generate_glapi", - "//AK", - "//Userland/Libraries/LibGLSL", - "//Userland/Libraries/LibGPU", - "//Userland/Libraries/LibGfx", - ] -} diff --git a/Meta/gn/secondary/Userland/Libraries/LibGLSL/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibGLSL/BUILD.gn deleted file mode 100644 index f2306593e23..00000000000 --- a/Meta/gn/secondary/Userland/Libraries/LibGLSL/BUILD.gn +++ /dev/null @@ -1,13 +0,0 @@ -shared_library("LibGLSL") { - output_name = "glsl" - include_dirs = [ "//Userland/Libraries" ] - sources = [ - "Compiler.cpp", - "Linker.cpp", - ] - deps = [ - "//AK", - "//Userland/Libraries/LibCore", - "//Userland/Libraries/LibGPU", - ] -} diff --git a/Meta/gn/secondary/Userland/Libraries/LibGPU/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibGPU/BUILD.gn deleted file mode 100644 index 2ca1f5da896..00000000000 --- a/Meta/gn/secondary/Userland/Libraries/LibGPU/BUILD.gn +++ /dev/null @@ -1,18 +0,0 @@ -shared_library("LibGPU") { - output_name = "gpu" - include_dirs = [ "//Userland/Libraries" ] - sources = [ - "Driver.cpp", - "Image.cpp", - ] - deps = [ "//AK" ] - - # FIXME: express this dependency properly to avoid cycles - # we want to make sure that LibSoftGPU is built when LibGPU is needed - #data_deps = [ "//Userland/Libraries/LibSoftGPU" ] - if (current_os == "serenity") { - #data_deps += [ "//Userland/Libraries/LibVirtGPU" ] - } else if (current_os == "linux") { - libs = [ "dl" ] - } -} diff --git a/Meta/gn/secondary/Userland/Libraries/LibGUI/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibGUI/BUILD.gn deleted file mode 100644 index a2cf2afcbc0..00000000000 --- a/Meta/gn/secondary/Userland/Libraries/LibGUI/BUILD.gn +++ /dev/null @@ -1,24 +0,0 @@ -# FIXME: Add serenity-only deps and sources - -shared_library("LibGUI") { - output_name = "gui" - include_dirs = [ - "//Userland/Libraries", - "//Userland", - ] - sources = [ - "GML/Lexer.cpp", - "GML/Parser.cpp", - "GML/SyntaxHighlighter.cpp", - "Icon.cpp", - "Model.cpp", - "ModelIndex.cpp", - ] - deps = [ - "//AK", - "//Userland/Libraries/LibCore", - "//Userland/Libraries/LibGfx", - "//Userland/Libraries/LibSyntax", - "//Userland/Libraries/LibURL", - ] -} diff --git a/Meta/gn/secondary/Userland/Libraries/LibJIT/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibJIT/BUILD.gn deleted file mode 100644 index acd45f974a5..00000000000 --- a/Meta/gn/secondary/Userland/Libraries/LibJIT/BUILD.gn +++ /dev/null @@ -1,18 +0,0 @@ -shared_library("LibJIT") { - output_name = "jit" - include_dirs = [ "//Userland/Libraries" ] - sources = [ - "Assembler.cpp", - "Assembler.h", - "GDB.cpp", - "GDB.h", - ] - deps = [ "//AK" ] - - if (current_os == "mac") { - sources += [ "GDBUnsupported.cpp" ] - } else { - sources += [ "GDBElf.cpp" ] - deps += [ "//Userland/Libraries/LibELF" ] - } -} diff --git a/Meta/gn/secondary/Userland/Libraries/LibPDF/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibPDF/BUILD.gn deleted file mode 100644 index 41f66687f9e..00000000000 --- a/Meta/gn/secondary/Userland/Libraries/LibPDF/BUILD.gn +++ /dev/null @@ -1,38 +0,0 @@ -shared_library("LibPDF") { - output_name = "pdf" - include_dirs = [ "//Userland/Libraries" ] - sources = [ - "ColorSpace.cpp", - "CommonNames.cpp", - "Document.cpp", - "DocumentParser.cpp", - "Encoding.cpp", - "Encryption.cpp", - "Filter.cpp", - "Fonts/CFF.cpp", - "Fonts/PDFFont.cpp", - "Fonts/PS1FontProgram.cpp", - "Fonts/SimpleFont.cpp", - "Fonts/TrueTypeFont.cpp", - "Fonts/Type0Font.cpp", - "Fonts/Type1Font.cpp", - "Fonts/Type1FontProgram.cpp", - "Fonts/Type3Font.cpp", - "Function.cpp", - "Interpolation.cpp", - "ObjectDerivatives.cpp", - "Page.cpp", - "Parser.cpp", - "Reader.cpp", - "Renderer.cpp", - "Value.cpp", - ] - deps = [ - "//AK", - "//Userland/Libraries/LibCompress", - "//Userland/Libraries/LibCrypto", - "//Userland/Libraries/LibGfx", - "//Userland/Libraries/LibIPC", - "//Userland/Libraries/LibTextCodec", - ] -} diff --git a/Meta/gn/secondary/Userland/Libraries/LibSoftGPU/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibSoftGPU/BUILD.gn deleted file mode 100644 index 5daf2b1fbe1..00000000000 --- a/Meta/gn/secondary/Userland/Libraries/LibSoftGPU/BUILD.gn +++ /dev/null @@ -1,21 +0,0 @@ -shared_library("LibSoftGPU") { - output_name = "softgpu" - include_dirs = [ "//Userland/Libraries" ] - cflags_cc = [ "-Wno-psabi" ] - sources = [ - "Clipper.cpp", - "Device.cpp", - "Image.cpp", - "PixelConverter.cpp", - "Sampler.cpp", - "Shader.cpp", - "ShaderCompiler.cpp", - "ShaderProcessor.cpp", - ] - deps = [ - "//AK", - "//Userland/Libraries/LibCore", - "//Userland/Libraries/LibGPU", - "//Userland/Libraries/LibGfx", - ] -} diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibWeb/BUILD.gn index def7442f8d5..866ad034356 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWeb/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/BUILD.gn @@ -364,8 +364,6 @@ shared_library("LibWeb") { "//Userland/Libraries/LibAudio", "//Userland/Libraries/LibCore", "//Userland/Libraries/LibCrypto", - "//Userland/Libraries/LibGL", - "//Userland/Libraries/LibGUI", "//Userland/Libraries/LibGemini", "//Userland/Libraries/LibGfx", "//Userland/Libraries/LibHTTP", @@ -375,7 +373,6 @@ shared_library("LibWeb") { "//Userland/Libraries/LibLocale", "//Userland/Libraries/LibMarkdown", "//Userland/Libraries/LibRegex", - "//Userland/Libraries/LibSoftGPU", "//Userland/Libraries/LibSyntax", "//Userland/Libraries/LibTLS", "//Userland/Libraries/LibTextCodec", diff --git a/Meta/gn/secondary/Userland/Libraries/LibX86/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibX86/BUILD.gn deleted file mode 100644 index 82383778489..00000000000 --- a/Meta/gn/secondary/Userland/Libraries/LibX86/BUILD.gn +++ /dev/null @@ -1,16 +0,0 @@ -shared_library("LibX86") { - output_name = "x86" - include_dirs = [ "//Userland/Libraries" ] - - deps = [ - "//AK", - "//Userland/Libraries/LibCore", - ] - sources = [ - "Disassembler.h", - "ELFSymbolProvider.h", - "Instruction.cpp", - "Instruction.h", - "Interpreter.h", - ] -} diff --git a/Meta/test_pdf.py b/Meta/test_pdf.py deleted file mode 100755 index 97ec554a49e..00000000000 --- a/Meta/test_pdf.py +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/env python3 - -'''Runs `pdf --debugging-stats` on a bunch of PDF files in parallel. - -Give it one or more folders containing PDF files, and the optional -n flag -to pick a random subset of n PDFs: - - test_pdf.py -n 200 ~/Downloads/0000 ~/src/pdffiles - -https://pdfa.org/new-large-scale-pdf-corpus-now-publicly-available/ has -8 TB of test PDFs, organized in a bunch of zip files with 1000 PDFs each. -One of those zip files in unzipped makes for a good input folder. -''' - -import argparse -import collections -import dataclasses -import glob -import json -import multiprocessing -import os -import random -import re -import subprocess - - -Result = collections.namedtuple( - 'Result', ['filename', 'returncode', 'stdout', 'stderr']) - - -@dataclasses.dataclass -class Issues: - filenames: [str] - filename_to_issues: {str: [int]} - num_pages: int - count: int - - -def elide_aslr(s): - return re.sub(rb'\b0x[0-9a-f]+\b', b'0xc3ns0r3d', s) - - -def elide_parser_offset(s): - return re.sub(rb'\bParser error at offset [0-9]+:', b'Parser error:', s) - - -def test_pdf(filename): - pdf_path = os.path.join(os.path.dirname(__file__), '../Build/lagom/bin/pdf') - r = subprocess.run([pdf_path, '--debugging-stats', '--json', filename], - capture_output=True) - return Result(filename, r.returncode, r.stdout, - elide_parser_offset(elide_aslr(r.stderr))) - - -def main(): - parser = argparse.ArgumentParser( - epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter - ) - parser.add_argument('input', nargs='+', help='input directories') - parser.add_argument('-n', type=int, help='render at most n pdfs') - args = parser.parse_args() - - files = [] - for input_directory in args.input: - files += glob.glob(os.path.join(input_directory, '*.pdf')) - if args.n is not None: - random.seed(42) - files = random.sample(files, k=args.n) - - results = multiprocessing.Pool().map(test_pdf, files) - - num_files_without_issues = 0 - num_files_with_password = 0 - num_files_with_issues = 0 - failed_files = [] - num_crashes = 0 - stack_to_files = {} - issues = {} - for r in results: - if r.returncode == 0: - if b'PDF requires password' in r.stderr: - num_files_with_password += 1 - continue - - j = json.loads(r.stdout.decode('utf-8')) - if not j['issues']: - num_files_without_issues += 1 - else: - num_files_with_issues += 1 - for diag in j['issues']: - issue = issues.setdefault(diag, Issues([], {}, 0, 0)) - issue.filenames.append(r.filename) - issue.filename_to_issues[r.filename] = j['issues'][diag] - issue.num_pages += len(j['issues'][diag]) - issue.count += sum(count for (page, count) in j['issues'][diag]) - continue - if r.returncode == 1: - failed_files.append(r.filename) - else: - num_crashes += 1 - stack_to_files.setdefault(r.stderr, []).append(r.filename) - - percent = 100 * num_files_with_issues / len(results) - print(f'{len(issues)} distinct issues, in {num_files_with_issues} files ({percent}%):') - issue_keys = list(issues.keys()) - issue_keys.sort(reverse=True, key=lambda x: len(issues[x].filenames)) - for issue_key in issue_keys: - issue = issues[issue_key] - print(issue_key, end='') - print(f', in {len(issue.filenames)} files, on {issue.num_pages} pages, {issue.count} times') - filenames = sorted(issue.filenames, reverse=True, key=lambda x: len(issue.filename_to_issues[x])) - for filename in filenames: - page_counts = issue.filename_to_issues[filename] - page_counts = ' '.join([f'{page} ({count}x)' if count > 1 else f'{page}' for (page, count) in page_counts]) - print(f' {filename} {page_counts}') - print() - print() - - print('Stacks:') - keys = list(stack_to_files.keys()) - keys.sort(key=lambda x: len(stack_to_files[x]), reverse=True) - for stack in reversed(keys): - files = stack_to_files[stack] - print(stack.decode('utf-8', 'backslashreplace'), end='') - print(f'In {len(files)} files:') - for file in files: - print(f' {file}') - print() - - percent = 100 * num_crashes / len(results) - print(f'{num_crashes} crashes ({percent:.1f}%)') - print(f'{len(keys)} distinct crash stacks') - - percent = 100 * len(failed_files) / len(results) - print() - print(f'{len(failed_files)} failed to open ({percent:.1f}%)') - for f in failed_files: - print(f' {f}') - print() - - percent = 100 * num_files_with_password / len(results) - print(f'{num_files_with_password} files with password ({percent:.1f}%)') - print() - - percent = 100 * num_files_without_issues / len(results) - print(f'{num_files_without_issues} files without issues ({percent:.1f}%)') - print() - - -if __name__ == '__main__': - main() diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 705039bd967..77b0506be23 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1,22 +1,13 @@ add_subdirectory(AK) -add_subdirectory(Kernel) add_subdirectory(LibAudio) -add_subdirectory(LibC) add_subdirectory(LibCompress) add_subdirectory(LibCore) -add_subdirectory(LibCpp) add_subdirectory(LibDiff) -add_subdirectory(LibELF) add_subdirectory(LibGfx) -add_subdirectory(LibGL) -add_subdirectory(LibGLSL) -add_subdirectory(LibIMAP) add_subdirectory(LibJS) add_subdirectory(LibLocale) add_subdirectory(LibMarkdown) -add_subdirectory(LibPDF) add_subdirectory(LibRegex) -add_subdirectory(LibSemVer) add_subdirectory(LibSQL) add_subdirectory(LibTest) add_subdirectory(LibTextCodec) @@ -31,5 +22,3 @@ add_subdirectory(LibWebView) add_subdirectory(LibXML) add_subdirectory(LibCrypto) add_subdirectory(LibTLS) -add_subdirectory(Spreadsheet) -add_subdirectory(Utilities) diff --git a/Tests/JSSpecCompiler/CMakeLists.txt b/Tests/JSSpecCompiler/CMakeLists.txt deleted file mode 100644 index 93d591d7d20..00000000000 --- a/Tests/JSSpecCompiler/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -lagom_test( - test-runner.cpp - NAME TestJSSpecCompiler - LIBS LibDiff - WORKING_DIRECTORY "${SERENITY_PROJECT_ROOT}/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/" -) diff --git a/Tests/JSSpecCompiler/test-runner.cpp b/Tests/JSSpecCompiler/test-runner.cpp deleted file mode 100644 index 1f641a9fa23..00000000000 --- a/Tests/JSSpecCompiler/test-runner.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2023, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct TestDescription { - struct Flag { - StringView name; - bool dump_ast = false; - bool dump_cfg = false; - }; - - Vector sources; - Vector flags; -}; - -constexpr StringView stderr_capture_filename = "stderr"sv; - -constexpr StringView compiler_binary_name = "JSSpecCompiler"sv; -constexpr StringView relative_path_to_test = "Tests"sv; - -constexpr TestDescription::Flag always_dump_all = { - .name = "all"sv, - .dump_ast = true, - .dump_cfg = true -}; - -constexpr TestDescription::Flag dump_after_frontend = { - .name = "reference-resolving"sv, - .dump_ast = true, - .dump_cfg = false -}; - -Array const regression_tests = { - TestDescription { - .sources = { "simple.cpp"sv }, - .flags = { always_dump_all }, - }, - TestDescription { - .sources = { - "spec-headers.xml"sv, - "spec-no-new-line-after-dot.xml"sv, - "spec-optional-arguments.xml"sv, - "spec-parsing.xml"sv, - "spec-single-function-simple.xml"sv, - }, - .flags = { dump_after_frontend }, - } -}; - -static LexicalPath const path_to_compiler_binary = [] { - auto path_to_self = LexicalPath(MUST(Core::System::current_executable_path())).parent(); - return LexicalPath::join(path_to_self.string(), compiler_binary_name); -}(); -static LexicalPath const path_to_tests_directory { relative_path_to_test }; - -Vector build_command_line_arguments(LexicalPath const& test_source, TestDescription const& description) -{ - Vector result; - - StringBuilder dump_ast_option; - StringBuilder dump_cfg_option; - - for (auto const& flag : description.flags) { - if (flag.dump_ast) { - if (!dump_ast_option.is_empty()) - dump_ast_option.append(","sv); - dump_ast_option.append(flag.name); - } - if (flag.dump_cfg) { - if (!dump_cfg_option.is_empty()) - dump_cfg_option.append(","sv); - dump_cfg_option.append(flag.name); - } - } - if (!dump_ast_option.is_empty()) - result.append(ByteString::formatted("--dump-ast={}", dump_ast_option.string_view())); - if (!dump_cfg_option.is_empty()) - result.append(ByteString::formatted("--dump-cfg={}", dump_cfg_option.string_view())); - - if (test_source.has_extension(".cpp"sv)) - result.append("-xc++"sv); - - result.append("--silence-diagnostics"sv); - - result.append(test_source.string()); - - return result; -} - -ErrorOr read(LexicalPath const& path) -{ - auto file = TRY(Core::File::open(path.string(), Core::File::OpenMode::Read)); - return MUST(file->read_until_eof()); -} - -void check_expectations(LexicalPath const& path_to_expectation, LexicalPath const& path_to_captured_output, bool should_update_expectations) -{ - struct PathPair { - LexicalPath expectation; - LexicalPath result; - }; - Vector file_pairs_to_check; - - file_pairs_to_check.append({ - .expectation = path_to_expectation, - .result = path_to_captured_output, - }); - - auto out = MUST(Core::File::standard_error()); - - for (auto const& [expectation_path, result_path] : file_pairs_to_check) { - auto result_content = read(result_path); - - if (should_update_expectations && !result_content.is_error()) { - using namespace FileSystem; - MUST(copy_file_or_directory(expectation_path.string(), result_path.string(), - RecursionMode::Disallowed, LinkMode::Disallowed, AddDuplicateFileMarker::No)); - } - - auto expectation = read(expectation_path); - - bool read_successfully = !(expectation.is_error() || result_content.is_error()); - EXPECT(read_successfully); - - if (read_successfully) { - bool are_equal = expectation.value() == result_content.value(); - EXPECT(are_equal); - - if (!are_equal) { - dbgln("Files {} and {} do not match!", expectation_path.string(), result_path.string()); - auto maybe_diff = Diff::from_text(expectation.value(), result_content.value()); - if (!maybe_diff.is_error()) { - for (auto const& hunk : maybe_diff.value()) - MUST(Diff::write_unified(hunk, *out, Diff::ColorOutput::Yes)); - } - } - } - } -} - -TEST_CASE(test_regression) -{ - auto* update_expectations_env = getenv("JSSC_UPDATE_EXPECTATIONS"); - - bool should_update_expectations = false; - if (update_expectations_env != nullptr && strcmp(update_expectations_env, "1") == 0) - should_update_expectations = true; - - auto temp_directory = MUST(FileSystem::TempFile::create_temp_directory()); - - auto path_to_captured_stderr = LexicalPath::join(temp_directory->path(), stderr_capture_filename); - - for (auto const& test_description : regression_tests) { - for (auto const& source : test_description.sources) { - dbgln("Running {}...", source); - - auto path_to_test = LexicalPath::join(path_to_tests_directory.string(), source); - auto path_to_expectation = LexicalPath::join(path_to_tests_directory.string(), ByteString::formatted("{}.expectation", source)); - - auto process = MUST(Core::Process::spawn({ - .executable = path_to_compiler_binary.string(), - .arguments = build_command_line_arguments(path_to_test, test_description), - .file_actions = { - Core::FileAction::OpenFile { - .path = path_to_captured_stderr.string(), - .mode = Core::File::OpenMode::Write, - .fd = STDERR_FILENO, - }, - }, - })); - - bool exited_with_code_0 = MUST(process.wait_for_termination()); - EXPECT(exited_with_code_0); - - if (!exited_with_code_0) { - auto captured_output = read(path_to_captured_stderr); - if (!captured_output.is_error()) { - StringView stderr_output_view = captured_output.value(); - dbgln("Compiler invocation failed. Captured output:\n{}", stderr_output_view); - } - } else { - check_expectations(path_to_expectation, path_to_captured_stderr, should_update_expectations); - } - } - } -} diff --git a/Tests/LibCpp/CMakeLists.txt b/Tests/LibCpp/CMakeLists.txt deleted file mode 100644 index 1dd7bbe6342..00000000000 --- a/Tests/LibCpp/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -set(TEST_SOURCES - test-cpp-parser.cpp - test-cpp-preprocessor.cpp -) - -foreach(source IN LISTS TEST_SOURCES) - serenity_test("${source}" LibCpp LIBS LibCpp) -endforeach() diff --git a/Tests/LibCpp/test-cpp-parser.cpp b/Tests/LibCpp/test-cpp-parser.cpp deleted file mode 100644 index a1f8249e8e9..00000000000 --- a/Tests/LibCpp/test-cpp-parser.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include - -constexpr StringView TESTS_ROOT_DIR = "/home/anon/Tests/cpp-tests/parser"sv; - -static ByteString read_all(ByteString const& path) -{ - auto file = MUST(Core::File::open(path, Core::File::OpenMode::Read)); - auto file_size = MUST(file->size()); - auto content = MUST(ByteBuffer::create_uninitialized(file_size)); - MUST(file->read_until_filled(content.bytes())); - return ByteString { content.bytes() }; -} - -TEST_CASE(test_regression) -{ - MUST(Core::Directory::for_each_entry(TESTS_ROOT_DIR, Core::DirIterator::Flags::SkipDots, [](auto const& entry, auto const& directory) -> ErrorOr { - auto path = LexicalPath::join(directory.path().string(), entry.name); - if (!path.has_extension(".cpp"sv)) - return IterationDecision::Continue; - - outln("Checking {}...", path.basename()); - auto file_path = path.string(); - - auto ast_file_path = ByteString::formatted("{}.ast", file_path.substring(0, file_path.length() - sizeof(".cpp") + 1)); - - auto source = read_all(file_path); - auto target_ast = read_all(ast_file_path); - - StringView source_view(source); - Cpp::Preprocessor preprocessor(file_path, source_view); - Cpp::Parser parser(preprocessor.process_and_lex(), file_path); - auto root = parser.parse(); - - EXPECT(parser.errors().is_empty()); - - int pipefd[2] = {}; - if (pipe(pipefd) < 0) { - perror("pipe"); - exit(1); - } - - FILE* input_stream = fdopen(pipefd[0], "r"); - FILE* output_stream = fdopen(pipefd[1], "w"); - - root->dump(output_stream); - - fclose(output_stream); - - ByteBuffer buffer; - while (!feof(input_stream)) { - char chunk[4096]; - size_t size = fread(chunk, sizeof(char), sizeof(chunk), input_stream); - if (size == 0) - break; - buffer.append(chunk, size); - } - - fclose(input_stream); - - ByteString content { reinterpret_cast(buffer.data()), buffer.size() }; - - auto equal = content == target_ast; - EXPECT(equal); - return IterationDecision::Continue; - })); -} diff --git a/Tests/LibCpp/test-cpp-preprocessor.cpp b/Tests/LibCpp/test-cpp-preprocessor.cpp deleted file mode 100644 index 51bea505df3..00000000000 --- a/Tests/LibCpp/test-cpp-preprocessor.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include - -constexpr StringView TESTS_ROOT_DIR = "/home/anon/Tests/cpp-tests/preprocessor"sv; - -static ByteString read_all(ByteString const& path) -{ - auto file = MUST(Core::File::open(path, Core::File::OpenMode::Read)); - auto file_size = MUST(file->size()); - auto content = MUST(ByteBuffer::create_uninitialized(file_size)); - MUST(file->read_until_filled(content.bytes())); - return ByteString { content.bytes() }; -} - -TEST_CASE(test_regression) -{ - MUST(Core::Directory::for_each_entry(TESTS_ROOT_DIR, Core::DirIterator::Flags::SkipDots, [](auto const& entry, auto const& directory) -> ErrorOr { - auto path = LexicalPath::join(directory.path().string(), entry.name); - if (!path.has_extension(".cpp"sv)) - return IterationDecision::Continue; - - outln("Checking {}...", path.basename()); - auto file_path = path.string(); - - auto ast_file_path = ByteString::formatted("{}.txt", file_path.substring(0, file_path.length() - sizeof(".cpp") + 1)); - - auto source = read_all(file_path); - auto target = read_all(ast_file_path); - - StringView source_view(source); - Cpp::Preprocessor preprocessor(file_path, source_view); - - auto target_lines = target.split_view('\n'); - auto tokens = preprocessor.process_and_lex(); - - EXPECT_EQ(tokens.size(), target_lines.size()); - for (size_t i = 0; i < tokens.size(); ++i) { - EXPECT_EQ(tokens[i].to_byte_string(), target_lines[i]); - } - return IterationDecision::Continue; - })); -} diff --git a/Tests/LibELF/CMakeLists.txt b/Tests/LibELF/CMakeLists.txt deleted file mode 100644 index 4b7e434f7c8..00000000000 --- a/Tests/LibELF/CMakeLists.txt +++ /dev/null @@ -1,104 +0,0 @@ -set(CMAKE_SKIP_RPATH FALSE) -if (NOT BUILD_LAGOM) - set(CMAKE_INSTALL_RPATH "$ORIGIN:$ORIGIN/../lib") - set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) -else() - set(CMAKE_BUILD_RPATH "$ORIGIN:$ORIGIN/../lib") - set(CMAKE_INSTALL_RPATH "$ORIGIN:$ORIGIN/../lib") -endif() - -macro(add_test_lib NAME FILE) - add_library(${NAME} SHARED ${FILE}) - if (NOT BUILD_LAGOM) - serenity_set_implicit_links(${NAME}) - else() - target_link_libraries(${NAME} PRIVATE AK LibCore) - endif() - install(TARGETS ${NAME} DESTINATION usr/Tests/LibELF) -endmacro() - -macro(add_test_exe NAME FILE) - add_executable(${NAME} ${FILE}) - if (NOT BUILD_LAGOM) - serenity_set_implicit_links(${NAME}) - else() - target_link_libraries(${NAME} PRIVATE AK LibCore) - endif() - install(TARGETS ${NAME} DESTINATION usr/Tests/LibELF) -endmacro() - -macro(add_dlopen_lib NAME FUNCTION) - add_test_lib(${NAME} Dynlib.cpp) - target_compile_definitions(${NAME} PRIVATE -DFUNCTION=${FUNCTION}) - # LibLine is not special, just an "external" dependency - target_link_libraries(${NAME} PRIVATE LibLine) -endmacro() - -macro(target_link_manual TARGET LIB) - target_link_libraries(${TARGET} PRIVATE -Wl,--push-state,--no-as-needed $ -Wl,--pop-state) - add_dependencies(${TARGET} ${LIB}) -endmacro() - -set(TEST_SOURCES - TestDlOpen.cpp - TestOrder.cpp - TestTLS.cpp - TestWeakSymbolResolution.cpp -) - -foreach(source IN LISTS TEST_SOURCES) - if (NOT BUILD_LAGOM) - serenity_test("${source}" LibELF) - else() - get_filename_component(test_name ${source} NAME_WE) - lagom_test("${source}" WORKING_DIRECTORY "$") - # FIXME: Figure out why on Ubuntu 22.04 dlopen ignores RUNPATH in executable. - set_tests_properties(${test_name} PROPERTIES ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) - endif() -endforeach() - -# test-elf.cpp -if (NOT BUILD_LAGOM) - serenity_test(test-elf.cpp LibELF) -endif() - -# TestDlOpen.cpp -add_dlopen_lib(DynlibA dynliba_function) -add_dlopen_lib(DynlibB dynlibb_function) - -add_dlopen_lib(DynlibC dynlibc_function) -add_dlopen_lib(DynlibD dynlibd_function) -target_link_manual(DynlibD DynlibC) - -# TestTLS.cpp -add_test_lib(TLSDef TLSDef.cpp) -add_test_lib(TLSUse TLSUse.cpp) -target_compile_options(TLSUse PRIVATE -ftls-model=global-dynamic) -target_link_libraries(TLSUse PRIVATE LibCore LibTest LibThreading TLSDef) -target_link_libraries(TestTLS PRIVATE TLSUse) - -# TestWeakSymbolResolution.cpp -add_test_lib(TestWeakSymbolResolution1 TestWeakSymbolResolution1.cpp) -add_test_lib(TestWeakSymbolResolution2 TestWeakSymbolResolution2.cpp) -target_link_manual(TestWeakSymbolResolution TestWeakSymbolResolution1) -target_link_manual(TestWeakSymbolResolution TestWeakSymbolResolution2) - -# TestOrder.cpp -add_test_lib(TestOrderLib1 TestOrderLib1.cpp) -add_test_lib(TestOrderLib2 TestOrderLib2.cpp) -target_link_manual(TestOrderLib2 TestOrderLib1) - -add_test_exe(TestOrderExe1.elf TestOrderExe.cpp) -target_link_manual(TestOrderExe1.elf TestOrderLib1) -target_link_manual(TestOrderExe1.elf TestOrderLib2) - -add_test_exe(TestOrderExe2.elf TestOrderExe.cpp) -target_link_manual(TestOrderExe2.elf TestOrderLib2) -target_link_manual(TestOrderExe2.elf TestOrderLib1) - -add_dependencies(TestOrder - TestOrderLib1 - TestOrderLib2 - TestOrderExe1.elf - TestOrderExe2.elf -) diff --git a/Tests/LibELF/Dynlib.cpp b/Tests/LibELF/Dynlib.cpp deleted file mode 100644 index 4187378fd1a..00000000000 --- a/Tests/LibELF/Dynlib.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2021, Rodrigo Tobar - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -extern "C" { -int FUNCTION(); -int FUNCTION() -{ - return (int)Line::Span(0, 0).beginning(); -} -} diff --git a/Tests/LibELF/TLSDef.cpp b/Tests/LibELF/TLSDef.cpp deleted file mode 100644 index e54af9a9e74..00000000000 --- a/Tests/LibELF/TLSDef.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2023, Daniel Bertalan - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -__thread int one = 1; -__thread int two = 2; -[[gnu::tls_model("initial-exec")]] __thread int three = 3; -[[gnu::tls_model("initial-exec")]] __thread int four = 4; - -void check_increment_worked(); -void check_increment_worked() -{ - EXPECT_EQ(one, 2); - EXPECT_EQ(two, 3); - EXPECT_EQ(three, 4); - EXPECT_EQ(four, 5); -} diff --git a/Tests/LibELF/TLSUse.cpp b/Tests/LibELF/TLSUse.cpp deleted file mode 100644 index 79f67a03f02..00000000000 --- a/Tests/LibELF/TLSUse.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2023, Daniel Bertalan - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -// Defined in TLSDef.cpp -extern __thread int one; -extern __thread int two; -extern __thread int three; -[[gnu::tls_model("initial-exec")]] extern __thread int four; -extern void check_increment_worked(); - -static void check_initial() -{ - EXPECT_EQ(one, 1); - EXPECT_EQ(two, 2); - EXPECT_EQ(three, 3); - EXPECT_EQ(four, 4); -} - -// This checks the basic functionality of thread-local variables: -// - TLS variables with a static initializer have the correct value on program startup -// - TLS variables are set to their initial values in a new thread -// - relocations refer to the correct variables -// - accessing an initial-exec variable from a DSO works even if -// it's not declared as initial-exec at the use site -// FIXME: Test C++11 thread_local variables with dynamic initializers -void run_test(); -void run_test() -{ - check_initial(); - ++one; - ++two; - ++three; - ++four; - check_increment_worked(); - - auto second_thread = Threading::Thread::construct([] { - check_initial(); - return 0; - }); - second_thread->start(); - (void)second_thread->join(); -} diff --git a/Tests/LibELF/TestDlOpen.cpp b/Tests/LibELF/TestDlOpen.cpp deleted file mode 100644 index 3d9771784f9..00000000000 --- a/Tests/LibELF/TestDlOpen.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2021, Rodrigo Tobar - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -TEST_CASE(test_dlopen) -{ - auto liba = dlopen("libDynlibA.so", RTLD_LAZY | RTLD_GLOBAL); - EXPECT_NE(liba, nullptr); - auto libb = dlopen("libDynlibB.so", RTLD_LAZY | RTLD_GLOBAL); - EXPECT_NE(libb, nullptr); - - typedef int (*dynlib_func_t)(); - dynlib_func_t func_a = (dynlib_func_t)dlsym(liba, "dynliba_function"); - EXPECT_NE(func_a, nullptr); - EXPECT_EQ(0, func_a()); - - dynlib_func_t func_b = (dynlib_func_t)dlsym(libb, "dynlibb_function"); - EXPECT_NE(func_b, nullptr); - EXPECT_EQ(0, func_b()); -} - -TEST_CASE(test_dlsym_rtld_default) -{ - auto libd = dlopen("libDynlibD.so", RTLD_LAZY | RTLD_GLOBAL); - EXPECT_NE(libd, nullptr); - if (libd == nullptr) { - warnln("can't open libDynlibD.so, {}", dlerror()); - return; - } - - typedef int (*dynlib_func_t)(); - dynlib_func_t func_c = (dynlib_func_t)dlsym(RTLD_DEFAULT, "dynlibc_function"); - EXPECT_NE(func_c, nullptr); - EXPECT_EQ(0, func_c()); - - dynlib_func_t func_d = (dynlib_func_t)dlsym(RTLD_DEFAULT, "dynlibd_function"); - EXPECT_NE(func_d, nullptr); - EXPECT_EQ(0, func_d()); - - dlclose(libd); -} diff --git a/Tests/LibELF/TestOrder.cpp b/Tests/LibELF/TestOrder.cpp deleted file mode 100644 index 05e2da85c7d..00000000000 --- a/Tests/LibELF/TestOrder.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -auto temp_directory = [] { - return MUST(FileSystem::TempFile::create_temp_directory()); -}(); - -static ByteBuffer run(ByteString executable) -{ - static auto path_to_captured_output = LexicalPath::join(temp_directory->path(), "output"sv); - - auto process = MUST(Core::Process::spawn(Core::ProcessSpawnOptions { - .executable = move(executable), - .file_actions = { - Core::FileAction::OpenFile { - .path = path_to_captured_output.string(), - .mode = Core::File::OpenMode::Write, - .fd = 1, - }, - }, - })); - MUST(process.wait_for_termination()); - auto output = MUST(Core::File::open(path_to_captured_output.string(), Core::File::OpenMode::Read)); - return MUST(output->read_until_eof()); -} - -TEST_CASE(order) -{ - { - auto expected = R"(TestOrderLib1.cpp:init -TestOrderLib2.cpp:init -TestOrderExe.cpp:init -TestOrderExe.cpp:main -f() returns: TestOrderLib1.cpp -)"sv; - auto output = run("TestOrderExe1.elf"); - EXPECT_EQ(StringView(output.bytes()), expected); - } - - { - auto expected = R"(TestOrderLib1.cpp:init -TestOrderLib2.cpp:init -TestOrderExe.cpp:init -TestOrderExe.cpp:main -f() returns: TestOrderLib2.cpp -)"sv; - auto output = run("TestOrderExe2.elf"); - EXPECT_EQ(StringView(output.bytes()), expected); - } -} diff --git a/Tests/LibELF/TestOrderExe.cpp b/Tests/LibELF/TestOrderExe.cpp deleted file mode 100644 index 3ba77e69a40..00000000000 --- a/Tests/LibELF/TestOrderExe.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -[[gnu::constructor]] static void init() -{ - outln("TestOrderExe.cpp:init"); -} - -StringView f(); - -int main() -{ - outln("TestOrderExe.cpp:main"); - outln("f() returns: {}", f()); -} diff --git a/Tests/LibELF/TestOrderLib1.cpp b/Tests/LibELF/TestOrderLib1.cpp deleted file mode 100644 index 9a2ad2dbdc9..00000000000 --- a/Tests/LibELF/TestOrderLib1.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -[[gnu::constructor]] static void init() -{ - outln("TestOrderLib1.cpp:init"); -} - -StringView f(); -StringView f() -{ - return "TestOrderLib1.cpp"sv; -} diff --git a/Tests/LibELF/TestOrderLib2.cpp b/Tests/LibELF/TestOrderLib2.cpp deleted file mode 100644 index bce8f356752..00000000000 --- a/Tests/LibELF/TestOrderLib2.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -[[gnu::constructor]] static void init() -{ - outln("TestOrderLib2.cpp:init"); -} - -StringView f(); -StringView f() -{ - return "TestOrderLib2.cpp"sv; -} diff --git a/Tests/LibELF/TestTLS.cpp b/Tests/LibELF/TestTLS.cpp deleted file mode 100644 index 5391d4374db..00000000000 --- a/Tests/LibELF/TestTLS.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023, Daniel Bertalan - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -// When linking an executable, TLS relaxations might be relaxed to different -// access modes than intended. Hence, the actual logic has been moved to a -// shared library, and this executable just calls it. -extern void run_test(); -TEST_CASE(basic) -{ - run_test(); -} - -TEST_CASE(local_exec) -{ - [[gnu::tls_model("local-exec")]] static volatile __thread char test1[4096 * 4 + 10]; - - for (size_t i = 0; i < sizeof(test1); i++) { - test1[i] = static_cast(i); - AK::taint_for_optimizer(test1[i]); - } - - for (size_t i = 0; i < sizeof(test1); i++) { - AK::taint_for_optimizer(test1[i]); - EXPECT_EQ(test1[i], static_cast(i)); - } - - [[gnu::tls_model("local-exec")]] static volatile __thread u16 test2[] = { 0x1234, 0x5678, 0xabcd }; - AK::taint_for_optimizer(test2[0]); - EXPECT_EQ(test2[0], 0x1234); - AK::taint_for_optimizer(test2[1]); - EXPECT_EQ(test2[1], 0x5678); - AK::taint_for_optimizer(test2[2]); - EXPECT_EQ(test2[2], 0xabcd); -} diff --git a/Tests/LibELF/TestWeakSymbolResolution.cpp b/Tests/LibELF/TestWeakSymbolResolution.cpp deleted file mode 100644 index 6e19ff397da..00000000000 --- a/Tests/LibELF/TestWeakSymbolResolution.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -int f(); -[[gnu::weak]] int f() { return 1; } -int g(); - -TEST_CASE(weak_symbol_resolution) -{ - EXPECT_EQ(g(), 1); -} diff --git a/Tests/LibELF/TestWeakSymbolResolution1.cpp b/Tests/LibELF/TestWeakSymbolResolution1.cpp deleted file mode 100644 index 2a120900799..00000000000 --- a/Tests/LibELF/TestWeakSymbolResolution1.cpp +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -[[gnu::weak]] int f(); - -int g(); -int g() { return f(); } diff --git a/Tests/LibELF/TestWeakSymbolResolution2.cpp b/Tests/LibELF/TestWeakSymbolResolution2.cpp deleted file mode 100644 index ee391bb9108..00000000000 --- a/Tests/LibELF/TestWeakSymbolResolution2.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (c) 2024, Dan Klishch - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -int f(); -int f() { return 2; } diff --git a/Tests/LibELF/test-elf.cpp b/Tests/LibELF/test-elf.cpp deleted file mode 100644 index 31d0be5333b..00000000000 --- a/Tests/LibELF/test-elf.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (c) 2021, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include - -TEST_CASE(test_interp_header_tiny_p_filesz) -{ - char buffer[0x2000]; - - auto& header = *(Elf32_Ehdr*)buffer; - header.e_ident[EI_MAG0] = ELFMAG0; - header.e_ident[EI_MAG1] = ELFMAG1; - header.e_ident[EI_MAG2] = ELFMAG2; - header.e_ident[EI_MAG3] = ELFMAG3; - header.e_ident[EI_CLASS] = ELFCLASS32; - header.e_ident[EI_DATA] = ELFDATA2LSB; - header.e_ident[EI_VERSION] = EV_CURRENT; - header.e_ident[EI_OSABI] = ELFOSABI_SYSV; - header.e_ident[EI_ABIVERSION] = 0; - header.e_type = ET_REL; - header.e_version = EV_CURRENT; - header.e_ehsize = sizeof(Elf32_Ehdr); - header.e_machine = EM_386; - header.e_shentsize = sizeof(Elf32_Shdr); - header.e_phnum = 1; - header.e_phoff = 52; // inaccurate - header.e_phentsize = sizeof(Elf32_Phdr); // inaccurate - header.e_shnum = 3; // inaccurate - header.e_shoff = 1024; // inaccurate - header.e_shstrndx = 2; // inaccurate - header.e_entry = 1024; // inaccurate - - auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]); - ph[0].p_flags = PF_R | PF_X; - ph[0].p_vaddr = 0x00d4; - ph[0].p_align = PAGE_SIZE; - ph[0].p_type = PT_INTERP; - ph[0].p_memsz = 0xffff0000; - ph[0].p_offset = 0x100; - - // p_filesz (1 or less) to trigger crash - ph[0].p_filesz = 1; - - char path[] = "/tmp/test-elf.XXXXXX"; - auto fd = mkstemp(path); - EXPECT_NE(fd, -1); - EXPECT_EQ(fchmod(fd, 0700), 0); - - int nwritten = write(fd, buffer, sizeof(buffer)); - EXPECT(nwritten); - - auto elf_path = TRY_OR_FAIL(FileSystem::read_link(ByteString::formatted("/proc/{}/fd/{}", getpid(), fd))); - EXPECT(elf_path.characters()); - - int rc = execl(elf_path.characters(), "test-elf", nullptr); - EXPECT_EQ(rc, -1); - EXPECT_EQ(errno, 8); - - EXPECT_EQ(unlink(path), 0); -} - -TEST_CASE(test_interp_header_p_filesz_larger_than_p_memsz) -{ - char buffer[0x2000]; - - auto& header = *(Elf32_Ehdr*)buffer; - header.e_ident[EI_MAG0] = ELFMAG0; - header.e_ident[EI_MAG1] = ELFMAG1; - header.e_ident[EI_MAG2] = ELFMAG2; - header.e_ident[EI_MAG3] = ELFMAG3; - header.e_ident[EI_CLASS] = ELFCLASS32; - header.e_ident[EI_DATA] = ELFDATA2LSB; - header.e_ident[EI_VERSION] = EV_CURRENT; - header.e_ident[EI_OSABI] = ELFOSABI_SYSV; - header.e_ident[EI_ABIVERSION] = 0; - header.e_type = ET_REL; - header.e_version = EV_CURRENT; - header.e_ehsize = sizeof(Elf32_Ehdr); - header.e_machine = EM_386; - header.e_shentsize = sizeof(Elf32_Shdr); - header.e_phnum = 1; - header.e_phoff = 52; // inaccurate - header.e_phentsize = sizeof(Elf32_Phdr); // inaccurate - header.e_shnum = 3; // inaccurate - header.e_shoff = 1024; // inaccurate - header.e_shstrndx = 2; // inaccurate - header.e_entry = 1024; // inaccurate - - auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]); - ph[0].p_flags = PF_R | PF_X; - ph[0].p_vaddr = 0x00d4; - ph[0].p_align = PAGE_SIZE; - ph[0].p_type = PT_INTERP; - ph[0].p_memsz = 0xffff0000; - ph[0].p_offset = 0x1000; - ph[0].p_filesz = 0x1000; - - char path[] = "/tmp/test-elf.XXXXXX"; - auto fd = mkstemp(path); - EXPECT_NE(fd, -1); - EXPECT_EQ(fchmod(fd, 0700), 0); - - int nwritten = write(fd, buffer, sizeof(buffer)); - EXPECT(nwritten); - - auto elf_path = TRY_OR_FAIL(FileSystem::read_link(ByteString::formatted("/proc/{}/fd/{}", getpid(), fd))); - EXPECT(elf_path.characters()); - - int rc = execl(elf_path.characters(), "test-elf", nullptr); - EXPECT_EQ(rc, -1); - EXPECT_EQ(errno, 8); - - EXPECT_EQ(unlink(path), 0); -} - -TEST_CASE(test_interp_header_p_filesz_plus_p_offset_overflow_p_memsz) -{ - char buffer[0x2000]; - - auto& header = *(Elf32_Ehdr*)buffer; - header.e_ident[EI_MAG0] = ELFMAG0; - header.e_ident[EI_MAG1] = ELFMAG1; - header.e_ident[EI_MAG2] = ELFMAG2; - header.e_ident[EI_MAG3] = ELFMAG3; - header.e_ident[EI_CLASS] = ELFCLASS32; - header.e_ident[EI_DATA] = ELFDATA2LSB; - header.e_ident[EI_VERSION] = EV_CURRENT; - header.e_ident[EI_OSABI] = ELFOSABI_SYSV; - header.e_ident[EI_ABIVERSION] = 0; - header.e_type = ET_REL; - header.e_version = EV_CURRENT; - header.e_ehsize = sizeof(Elf32_Ehdr); - header.e_machine = EM_386; - header.e_shentsize = sizeof(Elf32_Shdr); - header.e_phoff = 52; // inaccurate - header.e_phentsize = sizeof(Elf32_Phdr); // inaccurate - header.e_shnum = 3; // inaccurate - header.e_shoff = 1024; // inaccurate - header.e_shstrndx = 2; // inaccurate - header.e_entry = 1024; // inaccurate - - auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]); - ph[0].p_flags = PF_R | PF_X; - ph[0].p_vaddr = 0x00d4; - ph[0].p_align = PAGE_SIZE; - ph[0].p_type = PT_INTERP; - - // p_memsz must be of sufficient size to hold maxint - 0x1000 - ph[0].p_memsz = 0xfffff000; - - // p_offset + p_filesz must not exceed buffer size in order to pass buffer size check in ELF::validate_program_headers(). - // p_memsz + p_offset must be sufficiently large to overflow maxint. - ph[0].p_offset = 0x1234; - ph[0].p_filesz = -0x1000; - - char path[] = "/tmp/test-elf.XXXXXX"; - auto fd = mkstemp(path); - EXPECT_NE(fd, -1); - EXPECT_EQ(fchmod(fd, 0700), 0); - - int nwritten = write(fd, buffer, sizeof(buffer)); - EXPECT(nwritten); - - auto elf_path = TRY_OR_FAIL(FileSystem::read_link(ByteString::formatted("/proc/{}/fd/{}", getpid(), fd))); - EXPECT(elf_path.characters()); - - int rc = execl(elf_path.characters(), "test-elf", nullptr); - EXPECT_EQ(rc, -1); - EXPECT_EQ(errno, 8); - - EXPECT_EQ(unlink(path), 0); -} - -TEST_CASE(test_load_header_p_memsz_zero) -{ - char buffer[0x2000]; - - auto& header = *(Elf32_Ehdr*)buffer; - header.e_ident[EI_MAG0] = ELFMAG0; - header.e_ident[EI_MAG1] = ELFMAG1; - header.e_ident[EI_MAG2] = ELFMAG2; - header.e_ident[EI_MAG3] = ELFMAG3; - header.e_ident[EI_CLASS] = ELFCLASS32; - header.e_ident[EI_DATA] = ELFDATA2LSB; - header.e_ident[EI_VERSION] = EV_CURRENT; - header.e_ident[EI_OSABI] = ELFOSABI_SYSV; - header.e_ident[EI_ABIVERSION] = 0; - header.e_type = ET_REL; - header.e_version = EV_CURRENT; - header.e_ehsize = sizeof(Elf32_Ehdr); - header.e_machine = EM_386; - header.e_shentsize = sizeof(Elf32_Shdr); - header.e_phoff = 52; // inaccurate - header.e_phentsize = sizeof(Elf32_Phdr); // inaccurate - header.e_shnum = 3; // inaccurate - header.e_shoff = 1024; // inaccurate - header.e_shstrndx = 2; // inaccurate - header.e_entry = 1024; // inaccurate - - auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]); - ph[0].p_flags = PF_R | PF_X; - ph[0].p_vaddr = 0x00d4; - ph[0].p_align = PAGE_SIZE; - ph[0].p_type = PT_LOAD; - ph[0].p_offset = 0; - ph[0].p_filesz = 0; - - // p_memsz zero to trigger crash - ph[0].p_memsz = 0; - - char path[] = "/tmp/test-elf.XXXXXX"; - auto fd = mkstemp(path); - EXPECT_NE(fd, -1); - EXPECT_EQ(fchmod(fd, 0700), 0); - - int nwritten = write(fd, buffer, sizeof(buffer)); - EXPECT(nwritten); - - auto elf_path = TRY_OR_FAIL(FileSystem::read_link(ByteString::formatted("/proc/{}/fd/{}", getpid(), fd))); - EXPECT(elf_path.characters()); - - int rc = execl(elf_path.characters(), "test-elf", nullptr); - EXPECT_EQ(rc, -1); - EXPECT_EQ(errno, 8); - - EXPECT_EQ(unlink(path), 0); -} - -TEST_CASE(test_load_header_p_memsz_not_equal_to_p_align) -{ - char buffer[0x2000]; - - auto& header = *(Elf32_Ehdr*)buffer; - header.e_ident[EI_MAG0] = ELFMAG0; - header.e_ident[EI_MAG1] = ELFMAG1; - header.e_ident[EI_MAG2] = ELFMAG2; - header.e_ident[EI_MAG3] = ELFMAG3; - header.e_ident[EI_CLASS] = ELFCLASS32; - header.e_ident[EI_DATA] = ELFDATA2LSB; - header.e_ident[EI_VERSION] = EV_CURRENT; - header.e_ident[EI_OSABI] = ELFOSABI_SYSV; - header.e_ident[EI_ABIVERSION] = 0; - header.e_type = ET_REL; - header.e_version = EV_CURRENT; - header.e_ehsize = sizeof(Elf32_Ehdr); - header.e_machine = EM_386; - header.e_shentsize = sizeof(Elf32_Shdr); - header.e_phoff = 52; // inaccurate - header.e_phentsize = sizeof(Elf32_Phdr); // inaccurate - header.e_shnum = 3; // inaccurate - header.e_shoff = 1024; // inaccurate - header.e_shstrndx = 2; // inaccurate - header.e_entry = 1024; // inaccurate - - auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]); - ph[0].p_flags = PF_R | PF_X; - ph[0].p_vaddr = 0x00d4; - ph[0].p_type = PT_LOAD; - ph[0].p_memsz = 0xffff0000; - ph[0].p_offset = 0x1000; - ph[0].p_filesz = 0x1000; - - // p_align not equal to PAGE_SIZE to trigger crash - ph[0].p_align = PAGE_SIZE / 2; - - char path[] = "/tmp/test-elf.XXXXXX"; - auto fd = mkstemp(path); - EXPECT_NE(fd, -1); - EXPECT_EQ(fchmod(fd, 0700), 0); - - int nwritten = write(fd, buffer, sizeof(buffer)); - EXPECT(nwritten); - - auto elf_path = TRY_OR_FAIL(FileSystem::read_link(ByteString::formatted("/proc/{}/fd/{}", getpid(), fd))); - EXPECT(elf_path.characters()); - - int rc = execl(elf_path.characters(), "test-elf", nullptr); - EXPECT_EQ(rc, -1); - EXPECT_EQ(errno, 8); - - EXPECT_EQ(unlink(path), 0); -} diff --git a/Tests/LibGL/CMakeLists.txt b/Tests/LibGL/CMakeLists.txt deleted file mode 100644 index feb517cb34d..00000000000 --- a/Tests/LibGL/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -set(TEST_SOURCES - TestAPI.cpp - TestRender.cpp - TestShaders.cpp -) - -foreach(source IN LISTS TEST_SOURCES) - serenity_test("${source}" LibGL LIBS LibCore LibGfx LibGL LibGPU LibSoftGPU) -endforeach() - -install(DIRECTORY reference-images DESTINATION usr/Tests/LibGL) diff --git a/Tests/LibGL/TestAPI.cpp b/Tests/LibGL/TestAPI.cpp deleted file mode 100644 index 51908ba836e..00000000000 --- a/Tests/LibGL/TestAPI.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2022, Luke Wilde - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -static NonnullOwnPtr create_testing_context() -{ - auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, { 1, 1 })); - auto context = MUST(GL::create_context(*bitmap)); - GL::make_context_current(context); - return context; -} - -TEST_CASE(0001_gl_gen_textures_does_not_return_the_same_texture_name_twice_unless_deleted) -{ - // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGenTextures.xhtml - // "Texture names returned by a call to glGenTextures are not returned by subsequent calls, unless they are first deleted with glDeleteTextures." - auto context = create_testing_context(); - - GLuint texture1 = 0; - GLuint texture2 = 0; - - glGenTextures(1, &texture1); - - // glDeleteTextures previously did not check that the texture name was allocated by glGenTextures before adding it to the free texture name list. - // This means that if you delete a texture twice in a row, the name will appear twice in the free texture list, making glGenTextures return the - // same texture name twice in a row. - glDeleteTextures(1, &texture1); - glDeleteTextures(1, &texture1); - - texture1 = 0; - - glGenTextures(1, &texture1); - glGenTextures(1, &texture2); - - EXPECT_NE(texture1, texture2); -} - -TEST_CASE(0002_gl_cull_face_does_not_accept_left_and_right) -{ - auto context = create_testing_context(); - - // glCullFace only accepts GL_FRONT, GL_BACK and GL_FRONT_AND_BACK. We checked if the mode was valid by performing cull_mode < GL_FRONT || cull_mode > GL_FRONT_AND_BACK. - // However, this range also contains GL_LEFT and GL_RIGHT, which we would accept when we should return a GL_INVALID_ENUM error. - glCullFace(GL_LEFT); - EXPECT_EQ(glGetError(), static_cast(GL_INVALID_ENUM)); - - glCullFace(GL_RIGHT); - EXPECT_EQ(glGetError(), static_cast(GL_INVALID_ENUM)); -} - -TEST_CASE(0003_gl_bind_buffer_names_must_be_allocated) -{ - auto context = create_testing_context(); - - glBindBuffer(GL_ARRAY_BUFFER, 123); - EXPECT_EQ(glGetError(), static_cast(GL_INVALID_VALUE)); -} - -TEST_CASE(0004_gl_color_clear_value) -{ - auto context = create_testing_context(); - - Array clear_color; - glGetDoublev(GL_COLOR_CLEAR_VALUE, clear_color.data()); - EXPECT_EQ(clear_color[0], 0.); - EXPECT_EQ(clear_color[1], 0.); - EXPECT_EQ(clear_color[2], 0.); - EXPECT_EQ(clear_color[3], 0.); - - glClearColor(.1f, .2f, .3f, .4f); - - glGetDoublev(GL_COLOR_CLEAR_VALUE, clear_color.data()); - EXPECT_APPROXIMATE(clear_color[0], .1); - EXPECT_APPROXIMATE(clear_color[1], .2); - EXPECT_APPROXIMATE(clear_color[2], .3); - EXPECT_APPROXIMATE(clear_color[3], .4); -} - -TEST_CASE(0005_gl_depth_clear_value) -{ - auto context = create_testing_context(); - - GLdouble clear_depth; - glGetDoublev(GL_DEPTH_CLEAR_VALUE, &clear_depth); - EXPECT_EQ(clear_depth, 1.); - - glClearDepth(.1f); - - glGetDoublev(GL_DEPTH_CLEAR_VALUE, &clear_depth); - EXPECT_APPROXIMATE(clear_depth, .1); -} - -TEST_CASE(0006_gl_stencil_clear_value) -{ - auto context = create_testing_context(); - - GLint clear_stencil; - glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &clear_stencil); - EXPECT_EQ(clear_stencil, 0); - - glClearStencil(255); - - glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &clear_stencil); - EXPECT_EQ(clear_stencil, 255); -} diff --git a/Tests/LibGL/TestRender.cpp b/Tests/LibGL/TestRender.cpp deleted file mode 100644 index ff10b32c84b..00000000000 --- a/Tests/LibGL/TestRender.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (c) 2021, Leon Albrecht - * Copyright (c) 2022-2024, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef AK_OS_SERENITY -# define REFERENCE_IMAGE_DIR "/usr/Tests/LibGL/reference-images" -#else -# define REFERENCE_IMAGE_DIR "reference-images" -#endif -#define SAVE_OUTPUT false - -static NonnullOwnPtr create_testing_context(int width, int height, Gfx::BitmapFormat format = Gfx::BitmapFormat::BGRx8888) -{ - auto bitmap = MUST(Gfx::Bitmap::create(format, { width, height })); - auto context = MUST(GL::create_context(*bitmap)); - GL::make_context_current(context); - return context; -} - -static void expect_bitmap_equals_reference(Gfx::Bitmap const& bitmap, StringView test_name) -{ - auto reference_filename = ByteString::formatted("{}.qoi", test_name); - - if constexpr (SAVE_OUTPUT) { - auto target_path = LexicalPath("/home/anon").append(reference_filename); - auto qoi_buffer = MUST(Gfx::QOIWriter::encode(bitmap)); - auto qoi_output_stream = MUST(Core::File::open(target_path.string(), Core::File::OpenMode::Write)); - MUST(qoi_output_stream->write_until_depleted(qoi_buffer)); - } - - auto reference_image_path = ByteString::formatted(REFERENCE_IMAGE_DIR "/{}", reference_filename); - auto reference_bitmap = MUST(Gfx::Bitmap::load_from_file(reference_image_path)); - EXPECT_EQ(reference_bitmap->visually_equals(bitmap), true); -} - -TEST_CASE(0001_simple_triangle) -{ - auto context = create_testing_context(64, 64); - - glBegin(GL_TRIANGLES); - glColor3f(1, 1, 1); - glVertex2f(0, 1); - glVertex2f(-1, -1); - glVertex2f(1, -1); - glEnd(); - - EXPECT_EQ(glGetError(), 0u); - - context->present(); - expect_bitmap_equals_reference(context->frontbuffer(), "0001_simple_triangle"sv); -} - -TEST_CASE(0002_quad_color_interpolation) -{ - auto context = create_testing_context(64, 64); - - glBegin(GL_QUADS); - - glColor3f(1, 0, 0); - glVertex2i(-1, -1); - glColor3f(0, 1, 0); - glVertex2i(1, -1); - glColor3f(0, 0, 1); - glVertex2i(1, 1); - glColor3f(1, 0, 1); - glVertex2i(-1, 1); - glEnd(); - - EXPECT_EQ(glGetError(), 0u); - - context->present(); - expect_bitmap_equals_reference(context->frontbuffer(), "0002_quad_color_interpolation"sv); -} - -TEST_CASE(0003_rect_w_coordinate_regression) -{ - auto context = create_testing_context(64, 64); - - glEnable(GL_DEPTH_TEST); - glClear(GL_DEPTH_BUFFER_BIT); - - glColor3f(0, 1, 0); - glRectf(-0.5f, -0.5f, 0.5f, 0.5f); - - glBegin(GL_TRIANGLES); - glColor3f(1, 0, 0); - glVertex2i(-1, -1); - glVertex2i(1, -1); - glVertex2i(-1, 1); - glEnd(); - - EXPECT_EQ(glGetError(), 0u); - - context->present(); - expect_bitmap_equals_reference(context->frontbuffer(), "0003_rect_w_coordinate_regression"sv); -} - -TEST_CASE(0004_points) -{ - auto context = create_testing_context(64, 64); - - // Aliased points - for (size_t i = 0; i < 3; ++i) { - glPointSize(1.f + i); - glBegin(GL_POINTS); - glVertex2f(-.5f + i * .5f, .5f); - glEnd(); - } - - // Anti-aliased points - glEnable(GL_POINT_SMOOTH); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - for (size_t i = 0; i < 3; ++i) { - glPointSize(3.f - i); - glBegin(GL_POINTS); - glVertex2f(-.5f + i * .5f, -.5f); - glEnd(); - } - - EXPECT_EQ(glGetError(), 0u); - - context->present(); - expect_bitmap_equals_reference(context->frontbuffer(), "0004_points"sv); -} - -TEST_CASE(0005_lines_antialiased) -{ - auto context = create_testing_context(64, 64); - - // Draw anti-aliased lines - glEnable(GL_LINE_SMOOTH); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glBegin(GL_LINES); - for (size_t i = 0; i < 6; ++i) { - glVertex2f(-.9f, .25f - i * .1f); - glVertex2f(.9f, .9f - i * .36f); - } - glEnd(); - - EXPECT_EQ(glGetError(), 0u); - - context->present(); - expect_bitmap_equals_reference(context->frontbuffer(), "0005_lines"sv); -} - -TEST_CASE(0006_test_rgb565_texture) -{ - auto context = create_testing_context(64, 64); - - GLuint texture_id; - glGenTextures(1, &texture_id); - glBindTexture(GL_TEXTURE_2D, texture_id); - u16 texture_data[] = { 0xF800, 0xC000, 0x8000, 0x07E0, 0x0600, 0x0400, 0x001F, 0x0018, 0x0010 }; - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 3, 3, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texture_data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glEnable(GL_TEXTURE_2D); - glBegin(GL_QUADS); - glTexCoord2i(0, 0); - glVertex2i(-1, 1); - glTexCoord2i(0, 1); - glVertex2i(-1, -1); - glTexCoord2i(1, 1); - glVertex2i(1, -1); - glTexCoord2i(1, 0); - glVertex2i(1, 1); - glEnd(); - - EXPECT_EQ(glGetError(), 0u); - - context->present(); - expect_bitmap_equals_reference(context->frontbuffer(), "0006_test_rgb565_texture"sv); -} - -TEST_CASE(0007_test_rgba_to_rgb_texture) -{ - auto context = create_testing_context(64, 64); - - GLuint texture_id; - glGenTextures(1, &texture_id); - glBindTexture(GL_TEXTURE_2D, texture_id); - - // Write RGBA data with A = 0 to an RGB texture - u32 texture_data[] = { 0x00FF0000 }; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, texture_data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glEnable(GL_TEXTURE_2D); - glBegin(GL_TRIANGLES); - glTexCoord2i(0, 0); - glVertex2i(-1, 1); - glTexCoord2i(0, 1); - glVertex2i(-1, -1); - glTexCoord2i(1, 1); - glVertex2i(1, -1); - glEnd(); - - EXPECT_EQ(glGetError(), 0u); - - context->present(); - expect_bitmap_equals_reference(context->frontbuffer(), "0007_test_rgba_to_rgb_texture"sv); -} - -TEST_CASE(0008_test_pop_matrix_regression) -{ - auto context = create_testing_context(64, 64); - - // Load identity matrix after popping - glMatrixMode(GL_MODELVIEW); - glTranslatef(10.f, 10.f, 10.f); - glPushMatrix(); - glPopMatrix(); - glLoadIdentity(); - - glBegin(GL_TRIANGLES); - glColor3f(0.f, 1.f, 0.f); - glVertex2f(.5f, -.5f); - glVertex2f(.0f, .5f); - glVertex2f(-.5f, -.5f); - glEnd(); - - EXPECT_EQ(glGetError(), 0u); - - context->present(); - expect_bitmap_equals_reference(context->frontbuffer(), "0008_test_pop_matrix_regression"sv); -} - -TEST_CASE(0009_test_draw_elements_in_display_list) -{ - auto context = create_testing_context(64, 64); - - glColor3f(0.f, 0.f, 1.f); - glEnableClientState(GL_VERTEX_ARRAY); - - auto const list_index = glGenLists(1); - glNewList(list_index, GL_COMPILE); - float vertices[] = { 0.f, .5f, -.5f, -.5f, .5f, -.5f }; - glVertexPointer(2, GL_FLOAT, 0, &vertices); - u8 indices[] = { 0, 1, 2 }; - glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, &indices); - glEndList(); - - // Modifying an index here should not have an effect - indices[0] = 2; - - glCallList(list_index); - - EXPECT_EQ(glGetError(), 0u); - - context->present(); - expect_bitmap_equals_reference(context->frontbuffer(), "0009_test_draw_elements_in_display_list"sv); -} - -TEST_CASE(0010_test_store_data_in_buffer) -{ - auto context = create_testing_context(64, 64); - - glColor3f(1.f, 0.f, 0.f); - glEnableClientState(GL_VERTEX_ARRAY); - - float vertices[] = { 0.f, .5f, -.5f, -.5f, .5f, -.5f }; - u8 indices[] = { 0, 1, 2 }; - - GLuint buffers[2]; - glGenBuffers(2, buffers); - - glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); - glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), vertices, GL_STATIC_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3, indices, GL_STATIC_DRAW); - - glVertexPointer(2, GL_FLOAT, 0, 0); - glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, 0); - - glDeleteBuffers(2, buffers); - - EXPECT_EQ(glGetError(), 0u); - - context->present(); - expect_bitmap_equals_reference(context->frontbuffer(), "0010_test_store_data_in_buffer"sv); -} - -TEST_CASE(0011_tex_env_combine_with_constant_color) -{ - auto context = create_testing_context(64, 64); - - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); - - float color[4] = { .3f, .5f, .7f, 1.f }; - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); - - glRecti(-1, -1, 1, 1); - - EXPECT_EQ(glGetError(), 0u); - - context->present(); - expect_bitmap_equals_reference(context->frontbuffer(), "0011_tex_env_combine_with_constant_color"sv); -} - -TEST_CASE(0012_blend_equations) -{ - auto context = create_testing_context(64, 64, Gfx::BitmapFormat::BGRA8888); - - // Assert initial state - int actual_mode; - glGetIntegerv(GL_BLEND_EQUATION_RGB, &actual_mode); - EXPECT_EQ(actual_mode, GL_FUNC_ADD); - glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &actual_mode); - EXPECT_EQ(actual_mode, GL_FUNC_ADD); - - // Clear with alpha 0 so we get a transparent color buffer - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - glColor4f(.8f, .2f, .3f, .7f); - glRecti(-1, -1, 1, 1); - - glColor4f(.3f, .1f, .8f, .5f); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - - static constexpr Array blend_modes = { - GL_FUNC_ADD, - GL_FUNC_SUBTRACT, - GL_FUNC_REVERSE_SUBTRACT, - GL_MIN, - GL_MAX, - }; - auto constexpr grid_size = blend_modes.size(); - auto constexpr cell_size = 2.f / grid_size; - for (size_t x = 0; x < grid_size; ++x) { - for (size_t y = 0; y < grid_size; ++y) { - auto rgb_mode = blend_modes[x]; - auto alpha_mode = blend_modes[y]; - - glBlendEquationSeparate(rgb_mode, alpha_mode); - - glGetIntegerv(GL_BLEND_EQUATION_RGB, &actual_mode); - EXPECT_EQ(static_cast(actual_mode), rgb_mode); - - glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &actual_mode); - EXPECT_EQ(static_cast(actual_mode), alpha_mode); - - glRectf( - -1.f + cell_size * static_cast(x), - 1.f - cell_size * static_cast(y), - -1.f + cell_size * static_cast(x + 1), - 1.f - cell_size * static_cast(y + 1)); - } - } - - EXPECT_EQ(glGetError(), 0u); - - context->present(); - expect_bitmap_equals_reference(context->frontbuffer(), "0012_blend_equations"sv); -} diff --git a/Tests/LibGL/TestShaders.cpp b/Tests/LibGL/TestShaders.cpp deleted file mode 100644 index 546e8c5c08e..00000000000 --- a/Tests/LibGL/TestShaders.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include - -static NonnullOwnPtr create_testing_context(int width, int height) -{ - auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, { width, height })); - auto context = MUST(GL::create_context(*bitmap)); - GL::make_context_current(context); - - return context; -} - -TEST_CASE(0001_program_creation) -{ - auto context = create_testing_context(64, 64); - - GLuint vertex_shader; - GLuint fragment_shader; - GLuint program; - - auto vertex_shader_source = "#version 330\n" - "void main() {\n" - " gl_Position = vec4(0, 0, 0, 0);\n" - "}\n"; - - auto fragment_shader_source = "#version 330\n" - "out vec4 color;\n" - "void main() {\n" - " color = vec4(1, 1, 1, 1);\n" - "}\n"; - - vertex_shader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertex_shader, 1, &vertex_shader_source, nullptr); - glCompileShader(vertex_shader); - GLint vertex_shader_compile_status; - glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &vertex_shader_compile_status); - EXPECT_EQ(vertex_shader_compile_status, GL_TRUE); - - fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragment_shader, 1, &fragment_shader_source, nullptr); - glCompileShader(fragment_shader); - GLint fragment_shader_compile_status; - glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &fragment_shader_compile_status); - EXPECT_EQ(fragment_shader_compile_status, GL_TRUE); - - program = glCreateProgram(); - glAttachShader(program, vertex_shader); - glAttachShader(program, fragment_shader); - glLinkProgram(program); - glUseProgram(program); - - glBegin(GL_TRIANGLES); - glColor3f(1, 0, 0); - glVertex2i(-1, -1); - glColor3f(0, 1, 0); - glVertex2i(1, -1); - glColor3f(0, 0, 1); - glVertex2i(1, 1); - glEnd(); - - context->present(); - - glDeleteShader(vertex_shader); - glDeleteShader(fragment_shader); - glDeleteProgram(program); - - EXPECT_EQ(glGetError(), 0u); -} diff --git a/Tests/LibGL/reference-images/0001_simple_triangle.qoi b/Tests/LibGL/reference-images/0001_simple_triangle.qoi deleted file mode 100644 index cb3222aabc05b55b90e8e26847ad3400665bc423..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 277 zcmWmAMGnFM07TJ}aF)5j>^ThyE5Z$nyF>9(+}*VdKY17Up4i9YkZuq>$)c2 zF!@4+PkA85yWEiARW3;JEGJ}mlml|y%MJx@WrGsevOYFMDJ`jE&YD!QWJStYvm`}qS&%&T%t;nUW+aU>QNAT`j(A-Dx=2y_#NAT)X z(B4Pz;!n`oNAT=Rkk&`=(5;W) z#+{&hAHlUNfl432l^cOtAHk&yfodPYg}gw$kKjyNpwmZiA}i4ABRG~6==KpD$qDrP z2o9wLCVd14G6J(cf_({rX&=F!y}-PWVAob)(?_slC$Q@y*tQYa_7QBE3+(#{%BBK| zK7tK1flMDk$wVO4N3ff(12! zn?8bh6@jZhg4yl@cYOpi-2^WC2&VD{Zuh(e)|Xpn+3l62#O7X|2~3&x*$X!L4QpUrjMX65rpa^ U=ndINPzX1FvUiSuAta~p4+bUkSpWb4 diff --git a/Tests/LibGL/reference-images/0003_rect_w_coordinate_regression.qoi b/Tests/LibGL/reference-images/0003_rect_w_coordinate_regression.qoi deleted file mode 100644 index 262ab88039f78801baf5b6a6e733a70a61537b46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 344 zcmdUr%MF466a=4%1({9eZZ#&Jj2-ev5GlbD1Qg^aAeP}KGv~>kPsf9q?SE`-a_7a2 zNe&;mjPe-d(<`7;NUMmqVj5kjmGDx^Q&%cwl)6zUpKY-_x$@n=`mxp*+*FdO;;JX9 fUL>lys3F#yNG+i{0`>SB@HFD;gQJP{$KN(z$uFvE diff --git a/Tests/LibGL/reference-images/0004_points.qoi b/Tests/LibGL/reference-images/0004_points.qoi deleted file mode 100644 index 20695549e53335c7b9052133b6217fb315fce886..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 170 zcmXTS&rD-rU~m9o7KXp5;LN}O|NkE}y`yG&M(qF)A2fXprBT(P^REA!I(4d=f$8b3 k9sla<>kUj_Lkv0%;(?eT+7xWM=^b>nXomd)x(oyu0jXbf2mk;8 diff --git a/Tests/LibGL/reference-images/0005_lines.qoi b/Tests/LibGL/reference-images/0005_lines.qoi deleted file mode 100644 index c95b8683524410c54036a5ffb6460171f5d334fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2166 zcma)8ZA?>F7%r|rWmQp%D>w#BK-hp4;m8U?@CSkX;z zpXYs^`%O_{o=T-k5nr`xb#=8Lv9YnJsHi}9cQ;$6(6UcEwneLW5xI>i3L(W6Jv)YJr7meJACfvl`7e%EL;;^xhpSX^90e}6v; z3k%`n<6|NlLPJAw?b}?9rG-t3{vE{p{QS3sOP4Oe&(DuN+lmVp zE+~B(9UaA+H*YX7FaVRugj1(ZAvidg{pzyQC+# z{Ce&$a7eO)pk`0+lG1H{xFD}C3Pf3188R|5pwsE9XnG?)1~!I}kPw_ceL56FLqkT4 zjEtbRwiY=#If#geV6)oL&9DhBq^73g>eZ{dWM8zkwc*N@D@aaGhDM`dzd50*Q6L?G z!C*jMULG178!3||f4bzva0?+RDG8S^Uq)+dE9U0rw!v&RD_lE#_%OV^z1a(YiR@fqg9r}~$GLOo zP*YQb$B!R_4+DmWhvO7ZaGo-&g>dA^5tNpe;{N^nSYBSPCfvJsPr*4MApvT&npp)h z3PK#I?Y*Qx$0x@VdcB@4bdrV4q%!kh6v0A`#0CPfva*7)u`x6>G;Gnc>304|JhVs0 zFEiDXhl%z`WFm=wMEs5~A*fzP?CB3YM{iGaUcybH-S!kmvRHyW;}w0$3kuo4L*!~i zaEq4cBZ>505(V1R5+%Od6|Fs1J+V8E7Ui`>CVdVs~p20(R^d8yiJXu~DICNutG(TNDwS_76Yc z6a1CdOz|SmAcD>#LZWSs*6_X#dfTzYX^nC5f^HuRu6?G+oX{V^wdMaqYmZi1PwG&%v{^X6VDF|V>JvAivQERZ zDE2b$awxCsF;(oqKB+I>FXvnrR6-Plf+jc6CSh3Es6UE7I7^U_c7G=c`eU=(C_<-I zBwV<_%*+fwILFsn?&chl>Lt8O&psfhzbo49yI!~z1No44&%WOv{MCx-I9bH(n$PH* zOy;>TCdJ9P70>n1feq#)Z*}-sv@et2Z+fzwI>sQyA7xk4D!b5VSs?2|?q!#-$!oBz ZGauQ}?{zN=veMK*#wk9;k0vg+{{Z;W%pm{( diff --git a/Tests/LibGL/reference-images/0006_test_rgb565_texture.qoi b/Tests/LibGL/reference-images/0006_test_rgb565_texture.qoi deleted file mode 100644 index 888bded0d8e268ca2d594306b683d5b936809b55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 433 zcmXTS&rD-rU~m9o7KVTS85l1AJIcUtEVQ9XrcUj^J*8q^f2m%2{09m%ppa1{> diff --git a/Tests/LibGL/reference-images/0007_test_rgba_to_rgb_texture.qoi b/Tests/LibGL/reference-images/0007_test_rgba_to_rgb_texture.qoi deleted file mode 100644 index 73b517c1677c2441acfe9ccae5cf4538aad79f85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 277 zcmWmAM@~Wk007Z%;(=x}drxEH%6LOSDI&dhQE5t-B2p|&@-8rUw>Q^85L}&I2B+{( z@Edp{WM$@!;yl(5jw?EZNxnyR=T)|#{ zdGC*z%O_ku;PEau)OeK(>O9K{4Q7&}$)hCj8Os4JMzTknJK3VcjjYk-N<#Fwlm!CL VWrjYdGQogj8DYrZpGcp1&KH&=Xqo^3 diff --git a/Tests/LibGL/reference-images/0011_tex_env_combine_with_constant_color.qoi b/Tests/LibGL/reference-images/0011_tex_env_combine_with_constant_color.qoi deleted file mode 100644 index 493fe29130099c5df2d1306489170a044bbe5459..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 93 fcmXTS&rD-rU~m9o7KVR5^_%`u3=RPe0|7<=Vg5#} diff --git a/Tests/LibGL/reference-images/0012_blend_equations.qoi b/Tests/LibGL/reference-images/0012_blend_equations.qoi deleted file mode 100644 index a3ef80e7d36094672026c5cae9946ef6509feb83..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1961 zcmY+FQEKBz5Qep|&--F*Gz>z*SP?9;WwZz(KkWhXIyyoi1hVV}CU@EsRJCkbcIQl< z{r_smPSTP>x~l&Ay1Tma??2B^Q55~n_xI@X>+#q5=@Lb6^0JX;)9@pgw{MZ_D_2x< zdHnY1FYkYOdC^?Tyv&s`r)6QDjpMKC{HKTURQN`N3UxSJ4!J`}aaSQbD5h zGz`lEQD;n6in%E-h0{bMQnPU&1Q?b*kO@FnNoC5ymb!0TH9*w?J5N?{xcc~wHiCE4 zD4`Be&{c_%ucTZtQ4qn#fo`nSM2t>NMRHlbBFzDI?$H1jvXJ%W@e4Z9@u`+|IJ3@0 z-N57Ochl{tUe2};>$;POPb8h&^*dMNY5Z2&6YW0IZXb2JJ2(E~>vw4@ZL3x*sn@kz zBSo#&{cY-EXy(t<<`%55V$w8cb`; zr`gkF*gxtV4U&+~#R$62g!AOoMw^_j$(gZ(&9#9TDUd~pNq2p_vqp7CQg z^cmI}1C^i%o+lrudr-I;-4w`xo#@1cy1+?uoZ7Z#C)h?Clh_?!vJp(y zx)L_D`=5L3KvJT~p^31!`4EB5CYzJZpa)?Tx|Hxl4DE{^wq25aK*FwwxhcPF!>+zg#iq_AYi}+Vfy99jUb?_PX8!#4KPLh?NB{r; diff --git a/Tests/LibGLSL/CMakeLists.txt b/Tests/LibGLSL/CMakeLists.txt deleted file mode 100644 index 6edeb7549d4..00000000000 --- a/Tests/LibGLSL/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -set(TEST_SOURCES - test-parser.cpp -) - -foreach(source IN LISTS TEST_SOURCES) - serenity_test("${source}" LibGLSL LIBS LibGLSL) -endforeach() diff --git a/Tests/LibGLSL/test-parser.cpp b/Tests/LibGLSL/test-parser.cpp deleted file mode 100644 index 26fcecc4b3b..00000000000 --- a/Tests/LibGLSL/test-parser.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include - -constexpr StringView TESTS_ROOT_DIR = "/home/anon/Tests/glsl-tests/parser"sv; - -static String read_all(String const& path) -{ - auto file = MUST(Core::File::open(path, Core::File::OpenMode::Read)); - auto file_size = MUST(file->size()); - return MUST(String::from_stream(*file, file_size)); -} - -TEST_CASE(test_regression) -{ - MUST(Core::Directory::for_each_entry(TESTS_ROOT_DIR, Core::DirIterator::Flags::SkipDots, [](auto const& entry, auto const& directory) -> ErrorOr { - auto path = LexicalPath::join(directory.path().string(), entry.name); - if (!path.has_extension(".glsl"sv)) - return IterationDecision::Continue; - - outln("Checking {}...", path.basename()); - String file_path = MUST(String::from_byte_string(path.string())); - - auto ast_file_path = MUST(String::formatted("{}.ast", MUST(file_path.substring_from_byte_offset(0, file_path.bytes_as_string_view().length() - sizeof(".glsl") + 1)))); - - auto source = read_all(file_path); - auto target_ast = read_all(ast_file_path); - - GLSL::Preprocessor preprocessor(file_path, source); - GLSL::Parser parser(MUST(preprocessor.process_and_lex()), file_path); - auto root = MUST(parser.parse()); - - EXPECT(parser.errors().is_empty()); - - Vector memory; - memory.resize(8 * 1024 * 1024); - AK::FixedMemoryStream output_stream(memory.span()); - - MUST(root->dump(output_stream)); - - auto written_bytes = MUST(output_stream.tell()); - MUST(output_stream.seek(0)); - - String content = MUST(String::from_stream(output_stream, written_bytes)); - - auto equal = content == target_ast; - EXPECT(equal); - if (!equal) - outln("Failed on {}", path.basename()); - return IterationDecision::Continue; - })); -} diff --git a/Tests/LibPDF/BenchmarkPDF.cpp b/Tests/LibPDF/BenchmarkPDF.cpp deleted file mode 100644 index 35155098a20..00000000000 --- a/Tests/LibPDF/BenchmarkPDF.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2024, Nico Weber - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include - -static PDF::Value make_array(Vector floats) -{ - Vector values; - for (auto f : floats) - values.append(PDF::Value { f }); - return PDF::Value { make_object(move(values)) }; -} - -static PDF::PDFErrorOr> make_function(int type, ReadonlyBytes data, Vector domain, Vector range, Function&)> extra_keys = nullptr) -{ - HashMap map; - map.set(PDF::CommonNames::FunctionType, PDF::Value { type }); - map.set(PDF::CommonNames::Domain, make_array(move(domain))); - map.set(PDF::CommonNames::Range, make_array(move(range))); - if (extra_keys) - extra_keys(map); - auto dict = make_object(move(map)); - auto stream = make_object(dict, MUST(ByteBuffer::copy(data))); - - // document isn't used for anything, but UBSan complains about a (harmless) method call on a null object without it. - auto file = MUST(Core::MappedFile::map("linearized.pdf"sv)); - auto document = MUST(PDF::Document::create(file->bytes())); - return PDF::Function::create(document, stream); -} - -static PDF::PDFErrorOr> make_sampled_function(ReadonlyBytes data, Vector domain, Vector range, Vector sizes) -{ - return make_function(0, data, move(domain), move(range), [&sizes](auto& map) { - map.set(PDF::CommonNames::Size, make_array(sizes)); - map.set(PDF::CommonNames::BitsPerSample, PDF::Value { 8 }); - }); -} - -static PDF::PDFErrorOr> make_bench_sampled_function() -{ - Vector domain = { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f }; - Vector range = { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f }; - Vector sizes = { 9, 9, 9, 9 }; - Vector data; - size_t total_size = range.size() / 2; - for (auto size : sizes) - total_size *= static_cast(size); - data.resize(total_size); - return make_sampled_function(data.span(), move(domain), move(range), move(sizes)); -} - -BENCHMARK_CASE(function) -{ - auto bench_function = MUST(make_bench_sampled_function()); - - Vector inputs; - inputs.resize(4); - for (int i = 0; i < 500'000; ++i) { - inputs[0] = i * 31; - inputs[1] = i * 19; - inputs[2] = i * 103; - inputs[3] = i * 7; - auto result = MUST(bench_function->evaluate(inputs)); - VERIFY(result[0] == 0); - VERIFY(result[1] == 0); - VERIFY(result[2] == 0); - } -} diff --git a/Tests/LibPDF/CMakeLists.txt b/Tests/LibPDF/CMakeLists.txt deleted file mode 100644 index 3f4970bdb29..00000000000 --- a/Tests/LibPDF/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -set(TEST_SOURCES - BenchmarkPDF.cpp - TestPDF.cpp -) - -foreach(source IN LISTS TEST_SOURCES) - serenity_test("${source}" LibPDF LIBS LibCore LibGfx LibPDF) -endforeach() - -set(TEST_FILES - colorspaces.pdf - complex.pdf - encoding.pdf - encryption_nocopy.pdf - jbig2-globals.pdf - linearized.pdf - non-linearized.pdf - oss-fuzz-testcase-62065.pdf - password-is-sup.pdf - pattern.pdf - text.pdf - type1.pdf - type3.pdf -) -install(FILES ${TEST_FILES} DESTINATION home/anon/Documents/pdf) -install(FILES ${TEST_FILES} DESTINATION usr/Tests/LibPDF) diff --git a/Tests/LibPDF/TestPDF.cpp b/Tests/LibPDF/TestPDF.cpp deleted file mode 100644 index 8f3d7289b6e..00000000000 --- a/Tests/LibPDF/TestPDF.cpp +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (c) 2021, Simon Woertz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -TEST_CASE(parse_value) -{ - // document isn't really used for anything, only to check there's no security_handler. - auto file = MUST(Core::MappedFile::map("linearized.pdf"sv)); - auto document = MUST(PDF::Document::create(file->bytes())); - - auto contents = "<50607><10\n>"sv; - PDF::Parser parser(contents.bytes()); - parser.set_document(document->make_weak_ptr()); - - auto value1 = MUST(parser.parse_value(PDF::Parser::CanBeIndirectValue::No)); - auto string1 = value1.get>()->cast(); - EXPECT(string1->is_binary()); - EXPECT_EQ(string1->string(), "\x50\x60\x70"sv); - - auto value2 = MUST(parser.parse_value(PDF::Parser::CanBeIndirectValue::No)); - auto string2 = value2.get>()->cast(); - EXPECT(string2->is_binary()); - EXPECT_EQ(string2->string(), "\x10"sv); -} - -TEST_CASE(linearized_pdf) -{ - auto file = MUST(Core::MappedFile::map("linearized.pdf"sv)); - auto document = MUST(PDF::Document::create(file->bytes())); - MUST(document->initialize()); - EXPECT_EQ(document->get_page_count(), 1U); -} - -TEST_CASE(non_linearized_pdf) -{ - auto file = MUST(Core::MappedFile::map("non-linearized.pdf"sv)); - auto document = MUST(PDF::Document::create(file->bytes())); - MUST(document->initialize()); - EXPECT_EQ(document->get_page_count(), 1U); -} - -TEST_CASE(complex_pdf) -{ - auto file = MUST(Core::MappedFile::map("complex.pdf"sv)); - auto document = MUST(PDF::Document::create(file->bytes())); - MUST(document->initialize()); - EXPECT_EQ(document->get_page_count(), 3U); -} - -TEST_CASE(empty_file_issue_10702) -{ - AK::ReadonlyBytes empty; - auto document = PDF::Document::create(empty); - EXPECT(document.is_error()); -} - -TEST_CASE(encodig) -{ - auto file = MUST(Core::MappedFile::map("encoding.pdf"sv)); - auto document = MUST(PDF::Document::create(file->bytes())); - MUST(document->initialize()); - EXPECT_EQ(document->get_page_count(), 1U); - - auto info_dict = MUST(document->info_dict()).value(); - EXPECT_EQ(MUST(info_dict.author()).value(), "Nico Weber"); - EXPECT_EQ(MUST(info_dict.producer()).value(), (char const*)u8"Manüally Created"); - EXPECT_EQ(MUST(info_dict.title()).value(), (char const*)u8"Êñ©•ding test"); - - auto outline_dict = document->outline(); - EXPECT_EQ(outline_dict->count, 3u); - EXPECT_EQ(outline_dict->children[0]->title, (char const*)u8"Titlè 1"); - EXPECT_EQ(outline_dict->children[1]->title, (char const*)u8"Titlè 2"); - EXPECT_EQ(outline_dict->children[2]->title, (char const*)u8"Titlè 3"); -} - -TEST_CASE(truncated_pdf_header_issue_10717) -{ - AK::ByteString string { "%PDF-2.11%" }; - auto document = PDF::Document::create(string.bytes()); - EXPECT(document.is_error()); -} - -TEST_CASE(encrypted_with_aes) -{ - auto file = MUST(Core::MappedFile::map("password-is-sup.pdf"sv)); - auto document = MUST(PDF::Document::create(file->bytes())); - EXPECT(document->security_handler()->try_provide_user_password("sup"sv)); - MUST(document->initialize()); - EXPECT_EQ(document->get_page_count(), 1U); - - auto info_dict = MUST(document->info_dict()).value(); - EXPECT_EQ(MUST(info_dict.title()).value(), "sup"); - EXPECT_EQ(MUST(info_dict.creator()).value(), "TextEdit"); -} - -TEST_CASE(encrypted_object_stream) -{ - auto file = MUST(Core::MappedFile::map("encryption_nocopy.pdf"sv)); - auto document = MUST(PDF::Document::create(file->bytes())); - MUST(document->initialize()); - EXPECT_EQ(document->get_page_count(), 1U); - - auto info_dict = MUST(document->info_dict()).value(); - EXPECT_EQ(MUST(info_dict.author()).value(), "van der Knijff"); - EXPECT_EQ(MUST(info_dict.creator()).value(), "Acrobat PDFMaker 9.1 voor Word"); -} - -TEST_CASE(resolve_indirect_reference_during_parsing) -{ - auto file = MUST(Core::MappedFile::map("jbig2-globals.pdf"sv)); - auto document = MUST(PDF::Document::create(file->bytes())); - MUST(document->initialize()); - EXPECT_EQ(document->get_page_count(), 1U); - - auto jbig2_stream_value = MUST(document->get_or_load_value(5)); - auto jbig2_stream = MUST(document->resolve_to(jbig2_stream_value)); - EXPECT_EQ(jbig2_stream->bytes().size(), 20'000U); -} - -TEST_CASE(malformed_pdf_document) -{ - Array test_inputs = { - "oss-fuzz-testcase-62065.pdf"sv - }; - - for (auto test_input : test_inputs) { - auto file = MUST(Core::MappedFile::map(test_input)); - auto document_or_error = PDF::Document::create(file->bytes()); - EXPECT(document_or_error.is_error()); - } -} - -static PDF::Value make_array(Vector floats) -{ - Vector values; - for (auto f : floats) - values.append(PDF::Value { f }); - return PDF::Value { make_object(move(values)) }; -} - -static PDF::PDFErrorOr> make_function(int type, ReadonlyBytes data, Vector domain, Vector range, Function&)> extra_keys = nullptr) -{ - HashMap map; - map.set(PDF::CommonNames::FunctionType, PDF::Value { type }); - map.set(PDF::CommonNames::Domain, make_array(move(domain))); - map.set(PDF::CommonNames::Range, make_array(move(range))); - if (extra_keys) - extra_keys(map); - auto dict = make_object(move(map)); - auto stream = make_object(dict, MUST(ByteBuffer::copy(data))); - - // document isn't used for anything, but UBSan complains about a (harmless) method call on a null object without it. - auto file = MUST(Core::MappedFile::map("linearized.pdf"sv)); - auto document = MUST(PDF::Document::create(file->bytes())); - return PDF::Function::create(document, stream); -} - -static PDF::PDFErrorOr> make_sampled_function(ReadonlyBytes data, Vector domain, Vector range, Vector sizes) -{ - return make_function(0, data, move(domain), move(range), [&sizes](auto& map) { - map.set(PDF::CommonNames::Size, make_array(sizes)); - map.set(PDF::CommonNames::BitsPerSample, PDF::Value { 8 }); - }); -} - -TEST_CASE(sampled) -{ - auto f1 = MUST(make_sampled_function(Vector { { 0, 255, 0 } }, { 0.0f, 1.0f }, { 0.0f, 10.0f }, { 3 })); - EXPECT_EQ(MUST(f1->evaluate(Vector { 0.0f })), Vector { 0.0f }); - EXPECT_EQ(MUST(f1->evaluate(Vector { 0.25f })), Vector { 5.0f }); - EXPECT_EQ(MUST(f1->evaluate(Vector { 0.5f })), Vector { 10.0f }); - EXPECT_EQ(MUST(f1->evaluate(Vector { 0.75f })), Vector { 5.0f }); - EXPECT_EQ(MUST(f1->evaluate(Vector { 1.0f })), Vector { 0.0f }); - - auto f2 = MUST(make_sampled_function(Vector { { 0, 255, 255, 0, 0, 255 } }, { 0.0f, 1.0f }, { 0.0f, 10.0f, 0.0f, 8.0f }, { 3 })); - EXPECT_EQ(MUST(f2->evaluate(Vector { 0.0f })), (Vector { 0.0f, 8.0f })); - EXPECT_EQ(MUST(f2->evaluate(Vector { 0.25f })), (Vector { 5.0f, 4.0f })); - EXPECT_EQ(MUST(f2->evaluate(Vector { 0.5f })), (Vector { 10.0f, 0.0f })); - EXPECT_EQ(MUST(f2->evaluate(Vector { 0.75f })), (Vector { 5.0f, 4.0f })); - EXPECT_EQ(MUST(f2->evaluate(Vector { 1.0f })), (Vector { 0.0f, 8.0f })); - - auto f3 = MUST(make_sampled_function(Vector { { 0, 255, 0, 255, 0, 255 } }, { 0.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 10.0f }, { 3, 2 })); - EXPECT_EQ(MUST(f3->evaluate(Vector { 0.0f, 0.0f })), Vector { 0.0f }); - EXPECT_EQ(MUST(f3->evaluate(Vector { 0.25f, 0.0f })), Vector { 5.0f }); - EXPECT_EQ(MUST(f3->evaluate(Vector { 0.5f, 0.0f })), Vector { 10.0f }); - EXPECT_EQ(MUST(f3->evaluate(Vector { 0.75f, 0.0f })), Vector { 5.0f }); - EXPECT_EQ(MUST(f3->evaluate(Vector { 1.0f, 0.0f })), Vector { 0.0f }); - - EXPECT_EQ(MUST(f3->evaluate(Vector { 0.0f, 0.5f })), Vector { 5.0f }); - EXPECT_EQ(MUST(f3->evaluate(Vector { 0.25f, 0.5f })), Vector { 5.0f }); - EXPECT_EQ(MUST(f3->evaluate(Vector { 0.5f, 0.5f })), Vector { 5.0f }); - EXPECT_EQ(MUST(f3->evaluate(Vector { 0.75f, 0.5f })), Vector { 5.0f }); - EXPECT_EQ(MUST(f3->evaluate(Vector { 1.0f, 0.5f })), Vector { 5.0f }); - - EXPECT_EQ(MUST(f3->evaluate(Vector { 0.0f, 1.0f })), Vector { 10.0f }); - EXPECT_EQ(MUST(f3->evaluate(Vector { 0.25f, 1.0f })), Vector { 5.0f }); - EXPECT_EQ(MUST(f3->evaluate(Vector { 0.5f, 1.0f })), Vector { 0.0f }); - EXPECT_EQ(MUST(f3->evaluate(Vector { 0.75f, 1.0f })), Vector { 5.0f }); - EXPECT_EQ(MUST(f3->evaluate(Vector { 1.0f, 1.0f })), Vector { 10.0f }); - - auto f4 = MUST(make_sampled_function(Vector { { 0, 255, 255, 0, 0, 255, 255, 0 } }, { 0.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 10.0f, 0.0f, 8.0f }, { 2, 2 })); - EXPECT_EQ(MUST(f4->evaluate(Vector { 0.0f, 0.0f })), (Vector { 0.0f, 8.0f })); - EXPECT_EQ(MUST(f4->evaluate(Vector { 0.5f, 0.5f })), (Vector { 5.0f, 4.0f })); -} - -static PDF::PDFErrorOr> make_postscript_function(StringView program, Vector domain, Vector range) -{ - return make_function(4, program.bytes(), move(domain), move(range)); -} - -static NonnullRefPtr check_postscript_function(StringView program, Vector domain, Vector range) -{ - auto function = make_postscript_function(program, move(domain), move(range)); - if (function.is_error()) - FAIL(function.error().message()); - return function.value(); -} - -static void check_evaluate(StringView program, Vector inputs, Vector outputs) -{ - Vector domain; - for (size_t i = 0; i < inputs.size(); ++i) { - domain.append(-100.0f); - domain.append(100.0f); - } - Vector range; - for (size_t i = 0; i < outputs.size(); ++i) { - range.append(-100.0f); - range.append(100.0f); - } - auto function = check_postscript_function(program, domain, range); - auto result = function->evaluate(inputs); - if (result.is_error()) - FAIL(result.error().message()); - EXPECT_EQ(result.value(), outputs); -} - -TEST_CASE(postscript) -{ - // Arithmetic operators - check_evaluate("{ abs }"sv, { 0.5f }, { 0.5f }); - check_evaluate("{ add }"sv, { 0.25f, 0.5f }, { 0.75f }); - check_evaluate("{ atan }"sv, { 1.0f, 0.01f }, { AK::to_degrees(atan2f(0.01f, 1.0f)) }); - check_evaluate("{ ceiling }"sv, { 0.5f }, { 1.0f }); - check_evaluate("{ cos }"sv, { 1.0f }, { cosf(AK::to_radians(1.0f)) }); - check_evaluate("{ cvi }"sv, { 0.5f }, { 0.0f }); - check_evaluate("{ cvr }"sv, { 0.5f }, { 0.5f }); - check_evaluate("{ div }"sv, { 0.5f, 1.0f }, { 0.5f }); - check_evaluate("{ exp }"sv, { 0.0f }, { 1.0f }); - check_evaluate("{ floor }"sv, { 0.5f }, { 0.0f }); - check_evaluate("{ idiv }"sv, { 0.5f, 1.0f }, { 0.0f }); - check_evaluate("{ ln }"sv, { 10.0f }, { logf(10.0f) }); - check_evaluate("{ log }"sv, { 10.0f }, { log10f(10.0f) }); - check_evaluate("{ mod }"sv, { 0.5f, 0.25f }, { 0.0f }); - check_evaluate("{ mul }"sv, { 0.5f, 0.25f }, { 0.125f }); - check_evaluate("{ neg }"sv, { 0.5f }, { -0.5f }); - check_evaluate("{ round }"sv, { 0.5f }, { 1.0f }); - check_evaluate("{ sin }"sv, { 1.0f }, { sinf(AK::to_radians(1.0f)) }); - check_evaluate("{ sqrt }"sv, { 0.5f }, { sqrtf(0.5f) }); - check_evaluate("{ sub }"sv, { 0.5f, 0.25f }, { 0.25f }); - check_evaluate("{ truncate }"sv, { 0.5f }, { 0.0f }); - - // Relational, boolean, and bitwise operators - check_evaluate("{ and }"sv, { 0.0f, 1.0f }, { 0.0f }); - check_evaluate("{ bitshift }"sv, { 1.0f, 3.0f }, { 8.0f }); - check_evaluate("{ bitshift }"sv, { 8.0f, -2.0f }, { 2.0f }); - check_evaluate("{ eq }"sv, { 0.5f, 0.5f }, { 1.0f }); - check_evaluate("{ ge }"sv, { 0.5f, 0.5f }, { 1.0f }); - check_evaluate("{ gt }"sv, { 0.5f, 0.5f }, { 0.0f }); - check_evaluate("{ le }"sv, { 0.5f, 0.5f }, { 1.0f }); - check_evaluate("{ lt }"sv, { 0.5f, 0.5f }, { 0.0f }); - check_evaluate("{ ne }"sv, { 0.5f, 0.5f }, { 0.0f }); - check_evaluate("{ not }"sv, { 0.5f }, { 0.0f }); - check_evaluate("{ or }"sv, { 0.0f, 1.0f }, { 1.0f }); - check_evaluate("{ xor }"sv, { 0.0f, 1.0f }, { 1.0f }); - - // Conditional operators - check_evaluate("{ { 4 } if }"sv, { 1.0f }, { 4.0f }); - check_evaluate("{ { 4 } if }"sv, { 0.0f }, {}); - check_evaluate("{ { 4 } { 5 } ifelse }"sv, { 1.0f }, { 4.0f }); - check_evaluate("{ { 4 } { 5 } ifelse }"sv, { 0.0f }, { 5.0f }); - - // Stack operators - check_evaluate("{ 2 copy }"sv, { 8.0f, 0.5f, 1.0f }, { 8.0f, 0.5f, 1.0f, 0.5f, 1.0f }); - check_evaluate("{ dup }"sv, { 1.0f, 0.5f }, { 1.0f, 0.5f, 0.5f }); - check_evaluate("{ exch }"sv, { 8.0f, 1.0f, 0.5f }, { 8.0f, 0.5f, 1.0f }); - check_evaluate("{ 1 index }"sv, { 8.0f, 1.0f, 0.5f }, { 8.0f, 1.0f, 0.5f, 1.0f }); - check_evaluate("{ pop }"sv, { 8.0f, 1.0f, 0.5f }, { 8.0f, 1.0f }); - check_evaluate("{ 3 1 roll }"sv, { 0.5f, 1.0f, 2.0f }, { 2.0f, 0.5f, 1.0f }); - check_evaluate("{ 3 -1 roll }"sv, { 0.5f, 1.0f, 2.0f }, { 1.0f, 2.0f, 0.5f }); -} - -TEST_CASE(render) -{ -#if !defined(AK_OS_SERENITY) - // Get from Build/lagom/bin/TestPDF to Build/lagom/Root/res. - auto source_root = LexicalPath(MUST(Core::System::current_executable_path())).parent().parent().string(); - Core::ResourceImplementation::install(make(MUST(String::formatted("{}/Root/res", source_root)))); -#endif - - auto file = MUST(Core::MappedFile::map("colorspaces.pdf"sv)); - auto document = MUST(PDF::Document::create(file->bytes())); - MUST(document->initialize()); - EXPECT_EQ(document->get_page_count(), 1U); - - auto page = MUST(document->get_page(0)); - auto page_size = Gfx::IntSize { 310, 370 }; - auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, page_size)); - MUST(PDF::Renderer::render(document, page, bitmap, Color::White, PDF::RenderingPreferences {})); - - // DeviceGray - EXPECT_EQ(bitmap->get_pixel(270, 370 - 20), Gfx::Color::NamedColor::Black); - - // MyCalRGB - EXPECT_EQ(bitmap->get_pixel(270, 370 - 80), Gfx::Color::NamedColor::Black); - - // DeviceRGB - EXPECT_EQ(bitmap->get_pixel(270, 370 - 140), Gfx::Color::NamedColor::Black); - - // DeviceCMYK (note: black one box further left) - EXPECT_EQ(bitmap->get_pixel(220, 370 - 200), Gfx::Color::NamedColor::Black); - - // MyLab - EXPECT_EQ(bitmap->get_pixel(270, 370 - 260), Gfx::Color::NamedColor::Black); - - // MyCalGray - EXPECT_EQ(bitmap->get_pixel(270, 370 - 320), Gfx::Color::NamedColor::Black); -} diff --git a/Tests/LibPDF/colorspaces.pdf b/Tests/LibPDF/colorspaces.pdf deleted file mode 100644 index 14b2cae6cb2..00000000000 --- a/Tests/LibPDF/colorspaces.pdf +++ /dev/null @@ -1,96 +0,0 @@ -%PDF-1.3 -%µ¶ - -1 0 obj -<> -endobj - -2 0 obj -<> -endobj - -3 0 obj -<> -endobj - -4 0 obj -<>>> -endobj - -5 0 obj -[/CalRGB<>] -endobj - -6 0 obj -[/Lab<>] -endobj - -7 0 obj -[/CalGray<>] -endobj - -8 0 obj -<> -stream -/DeviceGray cs -0.2 sc 10 10 50 50 re f -0.5 sc 70 10 50 50 re f -0.8 sc 130 10 50 50 re f -1.0 sc 190 10 50 50 re B -0.0 sc 250 10 50 50 re f - -/MyCalRGB cs -1 0.5 1 sc 10 70 50 50 re f -0.8 1 0 sc 70 70 50 50 re f -1 1 0.5 sc 130 70 50 50 re f -1 1 1 sc 190 70 50 50 re B -0 0 0 sc 250 70 50 50 re f - -/DeviceRGB cs -1 0.5 1 sc 10 130 50 50 re f -0.8 1 0 sc 70 130 50 50 re f -1 1 0.5 sc 130 130 50 50 re f -1 1 1 sc 190 130 50 50 re B -0 0 0 sc 250 130 50 50 re f - -/DeviceCMYK cs -0 0.5 1 0.1 sc 10 190 50 50 re f -0.8 1 0 0.1 sc 70 190 50 50 re f -1 0 0.5 0.1 sc 130 190 50 50 re f -1 1 1 1 sc 190 190 50 50 re f -0 0 0 0 sc 250 190 50 50 re B - -/MyLab cs -80 -120 120 sc 10 250 50 50 re f -80 90 0 sc 70 250 50 50 re f -80 0 0 sc 130 250 50 50 re f -100 0 0 sc 190 250 50 50 re B -0 0 0 sc 250 250 50 50 re f - -/MyCalGray cs -0.2 sc 10 310 50 50 re f -0.5 sc 70 310 50 50 re f -0.8 sc 130 310 50 50 re f -1.0 sc 190 310 50 50 re B -0.0 sc 250 310 50 50 re f - -endstream -endobj - -xref -0 9 -0000000000 65536 f -0000000016 00000 n -0000000068 00000 n -0000000114 00000 n -0000000220 00000 n -0000000299 00000 n -0000000460 00000 n -0000000538 00000 n -0000000607 00000 n - -trailer -<> -startxref -1643 -%%EOF diff --git a/Tests/LibPDF/complex.pdf b/Tests/LibPDF/complex.pdf deleted file mode 100644 index 4d7a58dcb6f..00000000000 --- a/Tests/LibPDF/complex.pdf +++ /dev/null @@ -1,93 +0,0 @@ -%PDF-1.1 -1 0 obj -<< /Kids [2 0 R 3 0 R] /Type /Pages /Count 3 >> -endobj -4 0 obj -<< >> -stream -1. 0.000000 0.000000 1. 50. 770. cm BT /F0 36. Tf (Page One) Tj ET -endstream -endobj -2 0 obj -<< - /Rotate 0 - /Parent 1 0 R - /Resources - << /Font << /F0 << /BaseFont /Times-Italic /Subtype /Type1 /Type /Font >> >> >> - /MediaBox [0.000000 0.000000 595.275590551 841.88976378] - /Type /Page - /Contents [4 0 R] ->> -endobj -5 0 obj -<< /PageLayout /TwoColumnLeft /Pages 1 0 R /Type /Catalog >> -endobj -6 0 obj -<< - /Rotate 0 - /Parent 3 0 R - /Resources - << /Font << /F0 << /BaseFont /Times-Italic /Subtype /Type1 /Type /Font >> >> >> - /MediaBox [0.000000 0.000000 595.275590551 841.88976378] - /Type /Page - /Contents [7 0 R] ->> -endobj -3 0 obj -<< /Parent 1 0 R /Kids [8 0 R 6 0 R] /Count 2 /Type /Pages >> -endobj -8 0 obj -<< - /Rotate 270 - /Parent 3 0 R - /Resources - << /Font << /F0 << /BaseFont /Times-Italic /Subtype /Type1 /Type /Font >> >> >> - /MediaBox [0.000000 0.000000 595.275590551 841.88976378] - /Type /Page - /Contents [9 0 R] ->> -endobj -9 0 obj -<< >> -stream -q 1. 0.000000 0.000000 1. 50. 770. cm BT /F0 36. Tf (Page Two) Tj ET Q -1. 0.000000 0.000000 1. 50. 750 cm BT /F0 16 Tf ((Rotated by 270 degrees)) Tj ET -endstream -endobj -7 0 obj -<< >> -stream -1. 0.000000 0.000000 1. 50. 770. cm BT /F0 36. Tf (Page Three) Tj ET -endstream -endobj -10 0 obj -<< - /Title (PDF Explained Example) - /Author (John Whitington) - /Producer (Manually Created) - /ModDate (D:20110313002346Z) - /CreationDate (D:2011) ->> -endobj xref -0 11 -0000000000 65536 f -0000000009 00000 n -0000000177 00000 n -0000000731 00000 n -0000000072 00000 n -0000000416 00000 n -0000000492 00000 n -0000001239 00000 n -0000000808 00000 n -0000001049 00000 n -0000001346 00000 n -trailer -<< - /Info 10 0 R - /Root 5 0 R - /Size 11 - /ID [<75ff22189ceac848dfa2afec93deee03> <75ff22189ceac848dfa2afec93deee03>] ->> -startxref -1516 -%%EOF diff --git a/Tests/LibPDF/encoding.pdf b/Tests/LibPDF/encoding.pdf deleted file mode 100644 index 2b24c45407e..00000000000 --- a/Tests/LibPDF/encoding.pdf +++ /dev/null @@ -1,73 +0,0 @@ -%PDF-2.0 -%µ¶ - -1 0 obj -<> -endobj - -2 0 obj -<> -endobj - -3 0 obj -<>>>>> -endobj - -4 0 obj -<> -stream -BT -/F1 24 Tf -30 TL -40 220 Td -(The last line should say `abcd` three times,) ' -(prefixed with nothing, ``, and ``:) ' -T* [ (abcd) -800 (abcd) -800 (abcd) ] TJ -ET - -endstream -endobj - -5 0 obj -<> -endobj - -6 0 obj -</Producer(\357\273\277Man\303\274ally Created)/Title(\312\361\251\200ding test)>> -endobj - -7 0 obj -</Parent 10 0 R/Next 8 0 R>> -endobj - -8 0 obj -<> -endobj - -9 0 obj -</Parent 10 0 R/Prev 8 0 R>> -endobj - -10 0 obj -<> -endobj - -xref -0 11 -0000000000 65536 f -0000000016 00000 n -0000000078 00000 n -0000000130 00000 n -0000000243 00000 n -0000000464 00000 n -0000000562 00000 n -0000000715 00000 n -0000000801 00000 n -0000000876 00000 n -0000000952 00000 n - -trailer -<> -startxref -1005 -%%EOF diff --git a/Tests/LibPDF/encryption_nocopy.pdf b/Tests/LibPDF/encryption_nocopy.pdf deleted file mode 100644 index fe0efce40d675561c3f5afcb223016e275083dd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70599 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 z 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 Ub7D~m*f$ntmRzc;uKsRZ03wo9pa1{> diff --git a/Tests/LibPDF/linearized.pdf b/Tests/LibPDF/linearized.pdf deleted file mode 100644 index 34f8324f24f0b92140148fcf6ac8ef40e8e74581..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3908 zcmcInYiu0V6*k~DiD6u5et<*~w+^nIV(;9U+1c3vCuF^TBqV;|-H<>Ccy{-CJz;mo znYr88q&27y-W3G}lZZ&6juZ(Z5JiYIMc{;ocqIZv1OZuK@u<|2zz?WYK^t+--G|q^ z+q4nt%xdR8&N=tobIy0}xy^%JJ?%m{l6|-txRSScW z@tN0IH9}SLG{sOW=`>AOD#s`~qe31Hm#@n`%g!(ld@9K?@Fr2hlDx(lalucN41vdn zT$dBrx#$df>=)oWRfUN)U7I>m1|128l6t}lj<9ed6*Mg~m7=<7CTK#@m6iXUVlza6 z3zuRpJ~76K9JRQWanqo|pp|Am0ZRzo2F92ZNpjnDAPRLc zC~v&(dgA0VnX*5OOJwYGQy^@;&-z`5EeJ)7o8qE!3?i4vJ$8mO555_Tvo4ktyz7{g z=A#6|2Nb|q_PNKbtkkgjuEg;092*|~=5Ss8?h7w^@~pcIo; z8xQ<--)qym8dqI#TirQz2WA#MjYud6C}2WJ#@*{$2`9L*3WMNo#HKvv@RB)(nD6Gi zBp3*{gPx4K4hIUKV9<(@K9;hrPInv(hC?AmC5EXA=tezvtoF>1%fSdhUJlK4U&mQBh2eyg$Ni<&A#AFt=##S>s zJ<5Sml93MQ+EoY)2}2<56D^2MkkXkqQo9ZaZ`Y_nRH}x-!qCDj z+lJh%<-p7uh+;b#anc!KOF70__F7!9Omj3*4b6c&mP>GfhPanw0vE8B?fE=9YI#IM ze6F*~dmHQ&AN9c{s!oMw-3~;t?WBpk!FD2!ZfcKDg6)ZtIE5dLOxM?ze}Gmwwte)G)oIY5AQq>Fga% z>pSn?{q`*#U!CyfsSneu=8Ru2-v8LyM?Y%2{P!R1Jn!z=#J;{COtws2xc7G>_lBh8 zvZ?oeRR8AQx8@#x@|R1Nygu{P4aa}H_S{K*;Lktbv)^kBym3swdG94#o|@fv?y-r; zA5Wg&z51Yj>vg9--Prb%sa?;!z2%(GuWs9UQ+lF4`PmJRY~L~Y?ey`JpDv#1G}|sa z_BSKEQc^4mACyr*Zq}-)~&MbL~He&s%oo%h$Gi9+Fyae`fZo$A+(3vHPB9w;z9Z zkNwu+T}?-)FL`(CeT(|8UiV>c#qysuKflDDxHS6gUrs)-XlU)8*I(K3+M?q(&Aj~h z(>+&A?yfh!?(Oh5YA2@02ey8DaN>&>zMgvM#(yoQb^rd;eLEVeb0VHgH84>N%_g}1 zG-yVs7toA&DMxb%Fx;*|JgF3ruFzn(0?iT6wlZy=Q_xbh8!5bXF?&X)X?014`U@<4va z^ZTweX|Z20;Jk&46SY|LJ}Oe=zf~SUbLvnk^|FTHzY=9b^wKBme*a diff --git a/Tests/LibPDF/non-linearized.pdf b/Tests/LibPDF/non-linearized.pdf deleted file mode 100644 index 774c2ea70c55104973794121eae56bcad918da97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13264 zcmaibWmsIxvUW%|5FkJZ7A&~y%m9Oj;I6>~WPrgfxD$eVfZ*=#?hsspJHa(bATYRn zGueBev(G*EKHr+BrK+pDs^6;aH9u<6Dv3$30@ygwX}fZ|TDt1G($Rqw927PN=I8~c_R69-cY5S*jJE@5Wr0JUS6u!J~3#h`{ZMo=LkbbALoD8vfgB}Fh|2>mhOnfS$3 zNV5}8Ox=$fj;C0=UKy*{myZZPRVS|0mqr-HxZAy;()@wxQ}MN`QWAZTXb3Z&Om9W2 zbnA^OWoQbAW|3W^fw#J;YzDato8*`rHQs+@W70D&SyT{wb`SN*3nI z5G%$wJlq932=n{60Eii*9H8dFih2ks?QY=>nAFL=5g^P@#b{YUEHt0S$D7WbX zx%TzvzIK%zpvzLEd9LNr0ch#LFf_(9 zEGt0C9v~%b54vynAc{~;v&2?S(-sTTft@9CABMNFZHtY1W0-99CEbUNfp_yu{LDBz z@8z^$LPN$wX4Hi+dZQs6K3QiKKF0}Nme@EII;;F}IplC(YvT*C3-Oh#(A}e5pIz01 zyR}D2|ftBF0T=1moHZy}$wS*PSCmSzHQ%x z2tCQQCx4jt7w1cuhY69~eH`31KC4)ZZJ^)f=IabocAkBPa zEeg25yPX&9-i_N(Qiq!I3RDrfx&0t^i)&MSQ1D(w%|%#LTNr>1cPiltAYO;6kBn(B?r11c^Bz~#)z5~~V+*`U)lDFtKbZ|;? z&4wTUtK=KE&uQIWUQv1mDE;LIhXXgx44PMa@%Z<7a& zx45^oYSnei^~%}`?!O-+cgfSmn_c?`=Gmm*Z^I(96ve&$zDs|)r84)IEEiE1kfQ$q zm3km*m1)PjdU9nkk9BTlidI1~M|O~WfP7AUu2T}d>5is9l$<%;7r2&Re06w>W$KM~ zqITBTd=Ln>^crw`_N?{ z;2d_=E0n!*NisQ|XYuX9q3+UcqdA(MC45|>2tz^c6HdZOmXTB?X2Elx@_0f)1z&-gS;UxN`>Ll-kWb0X0 zTrQis=w9sJ(q7k|@|k3SA~DJ@uMXP@4(Mgn+LJC+3F~3NHW71pIzY(aHg~{O+squi zWO_|F>78)L5*gcRXXRD9IzQ(ddSxh}E7(8sC~EYrOz$9BkSMBCkGGO9FuZ{#*mW+h zvwE7d)6Ag=a*R5URs>}qdqb_E6g)kN2Wel;pWe9=hZ)XvRZR!RQg&gxAPGj8J0!gR zrdV<2@MZQ?_Ocbd5@0zI?t>$z3eD80_h^{DI)H5lk`T4lbn8kteH3%fOBH^g26#lLN2&P^s zr&d05GDs)u_8OKzCgNxllk5pLC<2wKmghL{zW%}5^}%S$?d=3OzjaSzT3>uWYikZN z2ZcR7*L|%UMs|u)wMi7#vkN?cxlBcyAM80Tyzzv&zHMF1TH9?Mx5&E57P^)^zE5N| z^foq}!--if$Uj=U6Tc>EM!Pv)e^_SZSdvtQ=@>)(ONejQ!XW8u6>ESl<*s^6cH;Q1 z#n}nL{#|{l}}@td^zNSA;R{`3A&Jjr8L9(3^2FSyZ1W9$%;!XP#N2 z-SAzyRfxtgq^py7_3*GJFO%x_v<`xJ46`~S*IukgQDKfLxzFnS&GYL!1LA{I z!c#{A90{k(b*tUfbgjOH>}{#V;%^O+LUU<*#QkLtWzjho*Kb?Cr&wC38%wxpn}^Wy zG6EpV9x3xioCWA6H6=aE3)%jmZePu#Ji7wy0CmkDZNG`a{J1i-2`Bt&UrFb&<~V$^ zy9i`R1<35M&{mtCz144%v#7LKBTPPApjoV}#W-gDc5cn;A@Mbt#zXUK@J9^vj*ME( zo8(%K{c-KDr8n1-I&Mjn)*i|pF|7l*`fXvo8-z&j{$NOfUPM-xILbX1D29IHp|__B zL*JQ8*7-VrZVY*&$!PiE%zv@osg`qx0M8+w9iy7Az7;HYezs;5NRvrdNM~t@o}5Gc zjagk3Y_>6!Ct;ITqhu3FojJO^(^SG-($M4|frkp?4y-QoSmFcw9Z%(z?eC0kGi9@? zm(vAgXU|%!6_)CrnqYL-Hj@B5hA?#8C3G^cjd?0dMSZ!wbe%O4bWvlIG=nwOEInVj zhjzd`Bry8sXBTfIUr+juZH5JyE#7~UQiwR!gmG@wm}aNyo`13xEo)tzP64MWWG|j8 z8u8a2_=C2FdRZ9(eG&Au`@$mY9vvWldP-@wj5@38H0W2V8wnaQO?!)qoS_J=(ieoI zOvH}mkBRh_p1oTW66+?3u-GH2Ex~c=BQiwpJ zJlF7O2PBaCojRRL_mp44*Iq}vcRFpBD>V9M7do5{w&b;4^<_V~Vr{+O_&hz9k5Sm` zq3|%Z(6B5~wz2k0iH-QlafAa>1%ZebdxkR;6SdA?@dK|4Jf8PIO%64Fpw$6RYG2R# zX>Iq(xf`5Xk)79-@;BAQjlWu|w@Ss3sJv3Ew&%lBu-H?vYsC8XPJD!lkv*A~z_-k= zLOaM?B5}$Sf-KF5BWHoB51WFA{GlweQna618{*tqVn)YKUVq?khU_=QER9uW?N17xgAponbjg0W`=>f;sulH3?st)Y_@k$We2-__a>^{E78lUiI13qq!3# zwxMEl75MK1q`~J>ST#?`mUx#vr%-jwpZ+DV;W!0KNkZmO#sK)zt)H@`EQl6RRWhwb z0&E7|fG~@z)wlK1-RsxN#8Gr)D5=xpv=b}=CWPbwz@(9bIhD0Crd-Q>qEo>~Gh{X7 z77AK5>TfF0wK!?7Nx!<5uDy?D{Qg$SEc_R3J9EuH!Z@qmEJ*QRRHd3BPirM6783nv zAnab$>rhdDJ6pO@%Ox(}BYw{Ba<3|=A%Fg5_Hfxj{%CfzZCFO{?%h&=?%CNBvi&p; z(otqN>+5giLLa^*G?xzN30=IgQrV+r7dW4bX;zKtuD)O$UnwAKC?CpkPt{77nUArH ze-jKcCfRrOlp(Q^b&W}mrgt4n%wikNxeSBBE_n>K-IOIzi6!<)xGRYA)wGgqp^s@d46N#krDHPc#9SOgXhI7Vbj?B z%c6@8dCOGPYBoNE#3N7HD^ihbC9*xGm6chu;?fcuv)s01keHHZ1vXl5D;29O7wZBr zyPzyLZHKMtUI%PK+*X2zTFtaDzU1qn(H=hRRj-SoJw7I5i%4b0u=&InEAKgoae-lp zXk0SkjlJ52HruS*1QykTZ&aCN`PbcKuw$1st{peJ@&aF^aR@~{XA@L&YvK%+VU}G4 ze5iuesu&i6=*#nvHbm_v-ZLr5^Ij#|YSAper4XpsH;0x(2h1-tIobIy;0~2a( z!G($SB!iu#P;;hGeI~C`O=-3|d~zoB0!`*JrU-)Ko_X5#kSpy5o^z49RG;{j#l~45 zF?X9Ih4IdviT(8@+q|`BveLTprbESZ6^2I&ew|V3pDXRe9gSyXT)zzqKQ;gCD;p+( zM)2(;YJ%P5)X(N3ZSn>dn6UIcEcvQOXZBn}uD!7V0yXr$f+d@eTSYoquPit2S8cPW zA8t3dX)Cv{0cKF`@e|PP(xS0|z2_R0(P6)#+kC$0^5- z$7Hs|bOQanE z1oJ;uh(dYiDt}mVmtC3&HaGT6-dY429v#ySHJ7V)C8ow=PSmnEI)=b3_RJsU(S*+J zV$p3>RkK?DFvTc;(-T=h!1u~CP!pE=0eSSu#c@N7S0Z57CPg}!5z{QL#`2v?DJDt^ zCGN{0p-&&=)Sb28Xlo;ZXc^CGdwL9prf30uu$y5aPeWD6WIk4%%~DEhTiwOvy!rS% z&3z#DWo2qBA*=M2xIu=_R0sbrmP;Y?_rRa^k}3WYU6n9H^(})Zi-woMKKXfgbab@J zWx3DUr0MLpdDYk_LO8As}d*Z=x^K+uIv#T&SnY6&C$9 zBn1u`G#TBt+n5b%a;Cr0h^sm5Fl^OdxJ^8IebW);DWATq#Ba=#rggj*wNKy5NMzz& zBm`bk9bcSVPJbC`dHrI>o^=LSvTFpT`VAK`x_naOpvS~*l2$1vIk$avBA!|aeZ+7c z$_9Zzh>fc4$uX&w@-$VORCscG(B)OA@SPj>BNY3gxkkcPgNi9bE=?&3A4`3ekrdsb zn~`M;p8I>4?@@ZI{9Afv(tC@pp@Oe5BYUw-%&J_WaTBGls)&d8q?t$i<<@=_CNfH! z4H!ww7#gkp_^`bxZaJI9@C+A9x7@E1ZRoG5PL?w3GDi>`8Qq%I+0ygfT78%{Zt#mP zqX0CzaHKn@hAOQsv=^8UbfpuyFnT8Ht++Vmmx$~09!e{5t8fMkEjr~tfIxMlIpr4zGwvEIWKC2`Q#C)c7QF9wet?hE zLKoU?t@nqm=iBc` z8_((*(i(g}7z)3{%SJ!uya{?Ir-2^Fiap*VC4pF@N zpL5F*DG+(taLhdu4DbyAP(0&60n@%?G~hHugBI^-X6@_YOu}8UqwbQ8V`2vwDRLMz z)aRFo+r1f?5idT9xRF`cjgx$a-IpH3AH|bs$emw}d23*3aU0hYNh4(D0o-Z+wIX{d zeann?lzjgsAt62`er@<$`G755?i7tl%CHNgXp}#j>j&S1n5wZ;ofNbI>B2*4L1}@3 zq(LzPqn()w{KBsX!5*a&=dv<}t=R%II;TcQatbnKM7S4Q1PQIoT=^$#=>Y(m{mBYtl5W z6}|l4kxikOcJ`C3o{TSxIi?8|N6sH7Lkhq5qttl@uBTA|-cBluU$hU0&xYKvNidrL z4q>|j76}G1Db23Fa|XlFm%W&jW0h#7B$_FD-ZhqJ5#7i!0ZmCrereX z|Jlf`<1zR2akFe|boWv-r=}kM03o|%$mZA7Of2T99u~e56~6sh$P=yk9f!H6msn)n zvFOLF?W?iqi6fK9C)a42Sgt0kz4#M6 z-UY6451Er~=V;ITs1O-q*>}{;bs74MMZ(Z&=Z{5#q+i@cw^vI#0|Dh~-Dh-tn2I(S zTXXp-bLEG{p0#BbIqIcTM|DWZmr`&br8u)jQ`CR*^+g_fIX%=K+)x}F%Oak-Uh$6nIHUavnNV5M7YffU80QPRD%y>T{bIzn<6Rsy zb6cW6`?0EwSn;uJddPn@`?^Cry2s(6ccP1ykKr!kmDg2~zbTJq@+e(z5N>ZNr|8$j zPi-~ofp7E|Xx1#H+f@UR@AS}iLP!}}dRwf{u!avAq-_hNw#uaoOD{2jo*eRn8$~bDK`h1&ssOC6ekGV38+hU!KR z+kpnSzT;y#o|V2h|F?SY4-z1MFxz0;)@Lk`H>Cj zSl@fR%*@F79;HJcsX%L8_d!%TwmQyi$|n&C{oBMJ9~Xm!@@#lZdz(WB9SgJ#NIC%@ zy+~ZnI|4E`7f@W0Y9I@N7UTs1fTPD-ZiU%Lr2MnP+2h8AGh?(WGVf>h@W-_M>jRkD z(KNxvo(UJ7)o+*t%fCcM10;2XM$1NAFKwhp(c917^io_ynn-yv58IFIF*UJUw*2Ma zm?a-a1yp9B?WxpLzap-c^$HKkX_IfT_W8Lqaltl*A%vZSZWAe`Kv}vjz}>Tc;Hw9T zA+Nc49X&{WDmxY~ReV0YceXdL!$9mTL$Q@_vXIW6I{G=`$KR7jFcE&IsHwnKX;KldV#YL z(xwKAB5cFiz+r6m*5iJvo&E)XQqVWjmA}BfyVS&dm9&Y%$Sp^sW!JE3iI0v(kQHdo zmhWk|gC!e@CFKPv4BE*U;mYo0y}J0J-Fhu!c%v+paQf9+3Ed2EkfPt(D7|Ok#t)^PGr3Y)RGfvO=k;@Xry=Cf3fLCQ# zi`%oCt+vyB-t{iEgI&+2dczmnMXj>EOmSpMuuL8Ob`1$D;fc$wM6j2HH4Q$ zqaoj&M$2sLhpptdJMbs!krJId=iOd}HdP4Lt@yf42OZ{pOoQ4_gShz_sMoWYX}yQd zDQ8(tc7UvTt%`0#?9K!C^J>GpucEnBhnsWg102Z=uzOlwez^q^j7nV$krID#wC}A$ zcRfc2)T5Y~({6@1`{yL-Lzs;miT@C9|1SIFBMK7cz*E;v2H|EStZphjfb5mGMpw{q z!pl;Vw772tuvDH4o$;j4u8)@=m+&BIf4Ix(u75P?Q{4Y8^uvpq)mCW(enuQc)hx$B zOY{`_*%~bm%k*x6y;)D8_-yYbMsC8y#1H}89X;M=a#*HT>d*NFf}x$pQ&X?nFtvzA zKH|l8y;frsm|&}<%&*}Yu}Yn0M=Jy8qe%<1qXRR%Nut}Aqr+1pQS*D7Cp`+8Y`RO02p14DyVOmSYlEzZ;9&JzYhtybMZ%e4s zlks=V(+aJ!LK-()3ox`%9c)lx#3#y4{ulL6KpG|&>9`n?Uh#m3G-mZy-3h98Scyja zH^3Pb7?P z+2hAkyvg}g$#)n$Gs2fL19JNOZ|~>Nx(|}lmwesC!>?Y~72mpf4XZ8t^TIwbCk;i0 z+a2ymSZ^=OrtrSH!(y#Vn!8KWk#O7<1-!if+`dDDy18U7wS3k$lIeM}Z0fhYqI)+x zo*o4*S$S|hGf6vL>PaQ(OQ_%eskx-G-FV|dXHbTH<#w@RbeIx9I$d$xqHh`{*&d3y zevlYNk)}w@cuu4A$^DYJsOvO7VBaom@Rx@gb$V5IKJ{Xue16H-1H0j=U0brW-aVRG znWCQRkESBmD^4?a7mB@!jf2>(Hs=Bd-;XX1oEilevb9axB^NhIPLO>jl03S+Rw|fx z&oIsIk(~W!4$zzKF|uSR<@S#;{r;fKup)iDaxz_9JouroY>XHcrN(Mm@UHV?-8bCh zXGfY~7U`rCasv(h-R*ava)^ zF1`BMT*n3xQBTdM?`n&h2Ecf*XXuLo7Zyl_El(v~oh>}mK01$%0a@#uzyiX_g>Bav2XWwH%YekAxU%pBT!p*?%cS#zA zv;^eDC#KZP@7o=^GDc_V8<3w>`*L(+=A#(fcH)dGjqM}Vk_el+c>B`{9xm<>IZ-Zm zLL!-Yf*3nju_(8ZGUd9*K`iofWW+BYFnZF&+a|=yxqV?oUOcG#ulnSR$DMs|e5Tph%WW zVjzE3nMh7+rG!}av)+~;o$#+EHyPX zzOUO?^#)Jh*t^b7pTW+I%f;xy&JMPCO&5RR``BmHX-Mw{qoJp9BjKea$;A9%>-iEZ zvuUBm%0j5UWax~`ue!K6dDdip+zs3f{+qQKqH;9C(1Z@95()-Ew=`BdLh2VS3zI8qYGH&&7m9+vpUc+x8l!i-ATXKhw34XL2;ya_VIQz!OL^)8mtqnb?q=~&^h-$;Zn^HRZ2p(gH z39An;`AWT=i&VP0u&CUe7OYW51Icv=q%Vc7%Zm z_uAp9n}osEUdk2*pV)*i`WRSa-FWtCwGqS-75@K#V0)r;+0(0XVp9vnb7lWiMj!q= z>Zf(ioa@gSwA55Jil$lh)%4U<)$j@HTQU2KwuUUsZA*2O^QTKobak8g0Qb~ROMTW7 zfTF2yF*na6i(lQ*Nq^rPen^0>$$b`K!Kp{FVa-VF`kCiXZg0Vtr}i*rcpny_YOR!} z+?Jiv?dWlT`}o$s9Fxt%%684d7ek-q-Q~jS*I5+8HtvSw+Rp!D=+gVr!gqcYy9K74 z&eClx6f6{1Din;ynjz?XZlJ~W7^A@0wiHIt8$aou;f>MYpU%gUlDwAK*nX0#vHtyl z_C=B+ZkOffY|oR^2>(+IlZCTMFirZMhn>bqzR=38hvJpcM4-@gUYY7_k^G*FW9;5r zc9q4c>C?hd{uS3{MThN*(w!3e05e?bI#SNlo$U&%>((Dz0_JeqbG|}!wI$& z%q2JQ)Vas;i0RYqNXW!CC~QK%u$K$beGI zT2KuzMjus26(zmofK;m2gY%d*o~sHBKA#`RBNc9c*-GLmbgh?*9V;^TBSot2E%~Q5 zl+R!WA_h_JT;+irbJ#Z-tSy-;B^t&&dOSwPV(T!CB)no8Y4sP%k(MD^0P!NL1vK&7 z`3luW2$gkI#Zf>IZT2=m4R&e@d zeo#B=Q|9`w8}%|)f%GBjYO01&Dk5qjm$+#1yia#CE=Sh~88Vdp%|VU}0a6mF@JkhUY&~W3f#rHK-1Qdo z>0*z5?#-hQUY}k^X7~1bkI?($-~3#c3mF4Cl@2%|0@1=ARZ z^qlNaN63&>;O_~mmto}?tAhznb}p;GpyIq1Z^yf<_6Ui~cpbbP;uV7W!+ke>wYG-f zPPz2~%UgSs(>vsKFle%uo=WIDYz;BR!doAy)aQ0QCpE_Wz1XK+3Kpr=V_H8w zqzaizn9ALx#?fo-N)_CtENYH*1|ID|x=xa9d#;9~1Wgrcx^8=evrfky*Xj`269~A;kh^O|ewZnM}=SmM7NX=?h#jjLh&1kIT+A z)If4luYo@s+e_L&eRJ$gw1`)>u#efOq=M0iYIPS$GII0z`T56eNxK@~Y%*^~Q&w$1b)jM9Z~kuRc~YX`6r#ySCskW5cq|#a39s;ZiaL~OdEpgu z1k*sKkLZ&?6fAi=)77yKI1xii%)@DG8r}663xkJcwLTj?s`h{GP@_2}`A|;w7zrzk4QOQ*O$(e|M^<`vLD*1^i>Nr*= z+A`y@f{!zLi)ys9OrFM5`Qw0292Ciyq>zC>8(TkG1O;#UUh?#I08kuwpS_vhufJ0v&p^Yr`=^WG7!qVG(8n9u7=J64fr zQq7B|9rzl7s)I_|8UeVp?=cqGILQ}0O(n+^vJz=vFBU9JmG$=DWzi+qCHw@D0a7`M zA`%pmU8+8W{u0{2*^tg&3;I&i`4`{YJe_n8 z{viTJZL?$}#l9w${3mydrW>Z%nY!WXf$HJv5$Zw4F%7^mXWsZ-s&olv31;C*KlH)j z?j?Eika^cI`l>)WJ*ga?%>0HwJm{%<)OP8pdvwMG@fm;Ca`jfy7ixY-sic42*f&ld zJg3(O0~;=Zsp@cdUj@&Zj~#~LX=F5Ws@!Ik0-~(wlbJO6&)S~s6WrAW9lrQ%6+S03 z&P&xJ{;BC%2s%J#uxZy3=Fc}fkwE9(T}QAK9b{FT!L3^PQ~;#X$T|9v&JFq)ru$h|ls zvPxYyWT}V&Dol3#)t6pVE4nIClEq=r++eGcG-tkOW4{n$Ra~3z?`@_gXRUiR`SrhY4K z#>C+t>pNtm>!Zw*;p^qI0|g<)Ob`r0jaN6asw2ZGLT}bMbHnQ$OH8cR7{Rq?=4%&x z2Qe&O`w$~b%fuo>fkgT`PVx=uto@&SdDpIXL)<da|A*x(b?o zdUj^iN+B9%;2{1URo7=%m@r*RJi3fQNO_`AZY;b#tClm;A}NQF#!Y;pMMdh=^fO@9 z>J>Xv^joKJM>M7x=xh!oSLO3JlxVwTn$DPHdGsnkAvB)9d)IE6ZHgd1vd+Z;W1d682CBy4zti z&6;T6!rzSKIy&zKKfAx9J%7q-=Mac{u-_GIYEaZt*`h25Ne?ch`E_c2{pGA<;nVkx z102u6#||N$g5MhA{!rFwaI(;8$S{1DePGc^L~j6?Q$2QMIO09 zPdma#_kX(|;oOau(pX877ac9V4O8x3g{Mdbr6oS)7 zN0v#H_j!bhUNl;q>GrkeA~){;lCg@&Mg5(z%E1HV`d7{>_}@9JZ(VJn>=HKC4q{My zLpw8D2OD@&E}T?=SV7rE-XI?4H+E(aOI8sZOC$NW=!leE6MG6ycn2;fB4XpB!^#Z= zQ?P=-+!R0#4h{+c2LPbUF6{uZG&6i-ZDI+f;6P`8V{ZtxcA((p;6i6ds6r4x005m` z6k;m{H8U}FK+J;+syaZe)G2u2J;eI(G+`)^0+C~@0#BIzJLi_?-}e8NR15?I|34|k zx>2LneiYApj|7nW4k1sp9h-vz^G);Jq7ONB*clw!(IJ2QT3sYWS)>yb_Ual2Um3r5 zw706UJD48HLY73$&Gm=sl|EYND&Uk>VT!eN_p49f6HS<{TU>u{4&#WYh1dwy^E8il ziH`_=$2m8k)y$Q2yDZQluP+AZbND!Yi7Co@fwHnw2pV1bo*=wGx2n7Urt$y1@imz1&#&nK47Nw zT-dLY@^1NHY?5B#-Qf9?`lA_={@NnLpmwJGQG7&oU}0>) ziZ`GdjY(jIKi2Q?e+d=de}nq3pkP;ZG;lyf$Xh!{=x?qF#2$)p%>NM^W_I=tqNWf# zgv;e1fAtY=)-W@2FtyhKb8%3Bfj|mw00#vR4=)857d&XdU z(4fLD4>dA_AWjHkeJ)-u3LZ|NF1w_ijiW6*A6^xXD#Y5}7O{k(E4!#F{9rhl8A4Sg zMcAb&9N>rx39*a9v4(4~r$8jq|MLt0{*hTPYU2nu0sub&aQG~$!9>qU@%LGVw1{ZAdD5crj3WAdl2KV62-uIT7sX=aUZ*>8aV1F3(c z_P=p-FtxG!8!9*^U<3>RcoByeFaipAK|lhB5)AqaI)n^@hmeEwxOw0OKK@%C0pZ{C z5o^F{FbEE(DEt!$_$B<8DlYiaV7ME855ql#Py+_S#o(c8`L;d6lqRR~$cn(zq-4};(pf)4`xt=`PWS`7YO27?$MdgtpDP{`vCa4 z{2x3Z5bm@8-~oUj5Zv+q!Gl}N`CoDX0N4M*gTIpgb1nb?;)Y)s|FIqb0Ot6gw!m#h zTnhg~j+YZ2)c?r?0yzIm4hZ1=FTFrc;D6}=a`OJeW(PY6{AFi{I1;L6ZcsR+>?$@k z@FNVDLEL!K*2XpzfZwk|I3Y%%Lm?mm76XGtKw?0k2(JV$kO#;s#>p!o!6gRf5#f;l j@(7{-|3%=32kuUL2Z)`+Z(jm{U>-0!Ev>ks1p5C2Hj`#V diff --git a/Tests/LibPDF/oss-fuzz-testcase-62065.pdf b/Tests/LibPDF/oss-fuzz-testcase-62065.pdf deleted file mode 100644 index c35b0ceaeea..00000000000 --- a/Tests/LibPDF/oss-fuzz-testcase-62065.pdf +++ /dev/null @@ -1 +0,0 @@ -%PDF- \ No newline at end of file diff --git a/Tests/LibPDF/password-is-sup.pdf b/Tests/LibPDF/password-is-sup.pdf deleted file mode 100644 index e725cdc2a551fdf3deef5af1069afe75604c6917..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12731 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 diff --git a/Tests/LibPDF/pattern.pdf b/Tests/LibPDF/pattern.pdf deleted file mode 100644 index efded88c3fa..00000000000 --- a/Tests/LibPDF/pattern.pdf +++ /dev/null @@ -1,126 +0,0 @@ -%PDF-1.7 -%µ¶ - -1 0 obj -<> -endobj - -3 0 obj -<> -endobj - -5 0 obj -<> -endobj - -10 0 obj -<>/Font<>>> -endobj - -15 0 obj -<> -stream -BT % Begin text object -0.0 -0.05 TD % Move text position -/F1 1 Tf % Set text font and size -55 0 0 55 7.1771 10.4414 Tm % Set text matrix -0 Tc % Set character spacing -0 Tw % Set word spacing -1.0 0.0 0.0 rg % Set nonstroking colour to red -( a ) Tj % Show spade glyph -0.7478 -0.007 TD % Move text position -0.0 1.0 0.0 rg % Set nonstroking colour to green -( b ) Tj % Show heart glyph --0.7323 0.7813 TD % Move text position -0.0 0.0 1.0 rg % Set nonstroking colour to blue -( c ) Tj % Show diamond glyph -0.6913 0.007 TD % Move text position -0.0 0.0 0.0 rg % Set nonstroking colour to black -( d ) Tj % Show club glyph -ET % End text object - - -endstream -endobj - -20 0 obj -<> -endobj - -21 0 obj -<> -endobj - -30 0 obj -<> -stream -0.0 G % Set stroking colour to black -1.0 1.0 0.0 rg % Set nonstroking colour to yellow -25 175 175 -150 re % Construct rectangular path -f % Fill path -/Pattern cs % Set pattern colour space -/P1 scn % Set pattern as nonstroking colour -99.92 49.92 m % Start new path -99.92 77.52 77.52 99.92 49.92 99.92 c % Construct lower-left circle -22.32 99.92 -0.08 77.52 -0.08 49.92 c --0.08 22.32 22.32 -0.08 49.92 -0.08 c -77.52 -0.08 99.92 22.32 99.92 49.92 c -B % Fill and stroke path -224.96 49.92 m % Start new path -224.96 77.52 202.56 99.92 174.96 99.92 c % Construct lower-right circle -147.36 99.92 124.96 77.52 124.96 49.92 c -124.96 22.32 147.36 -0.08 174.96 -0.08 c -202.56 -0.08 224.96 22.32 224.96 49.92 c -B % Fill and stroke path -87.56 201.70 m % Start new path -63.66 187.90 55.46 157.32 69.26 133.40 c % Construct upper circle -83.06 109.50 113.66 101.30 137.56 115.10 c -161.46 128.90 169.66 159.50 155.86 183.40 c -142.06 207.30 111.46 215.50 87.56 201.70 c -B % Fill and stroke path -50 50 m % Start new path -175 50 l % Construct triangular path -112.5 158.253 l -b % Close, fill, and stroke path -endstream -endobj - -xref -0 31 -0000000002 00001 f -0000000016 00000 n -0000000004 00003 f -0000000062 00000 n -0000000006 00003 f -0000000114 00000 n -0000000007 00003 f -0000000008 00003 f -0000000009 00003 f -0000000011 00003 f -0000000213 00000 n -0000000012 00003 f -0000000013 00003 f -0000000014 00003 f -0000000016 00003 f -0000000276 00000 n -0000000017 00003 f -0000000018 00003 f -0000000019 00003 f -0000000022 00003 f -0000001071 00000 n -0000001153 00000 n -0000000023 00003 f -0000000024 00003 f -0000000025 00003 f -0000000026 00003 f -0000000027 00003 f -0000000028 00003 f -0000000029 00003 f -0000000000 00003 f -0000001224 00000 n - -trailer -<> -startxref -2362 -%%EOF diff --git a/Tests/LibPDF/rotate.pdf b/Tests/LibPDF/rotate.pdf deleted file mode 100644 index f5236290e86..00000000000 --- a/Tests/LibPDF/rotate.pdf +++ /dev/null @@ -1,53 +0,0 @@ -%PDF-1.3 -%µ¶ - -1 0 obj -<> -endobj - -2 0 obj -<> -endobj - -3 0 obj -<>>>>> -endobj - -4 0 obj -<> -stream -BT -/F1 25 Tf -30 TL -0.7071 0.7071 -0.7071 0.7071 50 50 Tm -(Rotation) Tj -5 Ts -( line 1) Tj -T* -40 -20 TD -(Line 2) Tj T* -40 -20 Td -(Line 3) Tj T* -ET - -endstream -endobj - -5 0 obj -<> -endobj - -xref -0 6 -0000000000 65536 f -0000000016 00000 n -0000000062 00000 n -0000000114 00000 n -0000000227 00000 n -0000000422 00000 n - -trailer -<> -startxref -494 -%%EOF diff --git a/Tests/LibPDF/standard-14-fonts.pdf b/Tests/LibPDF/standard-14-fonts.pdf deleted file mode 100644 index fa095a5f4ca..00000000000 --- a/Tests/LibPDF/standard-14-fonts.pdf +++ /dev/null @@ -1,288 +0,0 @@ -%PDF-1.3 -%µ¶ - -1 0 obj -<> -endobj - -2 0 obj -<> -endobj - -3 0 obj -<>>>/Type/Page/Rotate 0/Parent 2 0 R/MediaBox[0 0 660 700]/Contents 4 0 R>> -endobj - -4 0 obj -<> -stream --15 TL - -BT -40 660 Td -/Helvetica 10 Tf -(Times) Tj -ET - -BT -40 630 Td -/Times 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - -BT -40 590 Td -/TimesBold 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - -BT -40 550 Td -/TimesItalic 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - -BT -40 510 Td -/TimesBoldItalic 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - - -BT -40 480 Td -/Helvetica 10 Tf -(Helvetica) Tj -ET - -BT -40 450 Td -/Helvetica 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - -BT -40 410 Td -/HelveticaBold 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - - -BT -40 370 Td -/HelveticaOblique 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - -BT -40 330 Td -/HelveticaBoldOblique 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - - -BT -40 300 Td -/Helvetica 10 Tf -(Courier) Tj -ET - -BT -40 270 Td -/Courier 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - -BT -40 230 Td -/CourierBold 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - - -BT -40 190 Td -/CourierOblique 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - -BT -40 150 Td -/CourierBoldOblique 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - - -BT -40 120 Td -/Helvetica 10 Tf -(Symbol) Tj -ET - -BT -40 90 Td -/Symbol 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - - -BT -40 60 Td -/Helvetica 10 Tf -(ZapfDingbats) Tj -ET - -BT -40 30 Td -/ZapfDingbats 7 Tf -<000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f> Tj -<404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f> Tj T* -<808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf> Tj - Tj T* -ET - -endstream -endobj - -5 0 obj -<> -endobj - -6 0 obj -<> -endobj - -7 0 obj -<> -endobj - -8 0 obj -<> -endobj - -9 0 obj -<> -endobj - -10 0 obj -<> -endobj - -11 0 obj -<> -endobj - -12 0 obj -<> -endobj - -13 0 obj -<> -endobj - -14 0 obj -<> -endobj - -15 0 obj -<> -endobj - -16 0 obj -<> -endobj - -17 0 obj -<> -endobj - -18 0 obj -<> -endobj - -19 0 obj -<> -endobj - -20 0 obj -19 0 R -endobj - -21 0 obj -<> -endobj - -22 0 obj -21 0 R -endobj - -xref -0 23 -0000000000 65536 f -0000000016 00000 n -0000000074 00000 n -0000000126 00000 n -0000000512 00000 n -0000008902 00000 n -0000008979 00000 n -0000009059 00000 n -0000009143 00000 n -0000009235 00000 n -0000009314 00000 n -0000009403 00000 n -0000009498 00000 n -0000009601 00000 n -0000009677 00000 n -0000009762 00000 n -0000009853 00000 n -0000009952 00000 n -0000010026 00000 n -0000010112 00000 n -0000010248 00000 n -0000010272 00000 n -0000010408 00000 n - -trailer -<]>> -startxref -10432 -%%EOF diff --git a/Tests/LibPDF/text.pdf b/Tests/LibPDF/text.pdf deleted file mode 100644 index f1034a340ca..00000000000 --- a/Tests/LibPDF/text.pdf +++ /dev/null @@ -1,61 +0,0 @@ -%PDF-1.3 -%µ¶ - -1 0 obj -<> -endobj - -2 0 obj -<> -endobj - -3 0 obj -<>>>>> -endobj - -4 0 obj -<> -stream -BT -0.9 0 0 0.9 0 0 cm -/F1 25 Tf --30 TL -40 40 Td -[ (Hello) -2000 (World) ] TJ T* -[ (Hello) -1000 -1000 (World) ] TJ T* -[ (Hello) -1000 ] TJ [ -1000 ] TJ [ (World) ] TJ T* -1 0 0 1 45 130 Tm [ 200 (Hello) -2000 (World) ] TJ T* -0.9 0 0 0.9 40 160 Tm -80 Tz -(should be the ) ' (same on all lines:) Tj -15 Ts /F1 10 Tf ( super) Tj /F1 25 Tf -15 TL -3 Tc -5 Tw -(The distance ) ' -(between "Hello" and "World") Tj -10 Ts -(yo) Tj -ET - - -endstream -endobj - -5 0 obj -<> -endobj - -xref -0 6 -0000000000 65536 f -0000000016 00000 n -0000000062 00000 n -0000000114 00000 n -0000000227 00000 n -0000000696 00000 n - -trailer -<> -startxref -794 -%%EOF diff --git a/Tests/LibPDF/type1.pdf b/Tests/LibPDF/type1.pdf deleted file mode 100644 index a51a6daaa0608f31d0a750365667f339eaf88669..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34754 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 diff --git a/Tests/LibPDF/type3.pdf b/Tests/LibPDF/type3.pdf deleted file mode 100644 index 14e306f7f48..00000000000 --- a/Tests/LibPDF/type3.pdf +++ /dev/null @@ -1,95 +0,0 @@ -%PDF-1.7 -%µ¶ - -1 0 obj -<> -endobj - -2 0 obj -<> -endobj - -3 0 obj -<>>>/Rotate 0/MediaBox[0 0 525 250]/Parent 2 0 R>> -endobj - -4 0 obj -<> -stream -BT -/F1 24 Tf -30 TL -40 220 Td -(There should be 5 triangles facing right) ' -(with colors blue green blue green blue:) ' -0 0 1 rg -/F2 24 Tf -(ababa) ' -ET - -endstream -endobj - -5 0 obj -<> -endobj - -6 0 obj -<>/Encoding/MacRomanEncoding/FirstChar 97/LastChar 98/Widths[10 10]/Resources<<>>>> -endobj - -7 0 obj -<> -stream -10 0 0 0 10 10 d1 -1 0 0 rg -0 0 m -8 5 l -0 10 l -0 0 l -f - -endstream -endobj - -8 0 obj -<> -stream -10 0 d0 -0 1 0 rg -0 0 m -8 5 l -0 10 l -0 0 l -f - -endstream -endobj - -9 0 obj -<> -endobj - -10 0 obj -9 0 R -endobj - -xref -0 11 -0000000000 65536 f -0000000016 00000 n -0000000074 00000 n -0000000126 00000 n -0000000257 00000 n -0000000457 00000 n -0000000555 00000 n -0000000761 00000 n -0000000864 00000 n -0000000957 00000 n -0000001092 00000 n - -trailer -<]>> -startxref -1115 -%%EOF diff --git a/Tests/LibPDF/wide-gamut-only.pdf b/Tests/LibPDF/wide-gamut-only.pdf deleted file mode 100644 index f14d172eddb0b6682184ad147e1256936b00b9c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 721914 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 - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -TEST_ROOT("Userland/Applications/Spreadsheet/Tests"); - -#ifdef AK_OS_SERENITY -static constexpr auto s_spreadsheet_runtime_path = "/res/js/Spreadsheet/runtime.js"sv; -#else -static constexpr auto s_spreadsheet_runtime_path = "../../../../Base/res/js/Spreadsheet/runtime.js"sv; -#endif - -TESTJS_RUN_FILE_FUNCTION(ByteString const&, JS::Realm& realm, JS::ExecutionContext& global_execution_context) -{ - auto run_file = [&](StringView name) { - auto result = Test::JS::parse_script(name, realm); - if (result.is_error()) { - warnln("Unable to parse {}", name); - warnln("{}", result.error().error.to_byte_string()); - warnln("{}", result.error().hint); - Test::cleanup_and_exit(); - } - auto script = result.release_value(); - - realm.vm().push_execution_context(global_execution_context); - MUST(realm.vm().bytecode_interpreter().run(*script)); - realm.vm().pop_execution_context(); - }; - -#ifdef AK_OS_SERENITY - run_file(s_spreadsheet_runtime_path); -#else - run_file(LexicalPath::join(Test::JS::g_test_root, s_spreadsheet_runtime_path).string()); -#endif - - run_file("mock.test-common.js"sv); - - return Test::JS::RunFileHookResult::RunAsNormal; -} diff --git a/Tests/Utilities/CMakeLists.txt b/Tests/Utilities/CMakeLists.txt deleted file mode 100644 index ddb18dc76a5..00000000000 --- a/Tests/Utilities/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -set(TEST_SOURCES - TestSed.cpp - TestPatch.cpp - TestUniq.cpp -) - -foreach(source IN LISTS TEST_SOURCES) - serenity_test("${source}" Utilities) -endforeach() diff --git a/Tests/Utilities/TestPatch.cpp b/Tests/Utilities/TestPatch.cpp deleted file mode 100644 index f95a928a4a9..00000000000 --- a/Tests/Utilities/TestPatch.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2023-2024, Shannon Booth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include - -static constexpr char const* s_test_dir = "/tmp/patch-test"; - -#define EXPECT_FILE_EQ(file_path, expected_content) \ - do { \ - auto output = MUST(Core::File::open(file_path, Core::File::OpenMode::Read)); \ - auto content = MUST(output->read_until_eof()); \ - EXPECT_EQ(StringView { content }, expected_content); \ - } while (false) - -class PatchSetup { -public: - PatchSetup() - { - clean_up(); // Just in case something was left behind from beforehand. - MUST(Core::System::mkdir(StringView { s_test_dir, strlen(s_test_dir) }, 0755)); - } - - ~PatchSetup() - { - clean_up(); - } - -private: - static void clean_up() - { - auto result = FileSystem::remove(StringView { s_test_dir, strlen(s_test_dir) }, FileSystem::RecursionMode::Allowed); - if (result.is_error()) - VERIFY(result.error().is_errno() && result.error().code() == ENOENT); - } -}; - -enum class ExpectSuccess { - Yes, - No, -}; - -static void run_patch(ExpectSuccess success, Vector&& arguments, StringView standard_input, Optional expected_stdout = {}) -{ - // Ask patch to run the test in a temporary directory so we don't leave any files around. - Vector args_with_chdir = { "patch", "-d", s_test_dir }; - args_with_chdir.extend(arguments); - args_with_chdir.append(nullptr); - - auto patch = MUST(Core::Command::create("patch"sv, args_with_chdir.data())); - - MUST(patch->write(standard_input)); - - auto [stdout, stderr] = MUST(patch->read_all()); - - auto status = MUST(patch->status()); - - StringView stdout_view { stdout.bytes() }; - StringView stderr_view { stderr.bytes() }; - - if (success == ExpectSuccess::Yes && status != Core::Command::ProcessResult::DoneWithZeroExitCode) { - FAIL(MUST(String::formatted("patch did not return success: status: {}, stdout: {}, stderr: {}", static_cast(status), stdout_view, stderr_view))); - } else if (success == ExpectSuccess::No && status != Core::Command::ProcessResult::Failed) { - FAIL(MUST(String::formatted("patch did not return error: status: {}, stdout: {}, stderr: {}", static_cast(status), stdout_view, stderr_view))); - } - - if (expected_stdout.has_value()) - EXPECT_EQ(StringView { expected_stdout->bytes() }, StringView { stdout.bytes() }); -} - -TEST_CASE(basic_change_patch) -{ - PatchSetup setup; - - auto patch = R"( ---- a -+++ b -@@ -1,3 +1,3 @@ - 1 --2 -+b - 3 -)"sv; - - auto file = "1\n2\n3\n"sv; - auto input = MUST(Core::File::open(ByteString::formatted("{}/a", s_test_dir), Core::File::OpenMode::Write)); - MUST(input->write_until_depleted(file.bytes())); - - run_patch(ExpectSuccess::Yes, {}, patch, "patching file a\n"sv); - - EXPECT_FILE_EQ(ByteString::formatted("{}/a", s_test_dir), "1\nb\n3\n"); -} - -TEST_CASE(basic_addition_patch_from_empty_file) -{ - PatchSetup setup; - - auto patch = R"( ---- /dev/null -+++ a -@@ -0,0 +1,3 @@ -+1 -+2 -+3 -)"sv; - - auto file = ""sv; - auto input = MUST(Core::File::open(ByteString::formatted("{}/a", s_test_dir), Core::File::OpenMode::Write)); - MUST(input->write_until_depleted(file.bytes())); - - run_patch(ExpectSuccess::Yes, {}, patch, "patching file a\n"sv); - - EXPECT_FILE_EQ(ByteString::formatted("{}/a", s_test_dir), "1\n2\n3\n"); -} - -TEST_CASE(strip_path_to_basename) -{ - PatchSetup setup; - - auto patch = R"( ---- /dev/null -+++ a/bunch/of/../folders/stripped/to/basename -@@ -0,0 +1 @@ -+Hello, friends! -)"sv; - - auto file = ""sv; - auto input = MUST(Core::File::open(MUST(String::formatted("{}/basename", s_test_dir)), Core::File::OpenMode::Write)); - MUST(input->write_until_depleted(file.bytes())); - - run_patch(ExpectSuccess::Yes, {}, patch, "patching file basename\n"sv); - - EXPECT_FILE_EQ(MUST(String::formatted("{}/basename", s_test_dir)), "Hello, friends!\n"); -} - -TEST_CASE(strip_path_partially) -{ - PatchSetup setup; - - auto patch = R"( ---- /dev/null -+++ a/bunch/of/../folders/stripped/to/basename -@@ -0,0 +1 @@ -+Hello, friends! -)"sv; - - MUST(Core::System::mkdir(MUST(String::formatted("{}/to", s_test_dir)), 0755)); - - auto file = ""sv; - auto input = MUST(Core::File::open(MUST(String::formatted("{}/to/basename", s_test_dir)), Core::File::OpenMode::Write)); - MUST(input->write_until_depleted(file.bytes())); - - run_patch(ExpectSuccess::Yes, { "-p6" }, patch, "patching file to/basename\n"sv); - - EXPECT_FILE_EQ(MUST(String::formatted("{}/to/basename", s_test_dir)), "Hello, friends!\n"); -} - -TEST_CASE(add_file_from_scratch) -{ - PatchSetup setup; - - auto patch = R"( ---- /dev/null -+++ a/file_to_add -@@ -0,0 +1 @@ -+Hello, friends! -)"sv; - - run_patch(ExpectSuccess::Yes, {}, patch, "patching file file_to_add\n"sv); - - EXPECT_FILE_EQ(ByteString::formatted("{}/file_to_add", s_test_dir), "Hello, friends!\n"); -} - -TEST_CASE(two_patches_in_single_patch_file) -{ - PatchSetup setup; - - auto patch = R"( ---- /dev/null -+++ a/first_file_to_add -@@ -0,0 +1 @@ -+Hello, friends! ---- /dev/null -+++ a/second_file_to_add -@@ -0,0 +1 @@ -+Hello, friends! -)"sv; - - run_patch(ExpectSuccess::Yes, {}, patch, "patching file first_file_to_add\n" - "patching file second_file_to_add\n"sv); - - EXPECT_FILE_EQ(ByteString::formatted("{}/first_file_to_add", s_test_dir), "Hello, friends!\n"); - EXPECT_FILE_EQ(ByteString::formatted("{}/second_file_to_add", s_test_dir), "Hello, friends!\n"); -} - -TEST_CASE(patch_adding_file_to_existing_file) -{ - PatchSetup setup; - - auto patch = R"( ---- /dev/null -+++ a -@@ -0,0 +1 @@ -+1 -)"sv; - - auto file = "a\n"sv; - auto input = MUST(Core::File::open(ByteString::formatted("{}/a", s_test_dir), Core::File::OpenMode::Write)); - MUST(input->write_until_depleted(file.bytes())); - - run_patch(ExpectSuccess::No, {}, patch); - - EXPECT_FILE_EQ(ByteString::formatted("{}/a", s_test_dir), "a\n"sv); -} - -TEST_CASE(patch_remove_file_to_empty) -{ - PatchSetup setup; - - auto patch = R"( ---- a -+++ /dev/null -@@ -1 +0,0 @@ --1 -)"sv; - - auto file = "1\n"sv; - auto input = MUST(Core::File::open(ByteString::formatted("{}/a", s_test_dir), Core::File::OpenMode::Write)); - MUST(input->write_until_depleted(file.bytes())); - - run_patch(ExpectSuccess::Yes, {}, patch, "patching file a\n"sv); - - EXPECT(!FileSystem::exists(ByteString::formatted("{}/a", s_test_dir))); -} - -TEST_CASE(patch_remove_file_trailing_garbage) -{ - PatchSetup setup; - - auto patch = R"( ---- a -+++ /dev/null -@@ -1 +0,0 @@ --1 -)"sv; - - auto file = "1\n2\n"sv; - auto input = MUST(Core::File::open(ByteString::formatted("{}/a", s_test_dir), Core::File::OpenMode::Write)); - MUST(input->write_until_depleted(file.bytes())); - - run_patch(ExpectSuccess::Yes, {}, patch, "patching file a\n" - "Not deleting file a as content differs from patch\n"sv); - - EXPECT_FILE_EQ(ByteString::formatted("{}/a", s_test_dir), "2\n"sv); -} - -TEST_CASE(patch_with_timestamp_separated_by_tab) -{ - PatchSetup setup; - - auto patch = R"( ---- /dev/null 2024-03-02 20:19:31.462146900 +1300 -+++ 1 2024-03-02 20:56:57.922136203 +1300 -@@ -0,0 +1 @@ -+a -)"sv; - - run_patch(ExpectSuccess::Yes, {}, patch, "patching file 1\n"sv); - EXPECT_FILE_EQ(ByteString::formatted("{}/1", s_test_dir), "a\n"sv); -} - -TEST_CASE(patch_defines_add_remove) -{ - PatchSetup setup; - - StringView patch = R"( ---- file.cpp -+++ file.cpp -@@ -1,4 +1,4 @@ - int main() - { -- return 0; -+ return 1; - } -)"sv; - - auto file = R"(int main() -{ - return 0; -} -)"sv; - - auto input = MUST(Core::File::open(ByteString::formatted("{}/file.cpp", s_test_dir), Core::File::OpenMode::Write)); - MUST(input->write_until_depleted(file.bytes())); - - run_patch(ExpectSuccess::Yes, { "--ifdef", "TEST_PATCH" }, patch); - - EXPECT_FILE_EQ(ByteString::formatted("{}/file.cpp", s_test_dir), R"(int main() -{ -#ifndef TEST_PATCH - return 0; -#else - return 1; -#endif -} -)"); -} diff --git a/Tests/Utilities/TestSed.cpp b/Tests/Utilities/TestSed.cpp deleted file mode 100644 index c6b111251ad..00000000000 --- a/Tests/Utilities/TestSed.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2023, Rodrigo Tobar . - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include - -static void run_sed(Vector&& arguments, StringView standard_input, StringView expected_stdout) -{ - MUST(arguments.try_insert(0, "sed")); - MUST(arguments.try_append(nullptr)); - auto sed = MUST(Core::Command::create("sed"sv, arguments.data())); - MUST(sed->write(standard_input)); - auto [stdout, stderr] = MUST(sed->read_all()); - auto status = MUST(sed->status()); - if (status != Core::Command::ProcessResult::DoneWithZeroExitCode) { - FAIL(ByteString::formatted("sed didn't exit cleanly: status: {}, stdout:{}, stderr: {}", static_cast(status), StringView { stdout.bytes() }, StringView { stderr.bytes() })); - } - EXPECT_EQ(StringView { expected_stdout.bytes() }, StringView { stdout.bytes() }); -} - -TEST_CASE(print_lineno) -{ - run_sed({ "=", "-n" }, "hi"sv, "1\n"sv); - run_sed({ "=", "-n" }, "hi\n"sv, "1\n"sv); - run_sed({ "=", "-n" }, "hi\nho"sv, "1\n2\n"sv); - run_sed({ "=", "-n" }, "hi\nho\n"sv, "1\n2\n"sv); -} - -TEST_CASE(s) -{ - run_sed({ "s/a/b/g" }, "aa\n"sv, "bb\n"sv); - run_sed({ "s/././g" }, "aa\n"sv, "..\n"sv); - run_sed({ "s/a/b/p" }, "a\n"sv, "b\nb\n"sv); - run_sed({ "s/a/b/p", "-n" }, "a\n"sv, "b\n"sv); - run_sed({ "1s/a/b/" }, "a\na"sv, "b\na\n"sv); - run_sed({ "1s/a/b/p", "-n" }, "a\na"sv, "b\n"sv); -} - -TEST_CASE(hold_space) -{ - run_sed({ "1h; 2x; 2p", "-n" }, "hi\nbye"sv, "hi\n"sv); -} - -TEST_CASE(complex) -{ - run_sed({ "h; x; s/./*/gp; x; h; p; x; s/./*/gp", "-n" }, "hello serenity"sv, "**************\nhello serenity\n**************\n"sv); -} diff --git a/Tests/Utilities/TestUniq.cpp b/Tests/Utilities/TestUniq.cpp deleted file mode 100644 index 7b08fe3aa9c..00000000000 --- a/Tests/Utilities/TestUniq.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2023, Rodrigo Tobar . - * Copyright (c) 2024, Daniel Gaston . - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include - -static void run_uniq(Vector&& arguments, StringView standard_input, StringView expected_stdout) -{ - MUST(arguments.try_insert(0, "uniq")); - MUST(arguments.try_append(nullptr)); - auto uniq = MUST(Core::Command::create("uniq"sv, arguments.data())); - MUST(uniq->write(standard_input)); - auto [stdout, stderr] = MUST(uniq->read_all()); - auto status = MUST(uniq->status()); - if (status != Core::Command::ProcessResult::DoneWithZeroExitCode) { - FAIL(ByteString::formatted("uniq didn't exit cleanly: status: {}, stdout: {}, stderr: {}", static_cast(status), StringView { stdout.bytes() }, StringView { stderr.bytes() })); - } - EXPECT_EQ(StringView { expected_stdout.bytes() }, StringView { stdout.bytes() }); -} - -TEST_CASE(two_duplicate_lines) -{ - run_uniq({}, "AAA\nAAA\n"sv, "AAA\n"sv); -} - -TEST_CASE(two_unique_lines) -{ - run_uniq({}, "AAA\nAaA\n"sv, "AAA\nAaA\n"sv); -} - -TEST_CASE(long_line) -{ - auto input = Array {}; - auto expected_output = Array {}; - // Create two lines of 2047 A's and a newline. - input.fill('A'); - input[2047] = '\n'; - input[4095] = '\n'; - - expected_output.fill('A'); - expected_output[2047] = '\n'; - - run_uniq({}, StringView { input }, StringView { expected_output }); -} - -TEST_CASE(line_longer_than_internal_stream_buffer) -{ - auto input = Array {}; - auto expected_output = Array {}; - // Create two lines of 65535 A's and a newline. - input.fill('A'); - input[65535] = '\n'; - input[131071] = '\n'; - - expected_output.fill('A'); - expected_output[65535] = '\n'; - - run_uniq({}, StringView { input }, StringView { expected_output }); -} - -TEST_CASE(ignore_case_flag) -{ - run_uniq({ "-i" }, "AAA\nAaA\n"sv, "AAA\n"sv); - run_uniq({ "-i" }, "AAA\naaa\nAaA\n"sv, "AAA\n"sv); -} - -TEST_CASE(duplicate_flag) -{ - run_uniq({ "-d" }, "AAA\nAAA\nBBB\n"sv, "AAA\n"sv); - run_uniq({ "-d" }, "AAA\nAAA\nBBB\nBBB\nCCC\n"sv, "AAA\nBBB\n"sv); -} - -TEST_CASE(skip_chars_flag) -{ - run_uniq({ "-s1" }, "AAA\nAaA\n"sv, "AAA\nAaA\n"sv); - run_uniq({ "-s2" }, "AAA\nAaA\n"sv, "AAA\n"sv); - run_uniq({ "-s200" }, "AAA\nAaA\n"sv, "AAA\n"sv); -} - -TEST_CASE(skip_fields_flag) -{ - run_uniq({ "-f1" }, "1 AA\n2 AA\n"sv, "1 AA\n"sv); - run_uniq({ "-f1" }, "1 a AA\n2 b AA\n"sv, "1 a AA\n2 b AA\n"sv); - run_uniq({ "-f2" }, "1 a AA\n2 b AA\n"sv, "1 a AA\n"sv); - run_uniq({ "-f200" }, "1 AA\n2 AA\n"sv, "1 AA\n"sv); -} - -TEST_CASE(count_flag) -{ - run_uniq({ "-c" }, "AAA\nAAA\n"sv, "2 AAA\n"sv); - run_uniq({ "-c" }, "AAA\nAAA\nBBB\n"sv, "2 AAA\n1 BBB\n"sv); -} diff --git a/Userland/Libraries/CMakeLists.txt b/Userland/Libraries/CMakeLists.txt index d847f98e81b..9fc671a09fb 100644 --- a/Userland/Libraries/CMakeLists.txt +++ b/Userland/Libraries/CMakeLists.txt @@ -1,55 +1,34 @@ add_subdirectory(LibAccelGfx) add_subdirectory(LibArchive) add_subdirectory(LibAudio) -add_subdirectory(LibC) -add_subdirectory(LibCards) -add_subdirectory(LibChess) -add_subdirectory(LibCMake) -add_subdirectory(LibCodeComprehension) add_subdirectory(LibCompress) add_subdirectory(LibConfig) add_subdirectory(LibCore) -add_subdirectory(LibCoredump) -add_subdirectory(LibCpp) add_subdirectory(LibCrypt) add_subdirectory(LibCrypto) add_subdirectory(LibDesktop) add_subdirectory(LibDiff) -add_subdirectory(LibDNS) add_subdirectory(LibDSP) -add_subdirectory(LibELF) add_subdirectory(LibFileSystem) add_subdirectory(LibFileSystemAccessClient) add_subdirectory(LibGemini) add_subdirectory(LibGfx) -add_subdirectory(LibGL) -add_subdirectory(LibGLSL) -add_subdirectory(LibGPU) -add_subdirectory(LibGUI) add_subdirectory(LibHTTP) add_subdirectory(LibIDL) add_subdirectory(LibIMAP) add_subdirectory(LibImageDecoderClient) add_subdirectory(LibIPC) -add_subdirectory(LibJIT) add_subdirectory(LibJS) add_subdirectory(LibKeyboard) add_subdirectory(LibLine) add_subdirectory(LibLocale) add_subdirectory(LibMain) -add_subdirectory(LibManual) add_subdirectory(LibMarkdown) -add_subdirectory(LibPartition) -add_subdirectory(LibPCIDB) -add_subdirectory(LibPDF) add_subdirectory(LibProtocol) add_subdirectory(LibRegex) add_subdirectory(LibRIFF) add_subdirectory(LibSanitizer) -add_subdirectory(LibSemVer) -add_subdirectory(LibSoftGPU) add_subdirectory(LibSQL) -add_subdirectory(LibSymbolication) add_subdirectory(LibSyntax) add_subdirectory(LibSystem) add_subdirectory(LibTest) @@ -61,11 +40,8 @@ add_subdirectory(LibUnicode) add_subdirectory(LibURL) add_subdirectory(LibUSBDB) add_subdirectory(LibVideo) -add_subdirectory(LibVirtGPU) -add_subdirectory(LibVT) add_subdirectory(LibWasm) add_subdirectory(LibWeb) add_subdirectory(LibWebSocket) add_subdirectory(LibWebView) -add_subdirectory(LibX86) add_subdirectory(LibXML) diff --git a/Userland/Libraries/LibCodeComprehension/CMakeLists.txt b/Userland/Libraries/LibCodeComprehension/CMakeLists.txt deleted file mode 100644 index 802a42b91bf..00000000000 --- a/Userland/Libraries/LibCodeComprehension/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -set(SOURCES - CodeComprehensionEngine.cpp - FileDB.cpp -) - -serenity_lib(LibCodeComprehension codecomprehension) - -add_subdirectory(Cpp) -add_subdirectory(Shell) diff --git a/Userland/Libraries/LibCodeComprehension/CodeComprehensionEngine.cpp b/Userland/Libraries/LibCodeComprehension/CodeComprehensionEngine.cpp deleted file mode 100644 index ffeef2ecaf2..00000000000 --- a/Userland/Libraries/LibCodeComprehension/CodeComprehensionEngine.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "CodeComprehensionEngine.h" - -namespace CodeComprehension { - -CodeComprehensionEngine::CodeComprehensionEngine(FileDB const& filedb, bool should_store_all_declarations) - : m_filedb(filedb) - , m_store_all_declarations(should_store_all_declarations) -{ -} - -void CodeComprehensionEngine::set_declarations_of_document(ByteString const& filename, Vector&& declarations) -{ - // Callback may not be configured if we're running tests - if (!set_declarations_of_document_callback) - return; - - // Optimization - Only notify callback if declarations have changed - if (auto previous_declarations = m_all_declarations.find(filename); previous_declarations != m_all_declarations.end()) { - if (previous_declarations->value == declarations) - return; - } - if (m_store_all_declarations) - m_all_declarations.set(filename, declarations); - set_declarations_of_document_callback(filename, move(declarations)); -} - -void CodeComprehensionEngine::set_todo_entries_of_document(ByteString const& filename, Vector&& todo_entries) -{ - // Callback may not be configured if we're running tests - if (!set_todo_entries_of_document_callback) - return; - set_todo_entries_of_document_callback(filename, move(todo_entries)); -} - -} diff --git a/Userland/Libraries/LibCodeComprehension/CodeComprehensionEngine.h b/Userland/Libraries/LibCodeComprehension/CodeComprehensionEngine.h deleted file mode 100644 index b708cf410f3..00000000000 --- a/Userland/Libraries/LibCodeComprehension/CodeComprehensionEngine.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "FileDB.h" -#include "Types.h" -#include -#include -#include -#include - -namespace CodeComprehension { - -class CodeComprehensionEngine { - AK_MAKE_NONCOPYABLE(CodeComprehensionEngine); - AK_MAKE_NONMOVABLE(CodeComprehensionEngine); - -public: - CodeComprehensionEngine(FileDB const& filedb, bool store_all_declarations = false); - virtual ~CodeComprehensionEngine() = default; - - virtual Vector get_suggestions(ByteString const& file, GUI::TextPosition const& autocomplete_position) = 0; - - // TODO: In the future we can pass the range that was edited and only re-parse what we have to. - virtual void on_edit([[maybe_unused]] ByteString const& file) {}; - virtual void file_opened([[maybe_unused]] ByteString const& file) {}; - - virtual Optional find_declaration_of(ByteString const&, GUI::TextPosition const&) { return {}; } - - struct FunctionParamsHint { - Vector params; - size_t current_index { 0 }; - }; - virtual Optional get_function_params_hint(ByteString const&, GUI::TextPosition const&) { return {}; } - - virtual Vector get_tokens_info(ByteString const&) { return {}; } - - Function&&)> set_declarations_of_document_callback; - Function&&)> set_todo_entries_of_document_callback; - -protected: - FileDB const& filedb() const { return m_filedb; } - void set_declarations_of_document(ByteString const&, Vector&&); - void set_todo_entries_of_document(ByteString const&, Vector&&); - HashMap> const& all_declarations() const { return m_all_declarations; } - -private: - HashMap> m_all_declarations; - FileDB const& m_filedb; - bool m_store_all_declarations { false }; -}; -} diff --git a/Userland/Libraries/LibCodeComprehension/Cpp/CMakeLists.txt b/Userland/Libraries/LibCodeComprehension/Cpp/CMakeLists.txt deleted file mode 100644 index d8e18961320..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Cpp/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -set(SOURCES - CppComprehensionEngine.cpp -) - -serenity_lib(LibCppComprehension cppcomprehension) -target_link_libraries(LibCppComprehension PRIVATE LibCodeComprehension) - -serenity_component( - CppComprehensionTests - TARGETS CppComprehensionTests -) - -set(SOURCES - CppComprehensionEngine.cpp - Tests.cpp -) - -serenity_bin(CppComprehensionTests) - -target_link_libraries(CppComprehensionTests PRIVATE LibCodeComprehension LibCore LibCpp LibFileSystem LibRegex LibMain) diff --git a/Userland/Libraries/LibCodeComprehension/Cpp/ConnectionFromClient.h b/Userland/Libraries/LibCodeComprehension/Cpp/ConnectionFromClient.h deleted file mode 100644 index 3fea907fb70..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Cpp/ConnectionFromClient.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "CppComprehensionEngine.h" -#include - -namespace LanguageServers::Cpp { - -class ConnectionFromClient final : public LanguageServers::ConnectionFromClient { - C_OBJECT(ConnectionFromClient); - -private: - ConnectionFromClient(NonnullOwnPtr socket) - : LanguageServers::ConnectionFromClient(move(socket)) - { - m_autocomplete_engine = make(m_filedb); - m_autocomplete_engine->set_declarations_of_document_callback = [this](ByteString const& filename, Vector&& declarations) { - async_declarations_in_document(filename, move(declarations)); - }; - m_autocomplete_engine->set_todo_entries_of_document_callback = [this](ByteString const& filename, Vector&& todo_entries) { - async_todo_entries_in_document(filename, move(todo_entries)); - }; - } - - virtual ~ConnectionFromClient() override = default; -}; -} diff --git a/Userland/Libraries/LibCodeComprehension/Cpp/CppComprehensionEngine.cpp b/Userland/Libraries/LibCodeComprehension/Cpp/CppComprehensionEngine.cpp deleted file mode 100644 index 4e5d79e6c65..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Cpp/CppComprehensionEngine.cpp +++ /dev/null @@ -1,1009 +0,0 @@ -/* - * Copyright (c) 2021-2022, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "CppComprehensionEngine.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace CodeComprehension::Cpp { - -CppComprehensionEngine::CppComprehensionEngine(FileDB const& filedb) - : CodeComprehensionEngine(filedb, true) -{ -} - -CppComprehensionEngine::DocumentData const* CppComprehensionEngine::get_or_create_document_data(ByteString const& file) -{ - auto absolute_path = filedb().to_absolute_path(file); - if (!m_documents.contains(absolute_path)) { - set_document_data(absolute_path, create_document_data_for(absolute_path)); - } - return get_document_data(absolute_path); -} - -CppComprehensionEngine::DocumentData const* CppComprehensionEngine::get_document_data(ByteString const& file) const -{ - auto absolute_path = filedb().to_absolute_path(file); - auto document_data = m_documents.get(absolute_path); - if (!document_data.has_value()) - return nullptr; - return document_data.value(); -} - -OwnPtr CppComprehensionEngine::create_document_data_for(ByteString const& file) -{ - if (m_unfinished_documents.contains(file)) { - return {}; - } - m_unfinished_documents.set(file); - ScopeGuard mark_finished([&file, this]() { m_unfinished_documents.remove(file); }); - auto document = filedb().get_or_read_from_filesystem(file); - if (!document.has_value()) - return {}; - return create_document_data(move(document.value()), file); -} - -void CppComprehensionEngine::set_document_data(ByteString const& file, OwnPtr&& data) -{ - m_documents.set(filedb().to_absolute_path(file), move(data)); -} - -Vector CppComprehensionEngine::get_suggestions(ByteString const& file, const GUI::TextPosition& autocomplete_position) -{ - Cpp::Position position { autocomplete_position.line(), autocomplete_position.column() > 0 ? autocomplete_position.column() - 1 : 0 }; - - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "CppComprehensionEngine position {}:{}", position.line, position.column); - - auto const* document_ptr = get_or_create_document_data(file); - if (!document_ptr) - return {}; - - auto const& document = *document_ptr; - auto containing_token = document.parser().token_at(position); - - if (containing_token.has_value() && containing_token->type() == Token::Type::IncludePath) { - auto results = try_autocomplete_include(document, containing_token.value(), position); - if (results.has_value()) - return results.value(); - } - - auto node = document.parser().node_at(position); - if (!node) { - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", position.line, position.column); - return {}; - } - - if (node->parent() && node->parent()->parent()) - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "node: {}, parent: {}, grandparent: {}", node->class_name(), node->parent()->class_name(), node->parent()->parent()->class_name()); - - if (!node->parent()) - return {}; - - auto results = try_autocomplete_property(document, *node, containing_token); - if (results.has_value()) - return results.value(); - - results = try_autocomplete_name(document, *node, containing_token); - if (results.has_value()) - return results.value(); - return {}; -} - -Optional> CppComprehensionEngine::try_autocomplete_name(DocumentData const& document, ASTNode const& node, Optional containing_token) const -{ - auto partial_text = ByteString::empty(); - if (containing_token.has_value() && containing_token.value().type() != Token::Type::ColonColon) { - partial_text = containing_token.value().text(); - } - return autocomplete_name(document, node, partial_text); -} - -Optional> CppComprehensionEngine::try_autocomplete_property(DocumentData const& document, ASTNode const& node, Optional containing_token) const -{ - if (!containing_token.has_value()) - return {}; - - if (!node.parent()->is_member_expression()) - return {}; - - auto const& parent = static_cast(*node.parent()); - - auto partial_text = ByteString::empty(); - if (containing_token.value().type() != Token::Type::Dot) { - if (&node != parent.property()) - return {}; - partial_text = containing_token.value().text(); - } - - return autocomplete_property(document, parent, partial_text); -} - -Vector CppComprehensionEngine::autocomplete_name(DocumentData const& document, ASTNode const& node, ByteString const& partial_text) const -{ - auto reference_scope = scope_of_reference_to_symbol(node); - auto current_scope = scope_of_node(node); - - auto symbol_matches = [&](Symbol const& symbol) { - if (!is_symbol_available(symbol, current_scope, reference_scope)) { - return false; - } - - if (!symbol.name.name.starts_with(partial_text)) - return false; - - if (symbol.is_local) { - // If this symbol was declared below us in a function, it's not available to us. - bool is_unavailable = symbol.is_local && symbol.declaration->start().line > node.start().line; - if (is_unavailable) - return false; - } - - return true; - }; - - Vector matches; - - for_each_available_symbol(document, [&](Symbol const& symbol) { - if (symbol_matches(symbol)) { - matches.append(symbol); - } - return IterationDecision::Continue; - }); - - Vector suggestions; - for (auto& symbol : matches) { - suggestions.append({ symbol.name.name, partial_text.length() }); - } - - if (reference_scope.is_empty()) { - for (auto& preprocessor_name : document.preprocessor().definitions().keys()) { - if (preprocessor_name.starts_with(partial_text)) { - suggestions.append({ preprocessor_name, partial_text.length() }); - } - } - } - - return suggestions; -} - -Vector CppComprehensionEngine::scope_of_reference_to_symbol(ASTNode const& node) const -{ - Name const* name = nullptr; - if (node.is_name()) { - // FIXME It looks like this code path is never taken - name = reinterpret_cast(&node); - } else if (node.is_identifier()) { - auto* parent = node.parent(); - if (!(parent && parent->is_name())) - return {}; - name = reinterpret_cast(parent); - } else { - return {}; - } - - VERIFY(name->is_name()); - - Vector scope_parts; - for (auto& scope_part : name->scope()) { - // If the target node is part of a scope reference, we want to end the scope chain before it. - if (scope_part == &node) - break; - scope_parts.append(scope_part->name()); - } - return scope_parts; -} - -Vector CppComprehensionEngine::autocomplete_property(DocumentData const& document, MemberExpression const& parent, ByteString const partial_text) const -{ - VERIFY(parent.object()); - auto type = type_of(document, *parent.object()); - if (type.is_empty()) { - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "Could not infer type of object"); - return {}; - } - - Vector suggestions; - for (auto& prop : properties_of_type(document, type)) { - if (prop.name.name.starts_with(partial_text)) { - suggestions.append({ prop.name.name, partial_text.length() }); - } - } - return suggestions; -} - -bool CppComprehensionEngine::is_property(ASTNode const& node) const -{ - if (!node.parent()->is_member_expression()) - return false; - - auto& parent = verify_cast(*node.parent()); - return parent.property() == &node; -} - -ByteString CppComprehensionEngine::type_of_property(DocumentData const& document, Identifier const& identifier) const -{ - auto& parent = verify_cast(*identifier.parent()); - VERIFY(parent.object()); - auto properties = properties_of_type(document, type_of(document, *parent.object())); - for (auto& prop : properties) { - if (prop.name.name != identifier.name()) - continue; - Type const* type { nullptr }; - if (prop.declaration->is_variable_declaration()) { - type = verify_cast(*prop.declaration).type(); - } - if (!type) - continue; - if (!type->is_named_type()) - continue; - - VERIFY(verify_cast(*type).name()); - if (verify_cast(*type).name()) - return verify_cast(*type).name()->full_name(); - return ByteString::empty(); - } - return {}; -} - -ByteString CppComprehensionEngine::type_of_variable(Identifier const& identifier) const -{ - ASTNode const* current = &identifier; - while (current) { - for (auto& decl : current->declarations()) { - if (decl->is_variable_or_parameter_declaration()) { - auto& var_or_param = verify_cast(*decl); - if (var_or_param.full_name() == identifier.name() && var_or_param.type()->is_named_type()) { - VERIFY(verify_cast(*var_or_param.type()).name()); - if (verify_cast(*var_or_param.type()).name()) - return verify_cast(*var_or_param.type()).name()->full_name(); - return ByteString::empty(); - } - } - } - current = current->parent(); - } - return {}; -} - -ByteString CppComprehensionEngine::type_of(DocumentData const& document, Expression const& expression) const -{ - if (expression.is_member_expression()) { - auto& member_expression = verify_cast(expression); - VERIFY(member_expression.property()); - if (member_expression.property()->is_identifier()) - return type_of_property(document, static_cast(*member_expression.property())); - return {}; - } - - Identifier const* identifier { nullptr }; - if (expression.is_name()) { - identifier = static_cast(expression).name(); - } else if (expression.is_identifier()) { - identifier = &static_cast(expression); - } else { - dbgln("expected identifier or name, got: {}", expression.class_name()); - VERIFY_NOT_REACHED(); // TODO - } - VERIFY(identifier); - if (is_property(*identifier)) - return type_of_property(document, *identifier); - - return type_of_variable(*identifier); -} - -Vector CppComprehensionEngine::properties_of_type(DocumentData const& document, ByteString const& type) const -{ - auto type_symbol = SymbolName::create(type); - auto decl = find_declaration_of(document, type_symbol); - if (!decl) { - dbgln("Couldn't find declaration of type: {}", type); - return {}; - } - - if (!decl->is_struct_or_class()) { - dbgln("Expected declaration of type: {} to be struct or class", type); - return {}; - } - - auto& struct_or_class = verify_cast(*decl); - VERIFY(struct_or_class.full_name() == type_symbol.name); - - Vector properties; - for (auto& member : struct_or_class.members()) { - Vector scope(type_symbol.scope); - scope.append(type_symbol.name); - // FIXME: We don't have to create the Symbol here, it should already exist in the 'm_symbol' table of some DocumentData we already parsed. - properties.append(Symbol::create(member->full_name(), scope, member, Symbol::IsLocal::No)); - } - return properties; -} - -CppComprehensionEngine::Symbol CppComprehensionEngine::Symbol::create(StringView name, Vector const& scope, NonnullRefPtr declaration, IsLocal is_local) -{ - return { { name, scope }, move(declaration), is_local == IsLocal::Yes }; -} - -Vector CppComprehensionEngine::get_child_symbols(ASTNode const& node) const -{ - return get_child_symbols(node, {}, Symbol::IsLocal::No); -} - -Vector CppComprehensionEngine::get_child_symbols(ASTNode const& node, Vector const& scope, Symbol::IsLocal is_local) const -{ - Vector symbols; - - for (auto& decl : node.declarations()) { - symbols.append(Symbol::create(decl->full_name(), scope, decl, is_local)); - - bool should_recurse = decl->is_namespace() || decl->is_struct_or_class() || decl->is_function(); - bool are_child_symbols_local = decl->is_function(); - - if (!should_recurse) - continue; - - auto new_scope = scope; - new_scope.append(decl->full_name()); - symbols.extend(get_child_symbols(decl, new_scope, are_child_symbols_local ? Symbol::IsLocal::Yes : is_local)); - } - - return symbols; -} - -ByteString CppComprehensionEngine::document_path_from_include_path(StringView include_path) const -{ - static Regex library_include("<(.+)>"); - static Regex user_defined_include("\"(.+)\""); - - auto document_path_for_library_include = [&](StringView include_path) -> ByteString { - RegexResult result; - if (!library_include.search(include_path, result)) - return {}; - - auto path = result.capture_group_matches.at(0).at(0).view.string_view(); - return ByteString::formatted("/usr/include/{}", path); - }; - - auto document_path_for_user_defined_include = [&](StringView include_path) -> ByteString { - RegexResult result; - if (!user_defined_include.search(include_path, result)) - return {}; - - return result.capture_group_matches.at(0).at(0).view.string_view(); - }; - - auto result = document_path_for_library_include(include_path); - if (result.is_empty()) - result = document_path_for_user_defined_include(include_path); - - return result; -} - -void CppComprehensionEngine::on_edit(ByteString const& file) -{ - set_document_data(file, create_document_data_for(file)); -} - -void CppComprehensionEngine::file_opened([[maybe_unused]] ByteString const& file) -{ - get_or_create_document_data(file); -} - -Optional CppComprehensionEngine::find_declaration_of(ByteString const& filename, const GUI::TextPosition& identifier_position) -{ - auto const* document_ptr = get_or_create_document_data(filename); - if (!document_ptr) - return {}; - - auto const& document = *document_ptr; - auto decl = find_declaration_of(document, identifier_position); - if (decl) { - return CodeComprehension::ProjectLocation { decl->filename(), decl->start().line, decl->start().column }; - } - - return find_preprocessor_definition(document, identifier_position); -} - -RefPtr CppComprehensionEngine::find_declaration_of(DocumentData const& document, const GUI::TextPosition& identifier_position) -{ - auto node = document.parser().node_at(Cpp::Position { identifier_position.line(), identifier_position.column() }); - if (!node) { - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", identifier_position.line(), identifier_position.column()); - return {}; - } - return find_declaration_of(document, *node); -} - -Optional CppComprehensionEngine::find_preprocessor_definition(DocumentData const& document, const GUI::TextPosition& text_position) -{ - Position cpp_position { text_position.line(), text_position.column() }; - auto substitution = find_preprocessor_substitution(document, cpp_position); - if (!substitution.has_value()) - return {}; - return CodeComprehension::ProjectLocation { substitution->defined_value.filename, substitution->defined_value.line, substitution->defined_value.column }; -} - -Optional CppComprehensionEngine::find_preprocessor_substitution(DocumentData const& document, Cpp::Position const& cpp_position) -{ - // Search for a replaced preprocessor token that intersects with text_position - for (auto& substitution : document.preprocessor().substitutions()) { - if (substitution.original_tokens.first().start() > cpp_position) - continue; - if (substitution.original_tokens.first().end() < cpp_position) - continue; - return substitution; - } - return {}; -} - -struct TargetDeclaration { - enum Type { - Variable, - Type, - Function, - Property, - Scope - } type; - ByteString name; -}; - -static Optional get_target_declaration(ASTNode const& node, ByteString name); -static Optional get_target_declaration(ASTNode const& node) -{ - if (node.is_identifier()) { - return get_target_declaration(node, static_cast(node).name()); - } - - if (node.is_declaration()) { - return get_target_declaration(node, verify_cast(node).full_name()); - } - - if (node.is_type() && node.parent() && node.parent()->is_declaration()) { - return get_target_declaration(*node.parent(), verify_cast(node.parent())->full_name()); - } - - dbgln("get_target_declaration: Invalid argument node of type: {}", node.class_name()); - return {}; -} - -static Optional get_target_declaration(ASTNode const& node, ByteString name) -{ - if (node.parent() && node.parent()->is_name()) { - auto& name_node = *verify_cast(node.parent()); - if (&node != name_node.name()) { - // Node is part of scope reference chain - return TargetDeclaration { TargetDeclaration::Type::Scope, name }; - } - if (name_node.parent() && name_node.parent()->is_declaration()) { - auto declaration = verify_cast(name_node.parent()); - if (declaration->is_struct_or_class() || declaration->is_enum()) { - return TargetDeclaration { TargetDeclaration::Type::Type, name }; - } - if (declaration->is_function()) { - return TargetDeclaration { TargetDeclaration::Type::Function, name }; - } - } - } - - if ((node.parent() && node.parent()->is_function_call()) || (node.parent()->is_name() && node.parent()->parent() && node.parent()->parent()->is_function_call())) { - return TargetDeclaration { TargetDeclaration::Type::Function, name }; - } - - if ((node.parent() && node.parent()->is_type()) || (node.parent()->is_name() && node.parent()->parent() && node.parent()->parent()->is_type())) - return TargetDeclaration { TargetDeclaration::Type::Type, name }; - - if ((node.parent() && node.parent()->is_member_expression())) - return TargetDeclaration { TargetDeclaration::Type::Property, name }; - - return TargetDeclaration { TargetDeclaration::Type::Variable, name }; -} -RefPtr CppComprehensionEngine::find_declaration_of(DocumentData const& document_data, ASTNode const& node) const -{ - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "find_declaration_of: {} ({})", document_data.parser().text_of_node(node), node.class_name()); - - auto target_decl = get_target_declaration(node); - if (!target_decl.has_value()) - return {}; - - auto reference_scope = scope_of_reference_to_symbol(node); - auto current_scope = scope_of_node(node); - - auto symbol_matches = [&](Symbol const& symbol) { - bool match_function = target_decl.value().type == TargetDeclaration::Function && symbol.declaration->is_function(); - bool match_variable = target_decl.value().type == TargetDeclaration::Variable && symbol.declaration->is_variable_declaration(); - bool match_type = target_decl.value().type == TargetDeclaration::Type && (symbol.declaration->is_struct_or_class() || symbol.declaration->is_enum()); - bool match_property = target_decl.value().type == TargetDeclaration::Property && symbol.declaration->parent()->is_declaration() && verify_cast(symbol.declaration->parent())->is_struct_or_class(); - bool match_parameter = target_decl.value().type == TargetDeclaration::Variable && symbol.declaration->is_parameter(); - bool match_scope = target_decl.value().type == TargetDeclaration::Scope && (symbol.declaration->is_namespace() || symbol.declaration->is_struct_or_class()); - - if (match_property) { - // FIXME: This is not really correct, we also need to check that the type of the struct/class matches (not just the property name) - if (symbol.name.name == target_decl.value().name) { - return true; - } - } - - if (!is_symbol_available(symbol, current_scope, reference_scope)) { - return false; - } - - if (match_function || match_type || match_scope) { - if (symbol.name.name == target_decl->name) - return true; - } - - if (match_variable || match_parameter) { - // If this symbol was declared below us in a function, it's not available to us. - bool is_unavailable = symbol.is_local && symbol.declaration->start().line > node.start().line; - - if (!is_unavailable && (symbol.name.name == target_decl->name)) { - return true; - } - } - - return false; - }; - - Optional match; - - for_each_available_symbol(document_data, [&](Symbol const& symbol) { - if (symbol_matches(symbol)) { - match = symbol; - return IterationDecision::Break; - } - return IterationDecision::Continue; - }); - - if (!match.has_value()) - return {}; - - return match->declaration; -} - -void CppComprehensionEngine::update_declared_symbols(DocumentData& document) -{ - for (auto& symbol : get_child_symbols(*document.parser().root_node())) { - document.m_symbols.set(symbol.name, move(symbol)); - } - - Vector declarations; - for (auto& symbol_entry : document.m_symbols) { - auto& symbol = symbol_entry.value; - declarations.append({ symbol.name.name, { document.filename(), symbol.declaration->start().line, symbol.declaration->start().column }, type_of_declaration(symbol.declaration), symbol.name.scope_as_string() }); - } - - for (auto& definition : document.preprocessor().definitions()) { - declarations.append({ definition.key, { document.filename(), definition.value.line, definition.value.column }, CodeComprehension::DeclarationType::PreprocessorDefinition, {} }); - } - set_declarations_of_document(document.filename(), move(declarations)); -} - -void CppComprehensionEngine::update_todo_entries(DocumentData& document) -{ - set_todo_entries_of_document(document.filename(), document.parser().get_todo_entries()); -} - -CodeComprehension::DeclarationType CppComprehensionEngine::type_of_declaration(Cpp::Declaration const& decl) -{ - if (decl.is_struct()) - return CodeComprehension::DeclarationType::Struct; - if (decl.is_class()) - return CodeComprehension::DeclarationType::Class; - if (decl.is_function()) - return CodeComprehension::DeclarationType::Function; - if (decl.is_variable_declaration()) - return CodeComprehension::DeclarationType::Variable; - if (decl.is_namespace()) - return CodeComprehension::DeclarationType::Namespace; - if (decl.is_member()) - return CodeComprehension::DeclarationType::Member; - return CodeComprehension::DeclarationType::Variable; -} - -OwnPtr CppComprehensionEngine::create_document_data(ByteString text, ByteString const& filename) -{ - auto document_data = make(); - document_data->m_filename = filename; - document_data->m_text = move(text); - document_data->m_preprocessor = make(document_data->m_filename, document_data->text()); - document_data->preprocessor().set_ignore_unsupported_keywords(true); - document_data->preprocessor().set_ignore_invalid_statements(true); - document_data->preprocessor().set_keep_include_statements(true); - - document_data->preprocessor().definitions_in_header_callback = [this](StringView include_path) -> Preprocessor::Definitions { - auto included_document = get_or_create_document_data(document_path_from_include_path(include_path)); - if (!included_document) - return {}; - - return included_document->preprocessor().definitions(); - }; - - auto tokens = document_data->preprocessor().process_and_lex(); - - for (auto include_path : document_data->preprocessor().included_paths()) { - auto include_fullpath = document_path_from_include_path(include_path); - auto included_document = get_or_create_document_data(include_fullpath); - if (!included_document) - continue; - - document_data->m_available_headers.set(include_fullpath); - - for (auto& header : included_document->m_available_headers) - document_data->m_available_headers.set(header); - } - - document_data->m_parser = make(move(tokens), filename); - - auto root = document_data->parser().parse(); - - if constexpr (CPP_LANGUAGE_SERVER_DEBUG) - root->dump(); - - update_declared_symbols(*document_data); - update_todo_entries(*document_data); - - return document_data; -} - -Vector CppComprehensionEngine::scope_of_node(ASTNode const& node) const -{ - - auto parent = node.parent(); - if (!parent) - return {}; - - auto parent_scope = scope_of_node(*parent); - - if (!parent->is_declaration()) - return parent_scope; - - auto& parent_decl = static_cast(*parent); - - StringView containing_scope; - if (parent_decl.is_namespace()) - containing_scope = static_cast(parent_decl).full_name(); - if (parent_decl.is_struct_or_class()) - containing_scope = static_cast(parent_decl).full_name(); - if (parent_decl.is_function()) - containing_scope = static_cast(parent_decl).full_name(); - - parent_scope.append(containing_scope); - return parent_scope; -} - -Optional> CppComprehensionEngine::try_autocomplete_include(DocumentData const&, Token include_path_token, Cpp::Position const& cursor_position) const -{ - VERIFY(include_path_token.type() == Token::Type::IncludePath); - auto partial_include = include_path_token.text().trim_whitespace(); - - enum IncludeType { - Project, - System, - } include_type { Project }; - - ByteString include_root; - bool already_has_suffix = false; - if (partial_include.starts_with('<')) { - include_root = "/usr/include/"; - include_type = System; - if (partial_include.ends_with('>')) { - already_has_suffix = true; - partial_include = partial_include.substring_view(0, partial_include.length() - 1).trim_whitespace(); - } - } else if (partial_include.starts_with('"')) { - include_root = filedb().project_root().value_or(""); - if (partial_include.length() > 1 && partial_include.ends_with('\"')) { - already_has_suffix = true; - partial_include = partial_include.substring_view(0, partial_include.length() - 1).trim_whitespace(); - } - } else - return {}; - - // The cursor is past the end of the <> or "", and so should not trigger autocomplete. - if (already_has_suffix && include_path_token.end() <= cursor_position) - return {}; - - auto last_slash = partial_include.find_last('/'); - auto include_dir = ByteString::empty(); - auto partial_basename = partial_include.substring_view((last_slash.has_value() ? last_slash.value() : 0) + 1); - if (last_slash.has_value()) { - include_dir = partial_include.substring_view(1, last_slash.value()); - } - - auto full_dir = LexicalPath::join(include_root, include_dir).string(); - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "searching path: {}, partial_basename: {}", full_dir, partial_basename); - - Core::DirIterator it(full_dir, Core::DirIterator::Flags::SkipDots); - Vector options; - - auto prefix = include_type == System ? "<" : "\""; - auto suffix = include_type == System ? ">" : "\""; - while (it.has_next()) { - auto path = it.next_path(); - - if (!path.starts_with(partial_basename)) - continue; - - if (FileSystem::is_directory(LexicalPath::join(full_dir, path).string())) { - // FIXME: Don't dismiss the autocomplete when filling these suggestions. - auto completion = ByteString::formatted("{}{}{}/", prefix, include_dir, path); - options.empend(completion, include_dir.length() + partial_basename.length() + 1, CodeComprehension::Language::Cpp, path, CodeComprehension::AutocompleteResultEntry::HideAutocompleteAfterApplying::No); - } else if (path.ends_with(".h"sv)) { - // FIXME: Place the cursor after the trailing > or ", even if it was - // already typed. - auto completion = ByteString::formatted("{}{}{}{}", prefix, include_dir, path, already_has_suffix ? "" : suffix); - options.empend(completion, include_dir.length() + partial_basename.length() + 1, CodeComprehension::Language::Cpp, path); - } - } - - return options; -} - -RefPtr CppComprehensionEngine::find_declaration_of(CppComprehensionEngine::DocumentData const& document, CppComprehensionEngine::SymbolName const& target_symbol_name) const -{ - RefPtr target_declaration; - for_each_available_symbol(document, [&](Symbol const& symbol) { - if (symbol.name == target_symbol_name) { - target_declaration = symbol.declaration; - return IterationDecision::Break; - } - return IterationDecision::Continue; - }); - return target_declaration; -} - -ByteString CppComprehensionEngine::SymbolName::scope_as_string() const -{ - if (scope.is_empty()) - return ByteString::empty(); - - StringBuilder builder; - for (size_t i = 0; i < scope.size() - 1; ++i) { - builder.appendff("{}::", scope[i]); - } - builder.append(scope.last()); - return builder.to_byte_string(); -} - -CppComprehensionEngine::SymbolName CppComprehensionEngine::SymbolName::create(StringView name, Vector&& scope) -{ - return { name, move(scope) }; -} - -CppComprehensionEngine::SymbolName CppComprehensionEngine::SymbolName::create(StringView qualified_name) -{ - auto parts = qualified_name.split_view("::"sv); - VERIFY(!parts.is_empty()); - auto name = parts.take_last(); - return SymbolName::create(name, move(parts)); -} - -ByteString CppComprehensionEngine::SymbolName::to_byte_string() const -{ - if (scope.is_empty()) - return name; - return ByteString::formatted("{}::{}", scope_as_string(), name); -} - -bool CppComprehensionEngine::is_symbol_available(Symbol const& symbol, Vector const& current_scope, Vector const& reference_scope) -{ - - if (!reference_scope.is_empty()) { - return reference_scope == symbol.name.scope; - } - - // FIXME: Take "using namespace ..." into consideration - - // Check if current_scope starts with symbol's scope - if (symbol.name.scope.size() > current_scope.size()) - return false; - - for (size_t i = 0; i < symbol.name.scope.size(); ++i) { - if (current_scope[i] != symbol.name.scope[i]) - return false; - } - - return true; -} - -Optional CppComprehensionEngine::get_function_params_hint(ByteString const& filename, const GUI::TextPosition& identifier_position) -{ - auto const* document_ptr = get_or_create_document_data(filename); - if (!document_ptr) - return {}; - - auto const& document = *document_ptr; - Cpp::Position cpp_position { identifier_position.line(), identifier_position.column() }; - auto node = document.parser().node_at(cpp_position); - if (!node) { - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", identifier_position.line(), identifier_position.column()); - return {}; - } - - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "node type: {}", node->class_name()); - - FunctionCall const* call_node { nullptr }; - - if (node->is_function_call()) { - call_node = verify_cast(node.ptr()); - - auto token = document.parser().token_at(cpp_position); - - // If we're in a function call with 0 arguments - if (token.has_value() && (token->type() == Token::Type::LeftParen || token->type() == Token::Type::RightParen)) { - return get_function_params_hint(document, *call_node, call_node->arguments().is_empty() ? 0 : call_node->arguments().size() - 1); - } - } - - // Walk upwards in the AST to find a FunctionCall node - while (!call_node && node) { - auto parent_is_call = node->parent() && node->parent()->is_function_call(); - if (parent_is_call) { - call_node = verify_cast(node->parent()); - break; - } - node = node->parent(); - } - - if (!call_node) { - dbgln("did not find function call"); - return {}; - } - - Optional invoked_arg_index; - for (size_t arg_index = 0; arg_index < call_node->arguments().size(); ++arg_index) { - if (call_node->arguments()[arg_index] == node.ptr()) { - invoked_arg_index = arg_index; - break; - } - } - if (!invoked_arg_index.has_value()) { - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "could not find argument index, defaulting to the last argument"); - invoked_arg_index = call_node->arguments().is_empty() ? 0 : call_node->arguments().size() - 1; - } - - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "arg index: {}", invoked_arg_index.value()); - return get_function_params_hint(document, *call_node, invoked_arg_index.value()); -} - -Optional CppComprehensionEngine::get_function_params_hint( - DocumentData const& document, - FunctionCall const& call_node, - size_t argument_index) -{ - Identifier const* callee = nullptr; - VERIFY(call_node.callee()); - if (call_node.callee()->is_identifier()) { - callee = verify_cast(call_node.callee()); - } else if (call_node.callee()->is_name()) { - callee = verify_cast(*call_node.callee()).name(); - } else if (call_node.callee()->is_member_expression()) { - auto& member_exp = verify_cast(*call_node.callee()); - VERIFY(member_exp.property()); - if (member_exp.property()->is_identifier()) { - callee = verify_cast(member_exp.property()); - } - } - - if (!callee) { - dbgln("unexpected node type for function call: {}", call_node.callee()->class_name()); - return {}; - } - VERIFY(callee); - - auto decl = find_declaration_of(document, *callee); - if (!decl) { - dbgln("func decl not found"); - return {}; - } - if (!decl->is_function()) { - dbgln("declaration is not a function"); - return {}; - } - - auto& func_decl = verify_cast(*decl); - auto document_of_declaration = get_document_data(func_decl.filename()); - - FunctionParamsHint hint {}; - hint.current_index = argument_index; - for (auto& arg : func_decl.parameters()) { - Vector tokens_text; - for (auto token : document_of_declaration->parser().tokens_in_range(arg->start(), arg->end())) { - tokens_text.append(token.text()); - } - hint.params.append(ByteString::join(' ', tokens_text)); - } - - return hint; -} - -Vector CppComprehensionEngine::get_tokens_info(ByteString const& filename) -{ - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "CppComprehensionEngine::get_tokens_info: {}", filename); - - auto const* document_ptr = get_or_create_document_data(filename); - if (!document_ptr) - return {}; - - auto const& document = *document_ptr; - - Vector tokens_info; - for (auto const& token : document.preprocessor().unprocessed_tokens()) { - - tokens_info.append({ get_token_semantic_type(document, token), - token.start().line, token.start().column, token.end().line, token.end().column }); - dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "{}: {}", token.text(), CodeComprehension::TokenInfo::type_to_string(tokens_info.last().type)); - } - return tokens_info; -} - -CodeComprehension::TokenInfo::SemanticType CppComprehensionEngine::get_token_semantic_type(DocumentData const& document, Token const& token) -{ - using GUI::AutocompleteProvider; - switch (token.type()) { - case Cpp::Token::Type::Identifier: - return get_semantic_type_for_identifier(document, token.start()); - case Cpp::Token::Type::Keyword: - return CodeComprehension::TokenInfo::SemanticType::Keyword; - case Cpp::Token::Type::KnownType: - return CodeComprehension::TokenInfo::SemanticType::Type; - case Cpp::Token::Type::DoubleQuotedString: - case Cpp::Token::Type::SingleQuotedString: - case Cpp::Token::Type::RawString: - return CodeComprehension::TokenInfo::SemanticType::String; - case Cpp::Token::Type::Integer: - case Cpp::Token::Type::Float: - return CodeComprehension::TokenInfo::SemanticType::Number; - case Cpp::Token::Type::IncludePath: - return CodeComprehension::TokenInfo::SemanticType::IncludePath; - case Cpp::Token::Type::EscapeSequence: - return CodeComprehension::TokenInfo::SemanticType::Keyword; - case Cpp::Token::Type::PreprocessorStatement: - case Cpp::Token::Type::IncludeStatement: - return CodeComprehension::TokenInfo::SemanticType::PreprocessorStatement; - case Cpp::Token::Type::Comment: - return CodeComprehension::TokenInfo::SemanticType::Comment; - default: - return CodeComprehension::TokenInfo::SemanticType::Unknown; - } -} - -CodeComprehension::TokenInfo::SemanticType CppComprehensionEngine::get_semantic_type_for_identifier(DocumentData const& document, Position position) -{ - if (find_preprocessor_substitution(document, position).has_value()) - return CodeComprehension::TokenInfo::SemanticType::PreprocessorMacro; - - auto decl = find_declaration_of(document, GUI::TextPosition { position.line, position.column }); - if (!decl) - return CodeComprehension::TokenInfo::SemanticType::Identifier; - - if (decl->is_function()) - return CodeComprehension::TokenInfo::SemanticType::Function; - if (decl->is_parameter()) - return CodeComprehension::TokenInfo::SemanticType::Parameter; - if (decl->is_variable_declaration()) { - if (decl->is_member()) - return CodeComprehension::TokenInfo::SemanticType::Member; - return CodeComprehension::TokenInfo::SemanticType::Variable; - } - if (decl->is_struct_or_class() || decl->is_enum()) - return CodeComprehension::TokenInfo::SemanticType::CustomType; - if (decl->is_namespace()) - return CodeComprehension::TokenInfo::SemanticType::Namespace; - - return CodeComprehension::TokenInfo::SemanticType::Identifier; -} - -} diff --git a/Userland/Libraries/LibCodeComprehension/Cpp/CppComprehensionEngine.h b/Userland/Libraries/LibCodeComprehension/Cpp/CppComprehensionEngine.h deleted file mode 100644 index 60d3c3b61f1..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Cpp/CppComprehensionEngine.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2021-2022, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace CodeComprehension::Cpp { - -using namespace ::Cpp; - -class CppComprehensionEngine : public CodeComprehensionEngine { -public: - CppComprehensionEngine(FileDB const& filedb); - - virtual Vector get_suggestions(ByteString const& file, GUI::TextPosition const& autocomplete_position) override; - virtual void on_edit(ByteString const& file) override; - virtual void file_opened([[maybe_unused]] ByteString const& file) override; - virtual Optional find_declaration_of(ByteString const& filename, GUI::TextPosition const& identifier_position) override; - virtual Optional get_function_params_hint(ByteString const&, GUI::TextPosition const&) override; - virtual Vector get_tokens_info(ByteString const& filename) override; - -private: - struct SymbolName { - StringView name; - Vector scope; - - static SymbolName create(StringView, Vector&&); - static SymbolName create(StringView); - ByteString scope_as_string() const; - ByteString to_byte_string() const; - - bool operator==(SymbolName const&) const = default; - }; - - struct Symbol { - SymbolName name; - NonnullRefPtr declaration; - - // Local symbols are symbols that should not appear in a global symbol search. - // For example, a variable that is declared inside a function will have is_local = true. - bool is_local { false }; - - enum class IsLocal { - No, - Yes - }; - static Symbol create(StringView name, Vector const& scope, NonnullRefPtr, IsLocal is_local); - }; - - friend Traits; - - struct DocumentData { - ByteString const& filename() const { return m_filename; } - ByteString const& text() const { return m_text; } - Preprocessor const& preprocessor() const - { - VERIFY(m_preprocessor); - return *m_preprocessor; - } - Preprocessor& preprocessor() - { - VERIFY(m_preprocessor); - return *m_preprocessor; - } - Parser const& parser() const - { - VERIFY(m_parser); - return *m_parser; - } - Parser& parser() - { - VERIFY(m_parser); - return *m_parser; - } - - ByteString m_filename; - ByteString m_text; - OwnPtr m_preprocessor; - OwnPtr m_parser; - - HashMap m_symbols; - HashTable m_available_headers; - }; - - Vector autocomplete_property(DocumentData const&, MemberExpression const&, ByteString const partial_text) const; - Vector autocomplete_name(DocumentData const&, ASTNode const&, ByteString const& partial_text) const; - ByteString type_of(DocumentData const&, Expression const&) const; - ByteString type_of_property(DocumentData const&, Identifier const&) const; - ByteString type_of_variable(Identifier const&) const; - bool is_property(ASTNode const&) const; - RefPtr find_declaration_of(DocumentData const&, ASTNode const&) const; - RefPtr find_declaration_of(DocumentData const&, SymbolName const&) const; - RefPtr find_declaration_of(DocumentData const&, const GUI::TextPosition& identifier_position); - - enum class RecurseIntoScopes { - No, - Yes - }; - - Vector properties_of_type(DocumentData const& document, ByteString const& type) const; - Vector get_child_symbols(ASTNode const&) const; - Vector get_child_symbols(ASTNode const&, Vector const& scope, Symbol::IsLocal) const; - - DocumentData const* get_document_data(ByteString const& file) const; - DocumentData const* get_or_create_document_data(ByteString const& file); - void set_document_data(ByteString const& file, OwnPtr&& data); - - OwnPtr create_document_data_for(ByteString const& file); - ByteString document_path_from_include_path(StringView include_path) const; - void update_declared_symbols(DocumentData&); - void update_todo_entries(DocumentData&); - CodeComprehension::DeclarationType type_of_declaration(Cpp::Declaration const&); - Vector scope_of_node(ASTNode const&) const; - Vector scope_of_reference_to_symbol(ASTNode const&) const; - - Optional find_preprocessor_definition(DocumentData const&, const GUI::TextPosition&); - Optional find_preprocessor_substitution(DocumentData const&, Cpp::Position const&); - - OwnPtr create_document_data(ByteString text, ByteString const& filename); - Optional> try_autocomplete_property(DocumentData const&, ASTNode const&, Optional containing_token) const; - Optional> try_autocomplete_name(DocumentData const&, ASTNode const&, Optional containing_token) const; - Optional> try_autocomplete_include(DocumentData const&, Token include_path_token, Cpp::Position const& cursor_position) const; - static bool is_symbol_available(Symbol const&, Vector const& current_scope, Vector const& reference_scope); - Optional get_function_params_hint(DocumentData const&, FunctionCall const&, size_t argument_index); - - template - void for_each_available_symbol(DocumentData const&, Func) const; - - template - void for_each_included_document_recursive(DocumentData const&, Func) const; - - CodeComprehension::TokenInfo::SemanticType get_token_semantic_type(DocumentData const&, Token const&); - CodeComprehension::TokenInfo::SemanticType get_semantic_type_for_identifier(DocumentData const&, Position); - - HashMap> m_documents; - - // A document's path will be in this set if we're currently processing it. - // A document is added to this set when we start processing it (e.g because it was #included) and removed when we're done. - // We use this to prevent circular #includes from looping indefinitely. - HashTable m_unfinished_documents; -}; - -template -void CppComprehensionEngine::for_each_available_symbol(DocumentData const& document, Func func) const -{ - for (auto& item : document.m_symbols) { - auto decision = func(item.value); - if (decision == IterationDecision::Break) - return; - } - - for_each_included_document_recursive(document, [&](DocumentData const& document) { - for (auto& item : document.m_symbols) { - auto decision = func(item.value); - if (decision == IterationDecision::Break) - return IterationDecision::Break; - } - return IterationDecision::Continue; - }); -} - -template -void CppComprehensionEngine::for_each_included_document_recursive(DocumentData const& document, Func func) const -{ - for (auto& included_path : document.m_available_headers) { - auto* included_document = get_document_data(included_path); - if (!included_document) - continue; - auto decision = func(*included_document); - if (decision == IterationDecision::Break) - continue; - } -} -} - -namespace AK { - -template<> -struct Traits : public DefaultTraits { - static unsigned hash(CodeComprehension::Cpp::CppComprehensionEngine::SymbolName const& key) - { - unsigned hash = 0; - hash = pair_int_hash(hash, string_hash(key.name.characters_without_null_termination(), key.name.length())); - for (auto& scope_part : key.scope) { - hash = pair_int_hash(hash, string_hash(scope_part.characters_without_null_termination(), scope_part.length())); - } - return hash; - } -}; - -} diff --git a/Userland/Libraries/LibCodeComprehension/Cpp/Tests.cpp b/Userland/Libraries/LibCodeComprehension/Cpp/Tests.cpp deleted file mode 100644 index 38ff863f21e..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Cpp/Tests.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Tests.h" -#include "../FileDB.h" -#include "CppComprehensionEngine.h" -#include -#include - -static bool s_some_test_failed = false; - -#define I_TEST(name) \ - { \ - printf("Testing " #name "... "); \ - fflush(stdout); \ - } - -#define PASS \ - do { \ - printf("PASS\n"); \ - fflush(stdout); \ - return; \ - } while (0) - -#define FAIL(reason) \ - do { \ - printf("FAIL: " #reason "\n"); \ - s_some_test_failed = true; \ - return; \ - } while (0) - -#define RUN(function) \ - function; \ - if (s_some_test_failed) { \ - return 1; \ - } - -constexpr auto TESTS_ROOT_DIR = "/home/anon/Tests/cpp-tests/comprehension"sv; - -class FileDB : public CodeComprehension::FileDB { -public: - FileDB() = default; - - void add(ByteString filename, ByteString content) - { - m_map.set(filename, content); - } - - virtual Optional get_or_read_from_filesystem(StringView filename) const override - { - ByteString target_filename = filename; - if (project_root().has_value() && filename.starts_with(*project_root())) { - target_filename = LexicalPath::relative_path(filename, *project_root()); - } - return m_map.get(target_filename); - } - -private: - HashMap m_map; -}; - -static void test_complete_local_args(); -static void test_complete_local_vars(); -static void test_complete_type(); -static void test_find_variable_definition(); -static void test_find_array_variable_declaration_single(); -static void test_find_array_variable_declaration_single_empty(); -static void test_find_array_variable_declaration_double(); -static void test_complete_includes(); -static void test_parameters_hint(); - -int run_tests() -{ - RUN(test_complete_local_args()); - RUN(test_complete_local_vars()); - RUN(test_complete_type()); - RUN(test_find_variable_definition()); - RUN(test_find_array_variable_declaration_single()); - RUN(test_find_array_variable_declaration_single_empty()); - RUN(test_find_array_variable_declaration_double()); - RUN(test_complete_includes()); - RUN(test_parameters_hint()); - return 0; -} - -static void add_file(FileDB& filedb, ByteString const& name) -{ - auto file = Core::File::open(LexicalPath::join(TESTS_ROOT_DIR, name).string(), Core::File::OpenMode::Read).release_value_but_fixme_should_propagate_errors(); - filedb.add(name, ByteString::copy(MUST(file->read_until_eof()))); -} - -void test_complete_local_args() -{ - I_TEST(Complete Local Args) - FileDB filedb; - add_file(filedb, "complete_local_args.cpp"); - CodeComprehension::Cpp::CppComprehensionEngine engine(filedb); - auto suggestions = engine.get_suggestions("complete_local_args.cpp", { 2, 6 }); - if (suggestions.size() != 2) - FAIL(bad size); - - if (suggestions[0].completion == "argc" && suggestions[1].completion == "argv") - PASS; - - FAIL("wrong results"); -} - -void test_complete_local_vars() -{ - I_TEST(Complete Local Vars) - FileDB filedb; - add_file(filedb, "complete_local_vars.cpp"); - CodeComprehension::Cpp::CppComprehensionEngine autocomplete(filedb); - auto suggestions = autocomplete.get_suggestions("complete_local_vars.cpp", { 3, 7 }); - if (suggestions.size() != 1) - FAIL(bad size); - - if (suggestions[0].completion == "myvar1") - PASS; - - FAIL("wrong results"); -} - -void test_complete_type() -{ - I_TEST(Complete Type) - FileDB filedb; - add_file(filedb, "complete_type.cpp"); - CodeComprehension::Cpp::CppComprehensionEngine autocomplete(filedb); - auto suggestions = autocomplete.get_suggestions("complete_type.cpp", { 5, 7 }); - if (suggestions.size() != 1) - FAIL(bad size); - - if (suggestions[0].completion == "MyStruct") - PASS; - - FAIL("wrong results"); -} - -void test_find_variable_definition() -{ - I_TEST(Find Variable Declaration) - FileDB filedb; - add_file(filedb, "find_variable_declaration.cpp"); - CodeComprehension::Cpp::CppComprehensionEngine engine(filedb); - auto position = engine.find_declaration_of("find_variable_declaration.cpp", { 2, 5 }); - if (!position.has_value()) - FAIL("declaration not found"); - - if (position.value().file == "find_variable_declaration.cpp" && position.value().line == 0 && position.value().column >= 19) - PASS; - FAIL("wrong declaration location"); -} - -void test_find_array_variable_declaration_single() -{ - I_TEST(Find 1D Array as a Variable Declaration) - FileDB filedb; - auto filename = "find_array_variable_declaration.cpp"; - add_file(filedb, filename); - CodeComprehension::Cpp::CppComprehensionEngine engine(filedb); - auto position = engine.find_declaration_of(filename, { 3, 6 }); - if (!position.has_value()) - FAIL("declaration not found"); - - if (position.value().file == filename && position.value().line == 2 && position.value().column >= 4) - PASS; - - printf("Found at position %zu %zu\n", position.value().line, position.value().column); - FAIL("wrong declaration location"); -} - -void test_find_array_variable_declaration_single_empty() -{ - I_TEST(Find 1D Empty size Array as a Variable Declaration) - FileDB filedb; - auto filename = "find_array_variable_declaration.cpp"; - add_file(filedb, filename); - CodeComprehension::Cpp::CppComprehensionEngine engine(filedb); - auto position = engine.find_declaration_of(filename, { 6, 6 }); - if (!position.has_value()) - FAIL("declaration not found"); - - if (position.value().file == filename && position.value().line == 5 && position.value().column >= 4) - PASS; - - printf("Found at position %zu %zu\n", position.value().line, position.value().column); - FAIL("wrong declaration location"); -} - -void test_find_array_variable_declaration_double() -{ - I_TEST(Find 2D Array as a Variable Declaration) - FileDB filedb; - auto filename = "find_array_variable_declaration.cpp"; - add_file(filedb, filename); - CodeComprehension::Cpp::CppComprehensionEngine engine(filedb); - auto position = engine.find_declaration_of(filename, { 9, 6 }); - if (!position.has_value()) - FAIL("declaration not found"); - - if (position.value().file == filename && position.value().line == 8 && position.value().column >= 4) - PASS; - - printf("Found at position %zu %zu\n", position.value().line, position.value().column); - FAIL("wrong declaration location"); -} - -void test_complete_includes() -{ - I_TEST(Complete include statements) - FileDB filedb; - filedb.set_project_root(TESTS_ROOT_DIR); - add_file(filedb, "complete_includes.cpp"); - add_file(filedb, "sample_header.h"); - CodeComprehension::Cpp::CppComprehensionEngine autocomplete(filedb); - - auto suggestions = autocomplete.get_suggestions("complete_includes.cpp", { 0, 22 }); - if (suggestions.size() != 1) - FAIL(project include - bad size); - - if (suggestions[0].completion != "\"sample_header.h\"") - FAIL("project include - wrong results"); - - suggestions = autocomplete.get_suggestions("complete_includes.cpp", { 1, 18 }); - if (suggestions.size() != 1) - FAIL(global include - bad size); - - if (suggestions[0].completion != "") - FAIL("global include - wrong results"); - - PASS; -} - -void test_parameters_hint() -{ - I_TEST(Function Parameters hint) - FileDB filedb; - filedb.set_project_root(TESTS_ROOT_DIR); - add_file(filedb, "parameters_hint1.cpp"); - CodeComprehension::Cpp::CppComprehensionEngine engine(filedb); - - auto result = engine.get_function_params_hint("parameters_hint1.cpp", { 4, 9 }); - if (!result.has_value()) - FAIL("failed to get parameters hint (1)"); - if (result->params != Vector { "int x", "char y" } || result->current_index != 0) - FAIL("bad result (1)"); - - result = engine.get_function_params_hint("parameters_hint1.cpp", { 5, 15 }); - if (!result.has_value()) - FAIL("failed to get parameters hint (2)"); - if (result->params != Vector { "int x", "char y" } || result->current_index != 1) - FAIL("bad result (2)"); - - result = engine.get_function_params_hint("parameters_hint1.cpp", { 6, 8 }); - if (!result.has_value()) - FAIL("failed to get parameters hint (3)"); - if (result->params != Vector { "int x", "char y" } || result->current_index != 0) - FAIL("bad result (3)"); - - PASS; -} - -ErrorOr serenity_main(Main::Arguments) -{ - return run_tests(); -} diff --git a/Userland/Libraries/LibCodeComprehension/Cpp/Tests.h b/Userland/Libraries/LibCodeComprehension/Cpp/Tests.h deleted file mode 100644 index 0c98313e9ad..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Cpp/Tests.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -int run_tests(); diff --git a/Userland/Libraries/LibCodeComprehension/Cpp/Tests/.clang-format b/Userland/Libraries/LibCodeComprehension/Cpp/Tests/.clang-format deleted file mode 100644 index 48ad0abce45..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Cpp/Tests/.clang-format +++ /dev/null @@ -1,4 +0,0 @@ -# These are all test files, don't format them, as they maybe -# intentionally miss-formatted. -DisableFormat: true -SortIncludes: Never diff --git a/Userland/Libraries/LibCodeComprehension/Cpp/Tests/complete_includes.cpp b/Userland/Libraries/LibCodeComprehension/Cpp/Tests/complete_includes.cpp deleted file mode 100644 index 3eb239f29ff..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Cpp/Tests/complete_includes.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "sample_heade -#include - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "FileDB.h" -#include - -namespace CodeComprehension { - -ByteString FileDB::to_absolute_path(StringView filename) const -{ - if (LexicalPath { filename }.is_absolute()) { - return filename; - } - if (!m_project_root.has_value()) - return filename; - return LexicalPath { ByteString::formatted("{}/{}", *m_project_root, filename) }.string(); -} - -} diff --git a/Userland/Libraries/LibCodeComprehension/FileDB.h b/Userland/Libraries/LibCodeComprehension/FileDB.h deleted file mode 100644 index efa599a7219..00000000000 --- a/Userland/Libraries/LibCodeComprehension/FileDB.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2022, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace CodeComprehension { - -class FileDB { - AK_MAKE_NONCOPYABLE(FileDB); - AK_MAKE_NONMOVABLE(FileDB); - -public: - virtual ~FileDB() = default; - - virtual Optional get_or_read_from_filesystem(StringView filename) const = 0; - void set_project_root(StringView project_root) - { - if (project_root.is_null()) - m_project_root.clear(); - else - m_project_root = project_root; - } - Optional const& project_root() const { return m_project_root; } - ByteString to_absolute_path(StringView filename) const; - -protected: - FileDB() = default; - -private: - Optional m_project_root; -}; - -} diff --git a/Userland/Libraries/LibCodeComprehension/Shell/CMakeLists.txt b/Userland/Libraries/LibCodeComprehension/Shell/CMakeLists.txt deleted file mode 100644 index c4d213ea32f..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Shell/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -set(SOURCES - ShellComprehensionEngine.cpp -) - -serenity_lib(LibShellComprehension shellcomprehension) -target_link_libraries(LibShellComprehension PRIVATE LibCodeComprehension) diff --git a/Userland/Libraries/LibCodeComprehension/Shell/ConnectionFromClient.h b/Userland/Libraries/LibCodeComprehension/Shell/ConnectionFromClient.h deleted file mode 100644 index e0694d7d8c6..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Shell/ConnectionFromClient.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "ShellComprehensionEngine.h" -#include -#include - -namespace LanguageServers::Shell { - -class ConnectionFromClient final : public LanguageServers::ConnectionFromClient { - C_OBJECT(ConnectionFromClient); - -private: - ConnectionFromClient(NonnullOwnPtr socket) - : LanguageServers::ConnectionFromClient(move(socket)) - { - m_autocomplete_engine = make(m_filedb); - m_autocomplete_engine->set_declarations_of_document_callback = [this](ByteString const& filename, Vector&& declarations) { - async_declarations_in_document(filename, move(declarations)); - }; - m_autocomplete_engine->set_todo_entries_of_document_callback = [this](ByteString const& filename, Vector&& todo_entries) { - async_todo_entries_in_document(filename, move(todo_entries)); - }; - } - virtual ~ConnectionFromClient() override = default; -}; -} diff --git a/Userland/Libraries/LibCodeComprehension/Shell/ShellComprehensionEngine.cpp b/Userland/Libraries/LibCodeComprehension/Shell/ShellComprehensionEngine.cpp deleted file mode 100644 index 1f863a9e81a..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Shell/ShellComprehensionEngine.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "ShellComprehensionEngine.h" -#include -#include -#include - -namespace CodeComprehension::Shell { - -RefPtr<::Shell::Shell> ShellComprehensionEngine::s_shell {}; - -ShellComprehensionEngine::ShellComprehensionEngine(FileDB const& filedb) - : CodeComprehensionEngine(filedb, true) -{ -} - -ShellComprehensionEngine::DocumentData const& ShellComprehensionEngine::get_or_create_document_data(ByteString const& file) -{ - auto absolute_path = filedb().to_absolute_path(file); - if (!m_documents.contains(absolute_path)) { - set_document_data(absolute_path, create_document_data_for(absolute_path)); - } - return get_document_data(absolute_path); -} - -ShellComprehensionEngine::DocumentData const& ShellComprehensionEngine::get_document_data(ByteString const& file) const -{ - auto absolute_path = filedb().to_absolute_path(file); - auto document_data = m_documents.get(absolute_path); - VERIFY(document_data.has_value()); - return *document_data.value(); -} - -OwnPtr ShellComprehensionEngine::create_document_data_for(ByteString const& file) -{ - auto document = filedb().get_or_read_from_filesystem(file); - if (!document.has_value()) - return {}; - - auto content = document.value(); - auto document_data = make(move(content), file); - for (auto& path : document_data->sourced_paths()) - get_or_create_document_data(path); - - update_declared_symbols(*document_data); - return document_data; -} - -void ShellComprehensionEngine::set_document_data(ByteString const& file, OwnPtr&& data) -{ - m_documents.set(filedb().to_absolute_path(file), move(data)); -} - -ShellComprehensionEngine::DocumentData::DocumentData(ByteString&& _text, ByteString _filename) - : filename(move(_filename)) - , text(move(_text)) - , node(parse()) -{ -} - -Vector const& ShellComprehensionEngine::DocumentData::sourced_paths() const -{ - if (all_sourced_paths.has_value()) - return all_sourced_paths.value(); - - struct : public ::Shell::AST::NodeVisitor { - void visit(::Shell::AST::CastToCommand const* node) override - { - auto& inner = node->inner(); - if (inner->is_list()) { - if (auto* list = dynamic_cast<::Shell::AST::ListConcatenate const*>(inner.ptr())) { - auto& entries = list->list(); - if (entries.size() == 2 && entries.first()->is_bareword() && static_ptr_cast<::Shell::AST::BarewordLiteral>(entries.first())->text() == "source") { - auto& filename = entries[1]; - if (filename->would_execute()) - return; - auto name_list_node = const_cast<::Shell::AST::Node*>(filename.ptr())->run(nullptr).release_value_but_fixme_should_propagate_errors(); - auto name_list = name_list_node->resolve_as_list(nullptr).release_value_but_fixme_should_propagate_errors(); - StringBuilder builder; - builder.join(' ', name_list); - sourced_files.set(builder.to_byte_string()); - } - } - } - ::Shell::AST::NodeVisitor::visit(node); - } - - HashTable sourced_files; - } visitor; - - node->visit(visitor); - - Vector sourced_paths; - for (auto& entry : visitor.sourced_files) - sourced_paths.append(move(entry)); - - all_sourced_paths = move(sourced_paths); - return all_sourced_paths.value(); -} - -NonnullRefPtr<::Shell::AST::Node> ShellComprehensionEngine::DocumentData::parse() const -{ - ::Shell::Parser parser { text }; - if (auto node = parser.parse()) - return node.release_nonnull(); - - return ::Shell::AST::make_ref_counted<::Shell::AST::SyntaxError>(::Shell::AST::Position {}, "Unable to parse file"_string); -} - -size_t ShellComprehensionEngine::resolve(ShellComprehensionEngine::DocumentData const& document, const GUI::TextPosition& position) -{ - size_t offset = 0; - - if (position.line() > 0) { - auto first = true; - size_t line = 0; - for (auto& line_view : document.text.split_limit('\n', position.line() + 1, SplitBehavior::KeepEmpty)) { - if (line == position.line()) - break; - if (first) - first = false; - else - ++offset; // For the newline. - offset += line_view.length(); - ++line; - } - } - - offset += position.column() + 1; - return offset; -} - -Vector ShellComprehensionEngine::get_suggestions(ByteString const& file, const GUI::TextPosition& position) -{ - dbgln_if(SH_LANGUAGE_SERVER_DEBUG, "ShellComprehensionEngine position {}:{}", position.line(), position.column()); - - auto const& document = get_or_create_document_data(file); - size_t offset_in_file = resolve(document, position); - - ::Shell::AST::HitTestResult hit_test = document.node->hit_test_position(offset_in_file); - if (!hit_test.matching_node) { - dbgln_if(SH_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", position.line(), position.column()); - return {}; - } - - auto completions = const_cast<::Shell::AST::Node*>(document.node.ptr())->complete_for_editor(shell(), offset_in_file, hit_test).release_value_but_fixme_should_propagate_errors(); - Vector entries; - for (auto& completion : completions) - entries.append({ completion.text_string(), completion.input_offset }); - - return entries; -} - -void ShellComprehensionEngine::on_edit(ByteString const& file) -{ - set_document_data(file, create_document_data_for(file)); -} - -void ShellComprehensionEngine::file_opened([[maybe_unused]] ByteString const& file) -{ - set_document_data(file, create_document_data_for(file)); -} - -Optional ShellComprehensionEngine::find_declaration_of(ByteString const& filename, const GUI::TextPosition& identifier_position) -{ - dbgln_if(SH_LANGUAGE_SERVER_DEBUG, "find_declaration_of({}, {}:{})", filename, identifier_position.line(), identifier_position.column()); - auto const& document = get_or_create_document_data(filename); - auto position = resolve(document, identifier_position); - auto result = document.node->hit_test_position(position); - if (!result.matching_node) { - dbgln_if(SH_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", identifier_position.line(), identifier_position.column()); - return {}; - } - - if (!result.matching_node->is_bareword()) { - dbgln_if(SH_LANGUAGE_SERVER_DEBUG, "no bareword at position {}:{}", identifier_position.line(), identifier_position.column()); - return {}; - } - - auto name = static_ptr_cast<::Shell::AST::BarewordLiteral const>(result.matching_node)->text(); - auto& declarations = all_declarations(); - for (auto& entry : declarations) { - for (auto& declaration : entry.value) { - if (declaration.name.view() == name) - return declaration.position; - } - } - - return {}; -} - -void ShellComprehensionEngine::update_declared_symbols(DocumentData const& document) -{ - struct Visitor : public ::Shell::AST::NodeVisitor { - explicit Visitor(ByteString const& filename) - : filename(filename) - { - } - - void visit(::Shell::AST::VariableDeclarations const* node) override - { - for (auto& entry : node->variables()) { - auto literal = entry.name->leftmost_trivial_literal(); - if (!literal) - continue; - - ByteString name; - if (literal->is_bareword()) - name = static_ptr_cast<::Shell::AST::BarewordLiteral const>(literal)->text().to_byte_string(); - - if (!name.is_empty()) { - dbgln("Found variable {}", name); - declarations.append({ move(name), { filename, entry.name->position().start_line.line_number, entry.name->position().start_line.line_column }, CodeComprehension::DeclarationType::Variable, {} }); - } - } - ::Shell::AST::NodeVisitor::visit(node); - } - - void visit(::Shell::AST::FunctionDeclaration const* node) override - { - dbgln("Found function {}", node->name().name); - declarations.append({ node->name().name.to_byte_string(), { filename, node->position().start_line.line_number, node->position().start_line.line_column }, CodeComprehension::DeclarationType::Function, {} }); - } - - ByteString const& filename; - Vector declarations; - } visitor { document.filename }; - - document.node->visit(visitor); - - set_declarations_of_document(document.filename, move(visitor.declarations)); -} -} diff --git a/Userland/Libraries/LibCodeComprehension/Shell/ShellComprehensionEngine.h b/Userland/Libraries/LibCodeComprehension/Shell/ShellComprehensionEngine.h deleted file mode 100644 index 9de44b24cd8..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Shell/ShellComprehensionEngine.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace CodeComprehension::Shell { - -class ShellComprehensionEngine : public CodeComprehensionEngine { -public: - ShellComprehensionEngine(FileDB const& filedb); - virtual Vector get_suggestions(ByteString const& file, const GUI::TextPosition& position) override; - virtual void on_edit(ByteString const& file) override; - virtual void file_opened([[maybe_unused]] ByteString const& file) override; - virtual Optional find_declaration_of(ByteString const& filename, const GUI::TextPosition& identifier_position) override; - -private: - struct DocumentData { - DocumentData(ByteString&& text, ByteString filename); - ByteString filename; - ByteString text; - NonnullRefPtr<::Shell::AST::Node> node; - - Vector const& sourced_paths() const; - - private: - NonnullRefPtr<::Shell::AST::Node> parse() const; - - mutable Optional> all_sourced_paths {}; - }; - - DocumentData const& get_document_data(ByteString const& file) const; - DocumentData const& get_or_create_document_data(ByteString const& file); - void set_document_data(ByteString const& file, OwnPtr&& data); - - OwnPtr create_document_data_for(ByteString const& file); - void update_declared_symbols(DocumentData const&); - - static size_t resolve(ShellComprehensionEngine::DocumentData const& document, const GUI::TextPosition& position); - - ::Shell::Shell& shell() - { - if (s_shell) - return *s_shell; - s_shell = ::Shell::Shell::construct(); - return *s_shell; - } - - HashMap> m_documents; - static RefPtr<::Shell::Shell> s_shell; -}; -} diff --git a/Userland/Libraries/LibCodeComprehension/Shell/main.cpp b/Userland/Libraries/LibCodeComprehension/Shell/main.cpp deleted file mode 100644 index 5281db9f3e5..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Shell/main.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "ConnectionFromClient.h" -#include -#include -#include -#include -#include - -ErrorOr serenity_main(Main::Arguments) -{ - Core::EventLoop event_loop; - TRY(Core::System::pledge("stdio unix rpath recvfd")); - - auto client = TRY(IPC::take_over_accepted_client_from_system_server()); - - TRY(Core::System::pledge("stdio rpath recvfd")); - TRY(Core::System::unveil("/etc/passwd", "r")); - - return event_loop.exec(); -} diff --git a/Userland/Libraries/LibCodeComprehension/Types.h b/Userland/Libraries/LibCodeComprehension/Types.h deleted file mode 100644 index 68ee592a675..00000000000 --- a/Userland/Libraries/LibCodeComprehension/Types.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2022, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace CodeComprehension { - -enum class Language { - Unspecified, - Cpp, -}; - -struct AutocompleteResultEntry { - ByteString completion; - size_t partial_input_length { 0 }; - // TODO: Actually assign the value of this field in more places (when applicable). - Language language { Language::Unspecified }; - ByteString display_text {}; - - enum class HideAutocompleteAfterApplying { - No, - Yes, - }; - HideAutocompleteAfterApplying hide_autocomplete_after_applying { HideAutocompleteAfterApplying::Yes }; -}; - -struct ProjectLocation { - ByteString file; - size_t line { 0 }; - size_t column { 0 }; - - bool operator==(ProjectLocation const& other) const - { - return file == other.file && line == other.line && column == other.column; - } -}; - -enum class DeclarationType { - Function, - Struct, - Class, - Variable, - PreprocessorDefinition, - Namespace, - Member, -}; - -struct Declaration { - ByteString name; - ProjectLocation position; - DeclarationType type; - ByteString scope; - - bool operator==(Declaration const& other) const - { - return name == other.name && position == other.position && type == other.type && scope == other.scope; - } -}; - -#define FOR_EACH_SEMANTIC_TYPE \ - __SEMANTIC(Unknown) \ - __SEMANTIC(Regular) \ - __SEMANTIC(Keyword) \ - __SEMANTIC(Type) \ - __SEMANTIC(Identifier) \ - __SEMANTIC(String) \ - __SEMANTIC(Number) \ - __SEMANTIC(IncludePath) \ - __SEMANTIC(PreprocessorStatement) \ - __SEMANTIC(Comment) \ - __SEMANTIC(Whitespace) \ - __SEMANTIC(Function) \ - __SEMANTIC(Variable) \ - __SEMANTIC(CustomType) \ - __SEMANTIC(Namespace) \ - __SEMANTIC(Member) \ - __SEMANTIC(Parameter) \ - __SEMANTIC(PreprocessorMacro) - -struct TokenInfo { - - enum class SemanticType : u32 { -#define __SEMANTIC(x) x, - FOR_EACH_SEMANTIC_TYPE -#undef __SEMANTIC - - } type { SemanticType::Unknown }; - size_t start_line { 0 }; - size_t start_column { 0 }; - size_t end_line { 0 }; - size_t end_column { 0 }; - - static constexpr char const* type_to_string(SemanticType t) - { - switch (t) { -#define __SEMANTIC(x) \ - case SemanticType::x: \ - return #x; - FOR_EACH_SEMANTIC_TYPE -#undef __SEMANTIC - } - VERIFY_NOT_REACHED(); - } -}; - -struct TodoEntry { - ByteString content; - ByteString filename; - size_t line { 0 }; - size_t column { 0 }; -}; - -} diff --git a/Userland/Libraries/LibCpp/AST.cpp b/Userland/Libraries/LibCpp/AST.cpp deleted file mode 100644 index 14a7e0f1ea7..00000000000 --- a/Userland/Libraries/LibCpp/AST.cpp +++ /dev/null @@ -1,695 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "AST.h" - -namespace Cpp { - -static void print_indent(FILE* output, int indent) -{ - for (int i = 0; i < indent * 2; ++i) - out(output, " "); -} - -void ASTNode::dump(FILE* output, size_t indent) const -{ - print_indent(output, indent); - outln(output, "{}[{}:{}->{}:{}]", class_name(), start().line, start().column, end().line, end().column); -} - -void TranslationUnit::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - for (auto const& child : m_declarations) { - child->dump(output, indent + 1); - } -} - -void FunctionDeclaration::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - - ByteString qualifiers_string; - if (!m_qualifiers.is_empty()) { - print_indent(output, indent + 1); - outln(output, "[{}]", ByteString::join(' ', m_qualifiers)); - } - - m_return_type->dump(output, indent + 1); - if (!m_name.is_null()) { - print_indent(output, indent + 1); - outln(output, "{}", m_name->full_name()); - } - print_indent(output, indent + 1); - outln(output, "("); - for (auto const& arg : m_parameters) { - arg->dump(output, indent + 1); - } - print_indent(output, indent + 1); - outln(output, ")"); - if (!m_definition.is_null()) { - m_definition->dump(output, indent + 1); - } -} - -Vector> FunctionDeclaration::declarations() const -{ - Vector> declarations; - for (auto& arg : m_parameters) { - declarations.append(arg); - } - - if (m_definition) - declarations.extend(m_definition->declarations()); - - return declarations; -} - -void Type::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent + 1); - outln(output, "{}", to_byte_string()); -} - -ByteString NamedType::to_byte_string() const -{ - ByteString qualifiers_string; - if (!qualifiers().is_empty()) - qualifiers_string = ByteString::formatted("[{}] ", ByteString::join(' ', qualifiers())); - - ByteString name; - if (is_auto()) - name = "auto"; - else - name = m_name.is_null() ? ""sv : m_name->full_name(); - - return ByteString::formatted("{}{}", qualifiers_string, name); -} - -ByteString Pointer::to_byte_string() const -{ - if (!m_pointee) - return {}; - StringBuilder builder; - builder.append(m_pointee->to_byte_string()); - builder.append('*'); - return builder.to_byte_string(); -} - -ByteString Reference::to_byte_string() const -{ - if (!m_referenced_type) - return {}; - StringBuilder builder; - builder.append(m_referenced_type->to_byte_string()); - if (m_kind == Kind::Lvalue) - builder.append('&'); - else - builder.append("&&"sv); - return builder.to_byte_string(); -} - -ByteString FunctionType::to_byte_string() const -{ - StringBuilder builder; - builder.append(m_return_type->to_byte_string()); - builder.append('('); - bool first = true; - for (auto& parameter : m_parameters) { - if (first) - first = false; - else - builder.append(", "sv); - if (parameter->type()) - builder.append(parameter->type()->to_byte_string()); - if (parameter->name() && !parameter->full_name().is_empty()) { - builder.append(' '); - builder.append(parameter->full_name()); - } - } - builder.append(')'); - return builder.to_byte_string(); -} - -void Parameter::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - if (m_is_ellipsis) { - print_indent(output, indent + 1); - outln(output, "..."); - } - if (!m_name.is_null()) { - print_indent(output, indent); - outln(output, "{}", m_name->full_name()); - } - if (m_type) - m_type->dump(output, indent + 1); -} - -void FunctionDefinition::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent); - outln(output, "{{"); - for (auto const& statement : m_statements) { - statement->dump(output, indent + 1); - } - print_indent(output, indent); - outln(output, "}}"); -} - -Vector> FunctionDefinition::declarations() const -{ - Vector> declarations; - for (auto& statement : m_statements) { - declarations.extend(statement->declarations()); - } - return declarations; -} - -void VariableDeclaration::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - if (m_type) - m_type->dump(output, indent + 1); - print_indent(output, indent + 1); - outln(output, "{}", full_name()); - if (m_initial_value) - m_initial_value->dump(output, indent + 1); -} - -void Identifier::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent); - outln(output, "{}", m_name); -} - -void NumericLiteral::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent); - outln(output, "{}", m_value); -} - -void BinaryExpression::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - - char const* op_string = nullptr; - switch (m_op) { - case BinaryOp::Addition: - op_string = "+"; - break; - case BinaryOp::Subtraction: - op_string = "-"; - break; - case BinaryOp::Multiplication: - op_string = "*"; - break; - case BinaryOp::Division: - op_string = "/"; - break; - case BinaryOp::Modulo: - op_string = "%"; - break; - case BinaryOp::GreaterThan: - op_string = ">"; - break; - case BinaryOp::GreaterThanEquals: - op_string = ">="; - break; - case BinaryOp::LessThan: - op_string = "<"; - break; - case BinaryOp::LessThanEquals: - op_string = "<="; - break; - case BinaryOp::BitwiseAnd: - op_string = "&"; - break; - case BinaryOp::BitwiseOr: - op_string = "|"; - break; - case BinaryOp::BitwiseXor: - op_string = "^"; - break; - case BinaryOp::LeftShift: - op_string = "<<"; - break; - case BinaryOp::RightShift: - op_string = ">>"; - break; - case BinaryOp::EqualsEquals: - op_string = "=="; - break; - case BinaryOp::NotEqual: - op_string = "!="; - break; - case BinaryOp::LogicalOr: - op_string = "||"; - break; - case BinaryOp::LogicalAnd: - op_string = "&&"; - break; - case BinaryOp::Arrow: - op_string = "->"; - break; - } - - m_lhs->dump(output, indent + 1); - print_indent(output, indent + 1); - VERIFY(op_string); - outln(output, "{}", op_string); - m_rhs->dump(output, indent + 1); -} - -void AssignmentExpression::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - - char const* op_string = nullptr; - switch (m_op) { - case AssignmentOp::Assignment: - op_string = "="; - break; - case AssignmentOp::AdditionAssignment: - op_string = "+="; - break; - case AssignmentOp::SubtractionAssignment: - op_string = "-="; - break; - } - - m_lhs->dump(output, indent + 1); - print_indent(output, indent + 1); - VERIFY(op_string); - outln(output, "{}", op_string); - m_rhs->dump(output, indent + 1); -} - -void FunctionCall::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - m_callee->dump(output, indent + 1); - for (auto const& arg : m_arguments) { - arg->dump(output, indent + 1); - } -} - -void StringLiteral::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent + 1); - outln(output, "{}", m_value); -} - -void ReturnStatement::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - if (m_value) - m_value->dump(output, indent + 1); -} - -void EnumDeclaration::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent); - outln(output, "{}", full_name()); - for (auto& entry : m_entries) { - print_indent(output, indent + 1); - outln(output, "{}", entry.name); - if (entry.value) - entry.value->dump(output, indent + 2); - } -} - -void StructOrClassDeclaration::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent); - outln(output, "{}", full_name()); - if (!m_baseclasses.is_empty()) { - print_indent(output, indent + 1); - outln(output, ":"); - for (size_t i = 0; i < m_baseclasses.size(); ++i) { - auto& baseclass = m_baseclasses[i]; - baseclass->dump(output, indent + 1); - if (i < m_baseclasses.size() - 1) { - print_indent(output, indent + 1); - outln(output, ","); - } - } - } - outln(output, ""); - for (auto& member : m_members) { - member->dump(output, indent + 1); - } -} -Vector> StructOrClassDeclaration::declarations() const -{ - Vector> declarations; - for (auto& member : m_members) - declarations.append(member); - return declarations; -} - -void UnaryExpression::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - - char const* op_string = nullptr; - switch (m_op) { - case UnaryOp::BitwiseNot: - op_string = "~"; - break; - case UnaryOp::Not: - op_string = "!"; - break; - case UnaryOp::Plus: - op_string = "+"; - break; - case UnaryOp::Minus: - op_string = "-"; - break; - case UnaryOp::PlusPlus: - op_string = "++"; - break; - case UnaryOp::Address: - op_string = "&"; - break; - default: - op_string = ""; - } - - VERIFY(op_string); - print_indent(output, indent + 1); - outln(output, "{}", op_string); - m_lhs->dump(output, indent + 1); -} - -void BooleanLiteral::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent + 1); - outln(output, "{}", m_value ? "true" : "false"); -} - -void Pointer::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - if (!m_pointee.is_null()) { - m_pointee->dump(output, indent + 1); - } -} - -void Reference::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent + 1); - outln(output, "{}", m_kind == Kind::Lvalue ? "&" : "&&"); - if (!m_referenced_type.is_null()) { - m_referenced_type->dump(output, indent + 1); - } -} - -void FunctionType::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - if (m_return_type) - m_return_type->dump(output, indent + 1); - print_indent(output, indent + 1); - outln("("); - for (auto& parameter : m_parameters) - parameter->dump(output, indent + 2); - print_indent(output, indent + 1); - outln(")"); -} - -void MemberExpression::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - m_object->dump(output, indent + 1); - m_property->dump(output, indent + 1); -} - -void BlockStatement::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - for (auto& statement : m_statements) { - statement->dump(output, indent + 1); - } -} - -void ForStatement::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - if (m_init) - m_init->dump(output, indent + 1); - if (m_test) - m_test->dump(output, indent + 1); - if (m_update) - m_update->dump(output, indent + 1); - if (m_body) - m_body->dump(output, indent + 1); -} - -Vector> Statement::declarations() const -{ - if (is_declaration()) { - Vector> vec; - auto const& decl = static_cast(*this); - vec.empend(const_cast(decl)); - return vec; - } - return {}; -} - -Vector> ForStatement::declarations() const -{ - Vector> declarations; - if (m_init) - declarations.extend(m_init->declarations()); - if (m_body) - declarations.extend(m_body->declarations()); - return declarations; -} - -Vector> BlockStatement::declarations() const -{ - Vector> declarations; - for (auto& statement : m_statements) { - declarations.extend(statement->declarations()); - } - return declarations; -} - -void IfStatement::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - if (m_predicate) { - print_indent(output, indent + 1); - outln(output, "Predicate:"); - m_predicate->dump(output, indent + 1); - } - if (m_then) { - print_indent(output, indent + 1); - outln(output, "Then:"); - m_then->dump(output, indent + 1); - } - if (m_else) { - print_indent(output, indent + 1); - outln(output, "Else:"); - m_else->dump(output, indent + 1); - } -} - -Vector> IfStatement::declarations() const -{ - Vector> declarations; - if (m_predicate) - declarations.extend(m_predicate->declarations()); - if (m_then) - declarations.extend(m_then->declarations()); - if (m_else) - declarations.extend(m_else->declarations()); - return declarations; -} - -void NamespaceDeclaration::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent + 1); - outln(output, "{}", full_name()); - for (auto& decl : m_declarations) - decl->dump(output, indent + 1); -} - -void NullPointerLiteral::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); -} - -void Name::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent); - outln(output, "{}", full_name()); -} - -StringView Name::full_name() const -{ - if (m_full_name.has_value()) - return *m_full_name; - - StringBuilder builder; - if (!m_scope.is_empty()) { - for (auto& scope : m_scope) { - builder.appendff("{}::", scope->name()); - } - } - m_full_name = ByteString::formatted("{}{}", builder.to_byte_string(), m_name.is_null() ? ""sv : m_name->name()); - return *m_full_name; -} - -StringView TemplatizedName::full_name() const -{ - if (m_full_name.has_value()) - return *m_full_name; - - StringBuilder name; - name.append(Name::full_name()); - name.append('<'); - for (auto& type : m_template_arguments) { - name.append(type->to_byte_string()); - } - name.append('>'); - m_full_name = name.to_byte_string(); - return *m_full_name; -} - -void SizedName::dump(FILE* output, size_t indent) const -{ - Name::dump(output, indent); - print_indent(output, indent + 1); - - StringBuilder dimension_info; - for (auto const& dim : m_dimensions) { - dimension_info.append('['); - dimension_info.append(dim); - dimension_info.append(']'); - } - - if (dimension_info.is_empty()) { - dimension_info.append("[]"sv); - } - outln(output, "{}", dimension_info.to_byte_string()); -} - -void CppCastExpression::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - - print_indent(output, indent); - outln(output, "{}", m_cast_type); - - print_indent(output, indent + 1); - outln(output, "<"); - if (m_type) - m_type->dump(output, indent + 1); - print_indent(output, indent + 1); - outln(output, ">"); - - if (m_expression) - m_expression->dump(output, indent + 1); -} - -void SizeofExpression::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - if (m_type) - m_type->dump(output, indent + 1); -} - -void BracedInitList::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - for (auto& exp : m_expressions) { - exp->dump(output, indent + 1); - } -} - -void CStyleCastExpression::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - if (m_type) - m_type->dump(output, indent + 1); - if (m_expression) - m_expression->dump(output, indent + 1); -} - -void Constructor::dump(FILE* output, size_t indent) const -{ - print_indent(output, indent); - outln(output, "C'tor"); - print_indent(output, indent + 1); - outln(output, "("); - for (auto const& arg : parameters()) { - arg->dump(output, indent + 1); - } - print_indent(output, indent + 1); - outln(output, ")"); - if (definition()) { - definition()->dump(output, indent + 1); - } -} - -void Destructor::dump(FILE* output, size_t indent) const -{ - print_indent(output, indent); - outln(output, "D'tor"); - print_indent(output, indent + 1); - outln(output, "("); - for (auto const& arg : parameters()) { - arg->dump(output, indent + 1); - } - print_indent(output, indent + 1); - outln(output, ")"); - if (definition()) { - definition()->dump(output, indent + 1); - } -} - -StringView Declaration::full_name() const -{ - if (!m_full_name.has_value()) { - if (m_name) - m_full_name = m_name->full_name(); - else - m_full_name = ByteString::empty(); - } - - return *m_full_name; -} - -void UsingNamespaceDeclaration::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent + 1); - outln(output, "{}", full_name()); -} - -void TypedefDeclaration::dump(FILE* output, size_t indent) const -{ - ASTNode::dump(output, indent); - print_indent(output, indent + 1); - outln(output, "{}", full_name()); - if (m_alias) - m_alias->dump(output, indent + 1); -} - -} diff --git a/Userland/Libraries/LibCpp/AST.h b/Userland/Libraries/LibCpp/AST.h deleted file mode 100644 index 9b354b353c8..00000000000 --- a/Userland/Libraries/LibCpp/AST.h +++ /dev/null @@ -1,1067 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Cpp { - -class ASTNode; -class TranslationUnit; -class Declaration; -class FunctionDefinition; -class Type; -class Parameter; -class Statement; -class Name; - -class ASTNode : public RefCounted { -public: - virtual ~ASTNode() = default; - virtual StringView class_name() const = 0; - virtual void dump(FILE* = stdout, size_t indent = 0) const; - - template - bool fast_is() const = delete; - - ASTNode const* parent() const { return m_parent; } - Position start() const - { - VERIFY(m_start.has_value()); - return m_start.value(); - } - Position end() const - { - VERIFY(m_end.has_value()); - return m_end.value(); - } - DeprecatedFlyString const& filename() const - { - return m_filename; - } - void set_end(Position const& end) { m_end = end; } - void set_parent(ASTNode const& parent) { m_parent = &parent; } - - virtual Vector> declarations() const { return {}; } - - virtual bool is_identifier() const { return false; } - virtual bool is_member_expression() const { return false; } - virtual bool is_variable_or_parameter_declaration() const { return false; } - virtual bool is_function_call() const { return false; } - virtual bool is_type() const { return false; } - virtual bool is_declaration() const { return false; } - virtual bool is_name() const { return false; } - virtual bool is_dummy_node() const { return false; } - -protected: - ASTNode(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : m_parent(parent) - , m_start(start) - , m_end(end) - , m_filename(filename) - { - } - -private: - ASTNode const* m_parent { nullptr }; - Optional m_start; - Optional m_end; - DeprecatedFlyString m_filename; -}; - -class TranslationUnit : public ASTNode { - -public: - virtual ~TranslationUnit() override = default; - virtual StringView class_name() const override { return "TranslationUnit"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual Vector> declarations() const override { return m_declarations; } - - TranslationUnit(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : ASTNode(parent, start, end, filename) - { - } - - void set_declarations(Vector>&& declarations) { m_declarations = move(declarations); } - -private: - Vector> m_declarations; -}; - -class Statement : public ASTNode { -public: - virtual ~Statement() override = default; - virtual StringView class_name() const override { return "Statement"sv; } - - virtual Vector> declarations() const override; - -protected: - Statement(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : ASTNode(parent, start, end, filename) - { - } -}; - -class Declaration : public Statement { - -public: - virtual bool is_declaration() const override { return true; } - virtual bool is_variable_declaration() const { return false; } - virtual bool is_parameter() const { return false; } - virtual bool is_struct_or_class() const { return false; } - virtual bool is_struct() const { return false; } - virtual bool is_class() const { return false; } - virtual bool is_function() const { return false; } - virtual bool is_namespace() const { return false; } - virtual bool is_enum() const { return false; } - bool is_member() const { return parent() != nullptr && parent()->is_declaration() && verify_cast(parent())->is_struct_or_class(); } - Name const* name() const { return m_name; } - StringView full_name() const; - void set_name(RefPtr name) { m_name = move(name); } - -protected: - Declaration(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Statement(parent, start, end, filename) - { - } - - RefPtr m_name; - mutable Optional m_full_name; -}; - -class InvalidDeclaration : public Declaration { - -public: - virtual ~InvalidDeclaration() override = default; - virtual StringView class_name() const override { return "InvalidDeclaration"sv; } - InvalidDeclaration(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Declaration(parent, start, end, filename) - { - } -}; - -class FunctionDeclaration : public Declaration { -public: - virtual ~FunctionDeclaration() override = default; - virtual StringView class_name() const override { return "FunctionDeclaration"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual bool is_function() const override { return true; } - virtual bool is_constructor() const { return false; } - virtual bool is_destructor() const { return false; } - RefPtr definition() { return m_definition; } - - FunctionDeclaration(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Declaration(parent, start, end, filename) - { - } - - virtual Vector> declarations() const override; - Vector const& qualifiers() const { return m_qualifiers; } - void set_qualifiers(Vector const& qualifiers) { m_qualifiers = qualifiers; } - Type const* return_type() const { return m_return_type.ptr(); } - void set_return_type(RefPtr const& return_type) { m_return_type = return_type; } - Vector> const& parameters() const { return m_parameters; } - void set_parameters(Vector> const& parameters) { m_parameters = parameters; } - FunctionDefinition const* definition() const { return m_definition.ptr(); } - void set_definition(RefPtr&& definition) { m_definition = move(definition); } - -private: - Vector m_qualifiers; - RefPtr m_return_type; - Vector> m_parameters; - RefPtr m_definition; -}; - -class VariableOrParameterDeclaration : public Declaration { -public: - virtual ~VariableOrParameterDeclaration() override = default; - virtual bool is_variable_or_parameter_declaration() const override { return true; } - - void set_type(RefPtr&& type) { m_type = move(type); } - Type const* type() const { return m_type.ptr(); } - -protected: - VariableOrParameterDeclaration(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Declaration(parent, start, end, filename) - { - } - - RefPtr m_type; -}; - -class Parameter : public VariableOrParameterDeclaration { -public: - virtual ~Parameter() override = default; - virtual StringView class_name() const override { return "Parameter"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual bool is_parameter() const override { return true; } - - Parameter(ASTNode const* parent, Optional start, Optional end, ByteString const& filename, RefPtr name) - : VariableOrParameterDeclaration(parent, start, end, filename) - { - m_name = name; - } - - bool is_ellipsis() const { return m_is_ellipsis; } - void set_ellipsis(bool is_ellipsis) { m_is_ellipsis = is_ellipsis; } - -private: - bool m_is_ellipsis { false }; -}; - -class Type : public ASTNode { -public: - virtual ~Type() override = default; - virtual StringView class_name() const override { return "Type"sv; } - virtual bool is_type() const override { return true; } - virtual bool is_templatized() const { return false; } - virtual bool is_named_type() const { return false; } - virtual ByteString to_byte_string() const = 0; - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - bool is_auto() const { return m_is_auto; } - void set_auto(bool is_auto) { m_is_auto = is_auto; } - Vector const& qualifiers() const { return m_qualifiers; } - void set_qualifiers(Vector&& qualifiers) { m_qualifiers = move(qualifiers); } - -protected: - Type(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : ASTNode(parent, start, end, filename) - { - } - -private: - bool m_is_auto { false }; - Vector m_qualifiers; -}; - -class NamedType : public Type { -public: - virtual ~NamedType() override = default; - virtual StringView class_name() const override { return "NamedType"sv; } - virtual ByteString to_byte_string() const override; - virtual bool is_named_type() const override { return true; } - - NamedType(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Type(parent, start, end, filename) - { - } - - Name const* name() const { return m_name.ptr(); } - void set_name(RefPtr&& name) { m_name = move(name); } - -private: - RefPtr m_name; -}; - -class Pointer : public Type { -public: - virtual ~Pointer() override = default; - virtual StringView class_name() const override { return "Pointer"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual ByteString to_byte_string() const override; - - Pointer(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Type(parent, start, end, filename) - { - } - - Type const* pointee() const { return m_pointee.ptr(); } - void set_pointee(RefPtr&& pointee) { m_pointee = move(pointee); } - -private: - RefPtr m_pointee; -}; - -class Reference : public Type { -public: - virtual ~Reference() override = default; - virtual StringView class_name() const override { return "Reference"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual ByteString to_byte_string() const override; - - enum class Kind { - Lvalue, - Rvalue, - }; - - Reference(ASTNode const* parent, Optional start, Optional end, ByteString const& filename, Kind kind) - : Type(parent, start, end, filename) - , m_kind(kind) - { - } - - Type const* referenced_type() const { return m_referenced_type.ptr(); } - void set_referenced_type(RefPtr&& pointee) { m_referenced_type = move(pointee); } - Kind kind() const { return m_kind; } - -private: - RefPtr m_referenced_type; - Kind m_kind; -}; - -class FunctionType : public Type { -public: - virtual ~FunctionType() override = default; - virtual StringView class_name() const override { return "FunctionType"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual ByteString to_byte_string() const override; - - FunctionType(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Type(parent, start, end, filename) - { - } - - void set_return_type(Type& type) { m_return_type = type; } - void set_parameters(Vector> parameters) { m_parameters = move(parameters); } - -private: - RefPtr m_return_type; - Vector> m_parameters; -}; - -class FunctionDefinition : public ASTNode { -public: - virtual ~FunctionDefinition() override = default; - virtual StringView class_name() const override { return "FunctionDefinition"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - FunctionDefinition(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : ASTNode(parent, start, end, filename) - { - } - - virtual Vector> declarations() const override; - Vector> const& statements() const { return m_statements; } - void add_statement(NonnullRefPtr&& statement) { m_statements.append(move(statement)); } - -private: - Vector> m_statements; -}; - -class InvalidStatement : public Statement { -public: - virtual ~InvalidStatement() override = default; - virtual StringView class_name() const override { return "InvalidStatement"sv; } - InvalidStatement(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Statement(parent, start, end, filename) - { - } -}; - -class Expression : public Statement { -public: - virtual ~Expression() override = default; - virtual StringView class_name() const override { return "Expression"sv; } - -protected: - Expression(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Statement(parent, start, end, filename) - { - } -}; - -class InvalidExpression : public Expression { -public: - virtual ~InvalidExpression() override = default; - virtual StringView class_name() const override { return "InvalidExpression"sv; } - InvalidExpression(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } -}; - -class VariableDeclaration : public VariableOrParameterDeclaration { -public: - virtual ~VariableDeclaration() override = default; - virtual StringView class_name() const override { return "VariableDeclaration"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - VariableDeclaration(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : VariableOrParameterDeclaration(parent, start, end, filename) - { - } - - virtual bool is_variable_declaration() const override { return true; } - - Expression const* initial_value() const { return m_initial_value; } - void set_initial_value(RefPtr&& initial_value) { m_initial_value = move(initial_value); } - -private: - RefPtr m_initial_value; -}; - -class Identifier : public Expression { -public: - virtual ~Identifier() override = default; - virtual StringView class_name() const override { return "Identifier"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - Identifier(ASTNode const* parent, Optional start, Optional end, ByteString const& filename, StringView name) - : Expression(parent, start, end, filename) - , m_name(name) - { - } - Identifier(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Identifier(parent, start, end, filename, {}) - { - } - - virtual bool is_identifier() const override { return true; } - - StringView name() const { return m_name; } - void set_name(StringView&& name) { m_name = move(name); } - -private: - StringView m_name; -}; - -class Name : public Expression { -public: - virtual ~Name() override = default; - virtual StringView class_name() const override { return "Name"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual bool is_name() const override { return true; } - virtual bool is_templatized() const { return false; } - virtual bool is_sized() const { return false; } - - Name(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } - virtual StringView full_name() const; - - Identifier const* name() const { return m_name.ptr(); } - void set_name(RefPtr&& name) { m_name = move(name); } - Vector> const& scope() const { return m_scope; } - void set_scope(Vector> scope) { m_scope = move(scope); } - void add_to_scope(NonnullRefPtr&& part) { m_scope.append(move(part)); } - -private: - RefPtr m_name; - Vector> m_scope; - mutable Optional m_full_name; -}; - -class SizedName : public Name { -public: - virtual ~SizedName() override = default; - virtual StringView class_name() const override { return "SizedName"sv; } - virtual bool is_sized() const override { return true; } - void dump(FILE* output, size_t indent) const override; - - SizedName(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Name(parent, start, end, filename) - { - } - - void append_dimension(StringView dim) { m_dimensions.append(dim); } - -private: - Vector m_dimensions; - mutable Optional m_full_name; -}; - -class TemplatizedName : public Name { -public: - virtual ~TemplatizedName() override = default; - virtual StringView class_name() const override { return "TemplatizedName"sv; } - virtual bool is_templatized() const override { return true; } - virtual StringView full_name() const override; - - TemplatizedName(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Name(parent, start, end, filename) - { - } - - void add_template_argument(NonnullRefPtr&& type) { m_template_arguments.append(move(type)); } - -private: - Vector> m_template_arguments; - mutable Optional m_full_name; -}; - -class NumericLiteral : public Expression { -public: - virtual ~NumericLiteral() override = default; - virtual StringView class_name() const override { return "NumericLiteral"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - NumericLiteral(ASTNode const* parent, Optional start, Optional end, ByteString const& filename, StringView value) - : Expression(parent, start, end, filename) - , m_value(value) - { - } - - StringView value() const { return m_value; } - -private: - StringView m_value; -}; - -class NullPointerLiteral : public Expression { -public: - virtual ~NullPointerLiteral() override = default; - virtual StringView class_name() const override { return "NullPointerLiteral"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - NullPointerLiteral(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } -}; - -class BooleanLiteral : public Expression { -public: - virtual ~BooleanLiteral() override = default; - virtual StringView class_name() const override { return "BooleanLiteral"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - BooleanLiteral(ASTNode const* parent, Optional start, Optional end, ByteString const& filename, bool value) - : Expression(parent, start, end, filename) - , m_value(value) - { - } - -private: - bool m_value; -}; - -enum class BinaryOp { - Addition, - Subtraction, - Multiplication, - Division, - Modulo, - GreaterThan, - GreaterThanEquals, - LessThan, - LessThanEquals, - BitwiseAnd, - BitwiseOr, - BitwiseXor, - LeftShift, - RightShift, - EqualsEquals, - NotEqual, - LogicalOr, - LogicalAnd, - Arrow, -}; - -class BinaryExpression : public Expression { -public: - BinaryExpression(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~BinaryExpression() override = default; - virtual StringView class_name() const override { return "BinaryExpression"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - BinaryOp op() const { return m_op; } - void set_op(BinaryOp op) { m_op = op; } - Expression const* lhs() const { return m_lhs.ptr(); } - void set_lhs(RefPtr&& e) { m_lhs = move(e); } - Expression const* rhs() const { return m_rhs.ptr(); } - void set_rhs(RefPtr&& e) { m_rhs = move(e); } - -private: - BinaryOp m_op; - RefPtr m_lhs; - RefPtr m_rhs; -}; - -enum class AssignmentOp { - Assignment, - AdditionAssignment, - SubtractionAssignment, -}; - -class AssignmentExpression : public Expression { -public: - AssignmentExpression(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~AssignmentExpression() override = default; - virtual StringView class_name() const override { return "AssignmentExpression"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - AssignmentOp op() const { return m_op; } - void set_op(AssignmentOp op) { m_op = op; } - Expression const* lhs() const { return m_lhs; } - void set_lhs(RefPtr&& e) { m_lhs = move(e); } - Expression const* rhs() const { return m_rhs; } - void set_rhs(RefPtr&& e) { m_rhs = move(e); } - -private: - AssignmentOp m_op {}; - RefPtr m_lhs; - RefPtr m_rhs; -}; - -class FunctionCall : public Expression { -public: - FunctionCall(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~FunctionCall() override = default; - virtual StringView class_name() const override { return "FunctionCall"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual bool is_function_call() const override { return true; } - - Expression const* callee() const { return m_callee.ptr(); } - void set_callee(RefPtr&& callee) { m_callee = move(callee); } - - void add_argument(NonnullRefPtr&& arg) { m_arguments.append(move(arg)); } - Vector> const& arguments() const { return m_arguments; } - -private: - RefPtr m_callee; - Vector> m_arguments; -}; - -class StringLiteral final : public Expression { -public: - StringLiteral(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } - - ~StringLiteral() override = default; - virtual StringView class_name() const override { return "StringLiteral"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - ByteString const& value() const { return m_value; } - void set_value(ByteString value) { m_value = move(value); } - -private: - ByteString m_value; -}; - -class ReturnStatement : public Statement { -public: - virtual ~ReturnStatement() override = default; - virtual StringView class_name() const override { return "ReturnStatement"sv; } - - ReturnStatement(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Statement(parent, start, end, filename) - { - } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - Expression const* value() const { return m_value.ptr(); } - void set_value(RefPtr&& value) { m_value = move(value); } - -private: - RefPtr m_value; -}; - -class EnumDeclaration : public Declaration { -public: - virtual ~EnumDeclaration() override = default; - virtual StringView class_name() const override { return "EnumDeclaration"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual bool is_enum() const override { return true; } - - EnumDeclaration(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Declaration(parent, start, end, filename) - { - } - - enum class Type { - RegularEnum, - EnumClass - }; - - void set_type(Type type) { m_type = type; } - void add_entry(StringView entry, RefPtr value = nullptr) { m_entries.append({ entry, move(value) }); } - -private: - Type m_type { Type::RegularEnum }; - struct EnumerationEntry { - StringView name; - RefPtr value; - }; - Vector m_entries; -}; - -class StructOrClassDeclaration : public Declaration { -public: - virtual ~StructOrClassDeclaration() override = default; - virtual StringView class_name() const override { return "StructOrClassDeclaration"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual bool is_struct_or_class() const override { return true; } - virtual bool is_struct() const override { return m_type == Type::Struct; } - virtual bool is_class() const override { return m_type == Type::Class; } - virtual Vector> declarations() const override; - - enum class Type { - Struct, - Class - }; - - StructOrClassDeclaration(ASTNode const* parent, Optional start, Optional end, ByteString const& filename, StructOrClassDeclaration::Type type) - : Declaration(parent, start, end, filename) - , m_type(type) - { - } - - Vector> const& members() const { return m_members; } - void set_members(Vector>&& members) { m_members = move(members); } - - Vector> const& baseclasses() const { return m_baseclasses; } - void set_baseclasses(Vector>&& baseclasses) { m_baseclasses = move(baseclasses); } - -private: - StructOrClassDeclaration::Type m_type; - Vector> m_members; - Vector> m_baseclasses; -}; - -enum class UnaryOp { - Invalid, - BitwiseNot, - Not, - Plus, - Minus, - PlusPlus, - Address, -}; - -class UnaryExpression : public Expression { -public: - UnaryExpression(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~UnaryExpression() override = default; - virtual StringView class_name() const override { return "UnaryExpression"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - void set_op(UnaryOp op) { m_op = op; } - void set_lhs(RefPtr&& e) { m_lhs = move(e); } - -private: - UnaryOp m_op; - RefPtr m_lhs; -}; - -class MemberExpression : public Expression { -public: - MemberExpression(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~MemberExpression() override = default; - virtual StringView class_name() const override { return "MemberExpression"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual bool is_member_expression() const override { return true; } - - Expression const* object() const { return m_object.ptr(); } - void set_object(RefPtr&& object) { m_object = move(object); } - Expression const* property() const { return m_property.ptr(); } - void set_property(RefPtr&& property) { m_property = move(property); } - -private: - RefPtr m_object; - RefPtr m_property; -}; - -class ForStatement : public Statement { -public: - ForStatement(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Statement(parent, start, end, filename) - { - } - - virtual ~ForStatement() override = default; - virtual StringView class_name() const override { return "ForStatement"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - virtual Vector> declarations() const override; - - void set_init(RefPtr&& init) { m_init = move(init); } - void set_test(RefPtr&& test) { m_test = move(test); } - void set_update(RefPtr&& update) { m_update = move(update); } - void set_body(RefPtr&& body) { m_body = move(body); } - Statement const* body() const { return m_body.ptr(); } - -private: - RefPtr m_init; - RefPtr m_test; - RefPtr m_update; - RefPtr m_body; -}; - -class BlockStatement final : public Statement { -public: - BlockStatement(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Statement(parent, start, end, filename) - { - } - - virtual ~BlockStatement() override = default; - virtual StringView class_name() const override { return "BlockStatement"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - virtual Vector> declarations() const override; - - void add_statement(NonnullRefPtr&& statement) { m_statements.append(move(statement)); } - - Vector> const& statements() const { return m_statements; } - -private: - Vector> m_statements; -}; - -class Comment final : public Statement { -public: - Comment(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Statement(parent, start, end, filename) - { - } - - virtual ~Comment() override = default; - virtual StringView class_name() const override { return "Comment"sv; } -}; - -class IfStatement : public Statement { -public: - IfStatement(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Statement(parent, start, end, filename) - { - } - - virtual ~IfStatement() override = default; - virtual StringView class_name() const override { return "IfStatement"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual Vector> declarations() const override; - - void set_predicate(RefPtr&& predicate) { m_predicate = move(predicate); } - void set_then_statement(RefPtr&& then) { m_then = move(then); } - void set_else_statement(RefPtr&& _else) { m_else = move(_else); } - - Expression const* predicate() const { return m_predicate.ptr(); } - Statement const* then_statement() const { return m_then.ptr(); } - Statement const* else_statement() const { return m_else.ptr(); } - -private: - RefPtr m_predicate; - RefPtr m_then; - RefPtr m_else; -}; - -class NamespaceDeclaration : public Declaration { -public: - virtual ~NamespaceDeclaration() override = default; - virtual StringView class_name() const override { return "NamespaceDeclaration"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual bool is_namespace() const override { return true; } - - NamespaceDeclaration(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Declaration(parent, start, end, filename) - { - } - - virtual Vector> declarations() const override { return m_declarations; } - void add_declaration(NonnullRefPtr&& declaration) { m_declarations.append(move(declaration)); } - -private: - Vector> m_declarations; -}; - -class CppCastExpression : public Expression { -public: - CppCastExpression(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~CppCastExpression() override = default; - virtual StringView class_name() const override { return "CppCastExpression"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - void set_cast_type(StringView cast_type) { m_cast_type = move(cast_type); } - void set_type(NonnullRefPtr&& type) { m_type = move(type); } - void set_expression(NonnullRefPtr&& e) { m_expression = move(e); } - -private: - StringView m_cast_type; - RefPtr m_type; - RefPtr m_expression; -}; - -class CStyleCastExpression : public Expression { -public: - CStyleCastExpression(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~CStyleCastExpression() override = default; - virtual StringView class_name() const override { return "CStyleCastExpression"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - void set_type(NonnullRefPtr&& type) { m_type = move(type); } - void set_expression(NonnullRefPtr&& e) { m_expression = move(e); } - -private: - RefPtr m_type; - RefPtr m_expression; -}; - -class SizeofExpression : public Expression { -public: - SizeofExpression(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~SizeofExpression() override = default; - virtual StringView class_name() const override { return "SizeofExpression"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - void set_type(RefPtr&& type) { m_type = move(type); } - -private: - RefPtr m_type; -}; - -class BracedInitList : public Expression { -public: - BracedInitList(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~BracedInitList() override = default; - virtual StringView class_name() const override { return "BracedInitList"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - void add_expression(NonnullRefPtr&& exp) { m_expressions.append(move(exp)); } - -private: - Vector> m_expressions; -}; - -class DummyAstNode : public ASTNode { -public: - DummyAstNode(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : ASTNode(parent, start, end, filename) - { - } - virtual bool is_dummy_node() const override { return true; } - virtual StringView class_name() const override { return "DummyAstNode"sv; } - virtual void dump(FILE* = stdout, size_t = 0) const override { } -}; - -class Constructor : public FunctionDeclaration { -public: - virtual ~Constructor() override = default; - virtual StringView class_name() const override { return "Constructor"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual bool is_constructor() const override { return true; } - - Constructor(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : FunctionDeclaration(parent, start, end, filename) - { - } -}; - -class Destructor : public FunctionDeclaration { -public: - virtual ~Destructor() override = default; - virtual StringView class_name() const override { return "Destructor"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - virtual bool is_destructor() const override { return true; } - - Destructor(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : FunctionDeclaration(parent, start, end, filename) - { - } -}; - -class UsingNamespaceDeclaration : public Declaration { -public: - virtual ~UsingNamespaceDeclaration() override = default; - virtual StringView class_name() const override { return "UsingNamespaceDeclaration"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - UsingNamespaceDeclaration(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Declaration(parent, start, end, filename) - { - } -}; - -class TypedefDeclaration : public Declaration { -public: - virtual ~TypedefDeclaration() override = default; - virtual StringView class_name() const override { return "TypedefDeclaration"sv; } - virtual void dump(FILE* = stdout, size_t indent = 0) const override; - - TypedefDeclaration(ASTNode const* parent, Optional start, Optional end, ByteString const& filename) - : Declaration(parent, start, end, filename) - { - } - - void set_alias(Type const& alias) { m_alias = alias; } - Type const* alias() const { return m_alias.ptr(); } - -private: - RefPtr m_alias; -}; -template<> -inline bool ASTNode::fast_is() const { return is_identifier(); } -template<> -inline bool ASTNode::fast_is() const { return is_member_expression(); } -template<> -inline bool ASTNode::fast_is() const { return is_variable_or_parameter_declaration(); } -template<> -inline bool ASTNode::fast_is() const { return is_function_call(); } -template<> -inline bool ASTNode::fast_is() const { return is_type(); } -template<> -inline bool ASTNode::fast_is() const { return is_declaration(); } -template<> -inline bool ASTNode::fast_is() const { return is_name(); } -template<> -inline bool ASTNode::fast_is() const { return is_dummy_node(); } - -template<> -inline bool ASTNode::fast_is() const { return is_declaration() && verify_cast(*this).is_variable_declaration(); } -template<> -inline bool ASTNode::fast_is() const { return is_declaration() && verify_cast(*this).is_struct_or_class(); } -template<> -inline bool ASTNode::fast_is() const { return is_declaration() && verify_cast(*this).is_function(); } -template<> -inline bool ASTNode::fast_is() const { return is_declaration() && verify_cast(*this).is_namespace(); } -template<> -inline bool ASTNode::fast_is() const { return is_declaration() && verify_cast(*this).is_function() && verify_cast(*this).is_constructor(); } -template<> -inline bool ASTNode::fast_is() const { return is_declaration() && verify_cast(*this).is_function() && verify_cast(*this).is_destructor(); } -template<> -inline bool ASTNode::fast_is() const { return is_type() && verify_cast(*this).is_named_type(); } -template<> -inline bool ASTNode::fast_is() const { return is_name() && verify_cast(*this).is_templatized(); } -template<> -inline bool ASTNode::fast_is() const { return is_name() && verify_cast(*this).is_sized(); } -} diff --git a/Userland/Libraries/LibCpp/CMakeLists.txt b/Userland/Libraries/LibCpp/CMakeLists.txt deleted file mode 100644 index cba29f635ea..00000000000 --- a/Userland/Libraries/LibCpp/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -set(SOURCES - AST.cpp - Lexer.cpp - Parser.cpp - Preprocessor.cpp - SemanticSyntaxHighlighter.cpp - SyntaxHighlighter.cpp - Token.cpp -) - -serenity_lib(LibCpp cpp) -target_link_libraries(LibCpp PRIVATE LibSyntax LibDiff) diff --git a/Userland/Libraries/LibCpp/Lexer.cpp b/Userland/Libraries/LibCpp/Lexer.cpp deleted file mode 100644 index e7ab750ca69..00000000000 --- a/Userland/Libraries/LibCpp/Lexer.cpp +++ /dev/null @@ -1,810 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Lexer.h" -#include -#include -#include -#include -#include - -namespace Cpp { - -Lexer::Lexer(StringView input, size_t start_line) - : m_input(input) - , m_previous_position { start_line, 0 } - , m_position { start_line, 0 } -{ -} - -char Lexer::peek(size_t offset) const -{ - if ((m_index + offset) >= m_input.length()) - return 0; - return m_input[m_index + offset]; -} - -char Lexer::consume() -{ - VERIFY(m_index < m_input.length()); - char ch = m_input[m_index++]; - m_previous_position = m_position; - if (ch == '\n') { - m_position.line++; - m_position.column = 0; - } else { - m_position.column++; - } - return ch; -} - -constexpr bool is_valid_first_character_of_identifier(char ch) -{ - return is_ascii_alpha(ch) || ch == '_' || ch == '$'; -} - -constexpr bool is_valid_nonfirst_character_of_identifier(char ch) -{ - return is_valid_first_character_of_identifier(ch) || is_ascii_digit(ch); -} - -constexpr StringView s_known_keywords[] = { - "alignas"sv, - "alignof"sv, - "and"sv, - "and_eq"sv, - "asm"sv, - "bitand"sv, - "bitor"sv, - "break"sv, - "case"sv, - "catch"sv, - "class"sv, - "compl"sv, - "const"sv, - "const_cast"sv, - "constexpr"sv, - "continue"sv, - "decltype"sv, - "default"sv, - "delete"sv, - "do"sv, - "dynamic_cast"sv, - "else"sv, - "enum"sv, - "explicit"sv, - "export"sv, - "extern"sv, - "false"sv, - "final"sv, - "for"sv, - "friend"sv, - "goto"sv, - "if"sv, - "inline"sv, - "mutable"sv, - "namespace"sv, - "new"sv, - "noexcept"sv, - "not"sv, - "not_eq"sv, - "nullptr"sv, - "operator"sv, - "or"sv, - "or_eq"sv, - "override"sv, - "private"sv, - "protected"sv, - "public"sv, - "register"sv, - "reinterpret_cast"sv, - "return"sv, - "signed"sv, - "sizeof"sv, - "static"sv, - "static_assert"sv, - "static_cast"sv, - "struct"sv, - "switch"sv, - "template"sv, - "this"sv, - "thread_local"sv, - "throw"sv, - "true"sv, - "try"sv, - "typedef"sv, - "typeid"sv, - "typename"sv, - "union"sv, - "using"sv, - "virtual"sv, - "volatile"sv, - "while"sv, - "xor"sv, - "xor_eq"sv -}; - -constexpr StringView s_known_types[] = { - "Array"sv, - "Array"sv, - "Badge"sv, - "Bitmap"sv, - "ByteBuffer"sv, - "Bytes"sv, - "Checked"sv, - "CircularDeque"sv, - "CircularQueue"sv, - "Deque"sv, - "DoublyLinkedList"sv, - "Error"sv, - "ErrorOr"sv, - "FlyString"sv, - "Function"sv, - "HashMap"sv, - "HashTable"sv, - "IPv4Address"sv, - "IntrusiveList"sv, - "IntrusiveList"sv, - "JsonArray"sv, - "JsonObject"sv, - "JsonValue"sv, - "LexicalPath"sv, - "MappedFile"sv, - "NetworkOrdered"sv, - "NeverDestroyed"sv, - "NonnullOwnPtr"sv, - "NonnullRefPtr"sv, - "Optional"sv, - "OwnPtr"sv, - "ReadonlyBytes"sv, - "RedBlackTree"sv, - "RefPtr"sv, - "Result"sv, - "ScopeGuard"sv, - "Singleton"sv, - "SinglyLinkedList"sv, - "Span"sv, - "String"sv, - "StringBuilder"sv, - "StringImpl"sv, - "StringView"sv, - "Utf8View"sv, - "Variant"sv, - "Vector"sv, - "WeakPtr"sv, - "auto"sv, - "bool"sv, - "char"sv, - "char16_t"sv, - "char32_t"sv, - "char8_t"sv, - "double"sv, - "float"sv, - "i16"sv, - "i32"sv, - "i64"sv, - "i8"sv, - "int"sv, - "int"sv, - "long"sv, - "short"sv, - "signed"sv, - "u16"sv, - "u32"sv, - "u64"sv, - "u8"sv, - "unsigned"sv, - "void"sv, - "wchar_t"sv, -}; - -static bool is_keyword(StringView string) -{ - static HashTable keywords(array_size(s_known_keywords)); - if (keywords.is_empty()) { - keywords.set_from(s_known_keywords); - } - return keywords.contains(string); -} - -static bool is_known_type(StringView string) -{ - static HashTable types(array_size(s_known_types)); - if (types.is_empty()) { - types.set_from(s_known_types); - } - return types.contains(string); -} - -void Lexer::lex_impl(Function callback) -{ - size_t token_start_index = 0; - Position token_start_position; - - auto emit_single_char_token = [&](auto type) { - callback(Token(type, m_position, m_position, m_input.substring_view(m_index, 1))); - consume(); - }; - - auto begin_token = [&] { - token_start_index = m_index; - token_start_position = m_position; - }; - auto commit_token = [&](auto type) { - if (m_options.ignore_whitespace && type == Token::Type::Whitespace) - return; - callback(Token(type, token_start_position, m_previous_position, m_input.substring_view(token_start_index, m_index - token_start_index))); - }; - - auto emit_token_equals = [&](auto type, auto equals_type) { - if (peek(1) == '=') { - begin_token(); - consume(); - consume(); - commit_token(equals_type); - return; - } - emit_single_char_token(type); - }; - - auto match_escape_sequence = [&]() -> size_t { - switch (peek(1)) { - case '\'': - case '"': - case '?': - case '\\': - case 'a': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': - case 'v': - return 2; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': { - size_t octal_digits = 1; - for (size_t i = 0; i < 2; ++i) { - char next = peek(2 + i); - if (next < '0' || next > '7') - break; - ++octal_digits; - } - return 1 + octal_digits; - } - case 'x': { - size_t hex_digits = 0; - while (is_ascii_hex_digit(peek(2 + hex_digits))) - ++hex_digits; - return 2 + hex_digits; - } - case 'u': - case 'U': { - bool is_unicode = true; - size_t number_of_digits = peek(1) == 'u' ? 4 : 8; - for (size_t i = 0; i < number_of_digits; ++i) { - if (!is_ascii_hex_digit(peek(2 + i))) { - is_unicode = false; - break; - } - } - return is_unicode ? 2 + number_of_digits : 0; - } - default: - return 0; - } - }; - - auto match_string_prefix = [&](char quote) -> size_t { - if (peek() == quote) - return 1; - if (peek() == 'L' && peek(1) == quote) - return 2; - if (peek() == 'u') { - if (peek(1) == quote) - return 2; - if (peek(1) == '8' && peek(2) == quote) - return 3; - } - if (peek() == 'U' && peek(1) == quote) - return 2; - return 0; - }; - - while (m_index < m_input.length()) { - auto ch = peek(); - if (is_ascii_space(ch)) { - begin_token(); - while (is_ascii_space(peek())) - consume(); - commit_token(Token::Type::Whitespace); - continue; - } - if (ch == '(') { - emit_single_char_token(Token::Type::LeftParen); - continue; - } - if (ch == ')') { - emit_single_char_token(Token::Type::RightParen); - continue; - } - if (ch == '{') { - emit_single_char_token(Token::Type::LeftCurly); - continue; - } - if (ch == '}') { - emit_single_char_token(Token::Type::RightCurly); - continue; - } - if (ch == '[') { - emit_single_char_token(Token::Type::LeftBracket); - continue; - } - if (ch == ']') { - emit_single_char_token(Token::Type::RightBracket); - continue; - } - if (ch == '<') { - begin_token(); - consume(); - if (peek() == '<') { - consume(); - if (peek() == '=') { - consume(); - commit_token(Token::Type::LessLessEquals); - continue; - } - commit_token(Token::Type::LessLess); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::LessEquals); - continue; - } - if (peek() == '>') { - consume(); - commit_token(Token::Type::LessGreater); - continue; - } - commit_token(Token::Type::Less); - continue; - } - if (ch == '>') { - begin_token(); - consume(); - if (peek() == '>') { - consume(); - if (peek() == '=') { - consume(); - commit_token(Token::Type::GreaterGreaterEquals); - continue; - } - commit_token(Token::Type::GreaterGreater); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::GreaterEquals); - continue; - } - commit_token(Token::Type::Greater); - continue; - } - if (ch == ',') { - emit_single_char_token(Token::Type::Comma); - continue; - } - if (ch == '+') { - begin_token(); - consume(); - if (peek() == '+') { - consume(); - commit_token(Token::Type::PlusPlus); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::PlusEquals); - continue; - } - commit_token(Token::Type::Plus); - continue; - } - if (ch == '-') { - begin_token(); - consume(); - if (peek() == '-') { - consume(); - commit_token(Token::Type::MinusMinus); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::MinusEquals); - continue; - } - if (peek() == '>') { - consume(); - if (peek() == '*') { - consume(); - commit_token(Token::Type::ArrowAsterisk); - continue; - } - commit_token(Token::Type::Arrow); - continue; - } - commit_token(Token::Type::Minus); - continue; - } - if (ch == '*') { - emit_token_equals(Token::Type::Asterisk, Token::Type::AsteriskEquals); - continue; - } - if (ch == '%') { - emit_token_equals(Token::Type::Percent, Token::Type::PercentEquals); - continue; - } - if (ch == '^') { - emit_token_equals(Token::Type::Caret, Token::Type::CaretEquals); - continue; - } - if (ch == '!') { - emit_token_equals(Token::Type::ExclamationMark, Token::Type::ExclamationMarkEquals); - continue; - } - if (ch == '=') { - emit_token_equals(Token::Type::Equals, Token::Type::EqualsEquals); - continue; - } - if (ch == '&') { - begin_token(); - consume(); - if (peek() == '&') { - consume(); - commit_token(Token::Type::AndAnd); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::AndEquals); - continue; - } - commit_token(Token::Type::And); - continue; - } - if (ch == '|') { - begin_token(); - consume(); - if (peek() == '|') { - consume(); - commit_token(Token::Type::PipePipe); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::PipeEquals); - continue; - } - commit_token(Token::Type::Pipe); - continue; - } - if (ch == '~') { - emit_single_char_token(Token::Type::Tilde); - continue; - } - if (ch == '?') { - emit_single_char_token(Token::Type::QuestionMark); - continue; - } - if (ch == ':') { - begin_token(); - consume(); - if (peek() == ':') { - consume(); - if (peek() == '*') { - consume(); - commit_token(Token::Type::ColonColonAsterisk); - continue; - } - commit_token(Token::Type::ColonColon); - continue; - } - commit_token(Token::Type::Colon); - continue; - } - if (ch == ';') { - emit_single_char_token(Token::Type::Semicolon); - continue; - } - if (ch == '.') { - begin_token(); - consume(); - if (peek() == '*') { - consume(); - commit_token(Token::Type::DotAsterisk); - continue; - } - commit_token(Token::Type::Dot); - continue; - } - if (ch == '#') { - begin_token(); - consume(); - while (AK::is_ascii_space(peek())) - consume(); - - size_t directive_start = m_index; - if (is_valid_first_character_of_identifier(peek())) - while (peek() && is_valid_nonfirst_character_of_identifier(peek())) - consume(); - - auto directive = StringView(m_input.characters_without_null_termination() + directive_start, m_index - directive_start); - if (directive == "include"sv) { - commit_token(Token::Type::IncludeStatement); - - if (is_ascii_space(peek())) { - begin_token(); - do { - consume(); - } while (is_ascii_space(peek())); - commit_token(Token::Type::Whitespace); - } - - begin_token(); - if (peek() == '<' || peek() == '"') { - char closing = consume() == '<' ? '>' : '"'; - while (peek() && peek() != closing && peek() != '\n') - consume(); - - if (peek() && consume() == '\n') { - commit_token(Token::Type::IncludePath); - continue; - } - - commit_token(Token::Type::IncludePath); - begin_token(); - } - } else { - while (peek()) { - if (peek() == '\\' && peek(1) == '\n') { - consume(); - consume(); - } else if (peek() == '\n') { - break; - } else { - consume(); - } - } - - commit_token(Token::Type::PreprocessorStatement); - } - - continue; - } - if (ch == '/' && peek(1) == '/') { - begin_token(); - while (peek() && peek() != '\n') - consume(); - commit_token(Token::Type::Comment); - continue; - } - if (ch == '/' && peek(1) == '*') { - begin_token(); - consume(); - consume(); - bool comment_block_ends = false; - while (peek()) { - if (peek() == '*' && peek(1) == '/') { - comment_block_ends = true; - break; - } - - consume(); - } - - if (comment_block_ends) { - consume(); - consume(); - } - - commit_token(Token::Type::Comment); - continue; - } - if (ch == '/') { - emit_token_equals(Token::Type::Slash, Token::Type::SlashEquals); - continue; - } - if (size_t prefix = match_string_prefix('"'); prefix > 0) { - begin_token(); - for (size_t i = 0; i < prefix; ++i) - consume(); - while (peek()) { - if (peek() == '\\') { - if (size_t escape = match_escape_sequence(); escape > 0) { - commit_token(Token::Type::DoubleQuotedString); - begin_token(); - for (size_t i = 0; i < escape; ++i) - consume(); - commit_token(Token::Type::EscapeSequence); - begin_token(); - continue; - } - } - - // If string is not terminated - stop before EOF - if (!peek(1)) - break; - - if (consume() == '"') - break; - } - commit_token(Token::Type::DoubleQuotedString); - continue; - } - if (size_t prefix = match_string_prefix('R'); prefix > 0 && peek(prefix) == '"') { - begin_token(); - for (size_t i = 0; i < prefix + 1; ++i) - consume(); - size_t prefix_start = m_index; - while (peek() && peek() != '(') - consume(); - StringView prefix_string = m_input.substring_view(prefix_start, m_index - prefix_start); - while (peek()) { - if (consume() == '"') { - VERIFY(m_index >= prefix_string.length() + 2); - VERIFY(m_input[m_index - 1] == '"'); - if (m_input[m_index - 1 - prefix_string.length() - 1] == ')') { - StringView suffix_string = m_input.substring_view(m_index - 1 - prefix_string.length(), prefix_string.length()); - if (prefix_string == suffix_string) - break; - } - } - } - commit_token(Token::Type::RawString); - continue; - } - if (size_t prefix = match_string_prefix('\''); prefix > 0) { - begin_token(); - for (size_t i = 0; i < prefix; ++i) - consume(); - while (peek()) { - if (peek() == '\\') { - if (size_t escape = match_escape_sequence(); escape > 0) { - commit_token(Token::Type::SingleQuotedString); - begin_token(); - for (size_t i = 0; i < escape; ++i) - consume(); - commit_token(Token::Type::EscapeSequence); - begin_token(); - continue; - } - } - - if (consume() == '\'') - break; - } - commit_token(Token::Type::SingleQuotedString); - continue; - } - if (is_ascii_digit(ch) || (ch == '.' && is_ascii_digit(peek(1)))) { - begin_token(); - consume(); - - auto type = ch == '.' ? Token::Type::Float : Token::Type::Integer; - bool is_hex = false; - bool is_binary = false; - - auto match_exponent = [&]() -> size_t { - char ch = peek(); - if (ch != 'e' && ch != 'E' && ch != 'p' && ch != 'P') - return 0; - - type = Token::Type::Float; - size_t length = 1; - ch = peek(length); - if (ch == '+' || ch == '-') { - ++length; - } - for (ch = peek(length); is_ascii_digit(ch); ch = peek(length)) { - ++length; - } - return length; - }; - - auto match_type_literal = [&]() -> size_t { - size_t length = 0; - for (;;) { - char ch = peek(length); - if ((ch == 'u' || ch == 'U') && type == Token::Type::Integer) { - ++length; - } else if ((ch == 'f' || ch == 'F') && !is_binary) { - type = Token::Type::Float; - ++length; - } else if (ch == 'l' || ch == 'L') { - ++length; - } else - return length; - } - }; - - if (peek() == 'b' || peek() == 'B') { - consume(); - is_binary = true; - for (char ch = peek(); ch == '0' || ch == '1' || (ch == '\'' && peek(1) != '\''); ch = peek()) { - consume(); - } - } else { - if (peek() == 'x' || peek() == 'X') { - consume(); - is_hex = true; - } - - for (char ch = peek(); (is_hex ? is_ascii_hex_digit(ch) : is_ascii_digit(ch)) || (ch == '\'' && peek(1) != '\'') || ch == '.'; ch = peek()) { - if (ch == '.') { - if (type == Token::Type::Integer) { - type = Token::Type::Float; - } else - break; - }; - consume(); - } - } - - if (!is_binary) { - size_t length = match_exponent(); - for (size_t i = 0; i < length; ++i) - consume(); - } - - size_t length = match_type_literal(); - for (size_t i = 0; i < length; ++i) - consume(); - - commit_token(type); - continue; - } - if (is_valid_first_character_of_identifier(ch)) { - begin_token(); - while (peek() && is_valid_nonfirst_character_of_identifier(peek())) - consume(); - auto token_view = StringView(m_input.characters_without_null_termination() + token_start_index, m_index - token_start_index); - if (is_keyword(token_view)) - commit_token(Token::Type::Keyword); - else if (is_known_type(token_view)) - commit_token(Token::Type::KnownType); - else - commit_token(Token::Type::Identifier); - continue; - } - - if (ch == '\\' && peek(1) == '\n') { - consume(); - consume(); - continue; - } - - dbgln("Unimplemented token character: {}", ch); - emit_single_char_token(Token::Type::Unknown); - } -} - -Vector Lexer::lex() -{ - Vector tokens; - lex_impl([&](auto token) { - tokens.append(move(token)); - }); - return tokens; -} - -} diff --git a/Userland/Libraries/LibCpp/Lexer.h b/Userland/Libraries/LibCpp/Lexer.h deleted file mode 100644 index 7c6da635886..00000000000 --- a/Userland/Libraries/LibCpp/Lexer.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace Cpp { - -class Lexer { -public: - explicit Lexer(StringView, size_t start_line = 0); - - Vector lex(); - template - void lex_iterable(Callback); - - void set_ignore_whitespace(bool value) { m_options.ignore_whitespace = value; } - -private: - char peek(size_t offset = 0) const; - char consume(); - void lex_impl(Function); - - StringView m_input; - size_t m_index { 0 }; - Position m_previous_position { 0, 0 }; - Position m_position { 0, 0 }; - - struct Options { - bool ignore_whitespace { false }; - } m_options; -}; - -template -void Lexer::lex_iterable(Callback callback) -{ - return lex_impl(move(callback)); -} - -} diff --git a/Userland/Libraries/LibCpp/Parser.cpp b/Userland/Libraries/LibCpp/Parser.cpp deleted file mode 100644 index 2ecb7ff5bc6..00000000000 --- a/Userland/Libraries/LibCpp/Parser.cpp +++ /dev/null @@ -1,1864 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Parser.h" -#include "AST.h" -#include -#include -#include -#include - -#define LOG_SCOPE() ScopeLogger logger(ByteString::formatted("'{}' - {} ({})", peek().text(), peek().type_as_byte_string(), m_state.token_index)) - -namespace Cpp { - -Parser::Parser(Vector tokens, ByteString const& filename) - : m_filename(filename) - , m_tokens(move(tokens)) -{ - if constexpr (CPP_DEBUG) { - dbgln("Tokens:"); - for (size_t i = 0; i < m_tokens.size(); ++i) { - dbgln("{}- {}", i, m_tokens[i].to_byte_string()); - } - } -} - -NonnullRefPtr Parser::parse() -{ - LOG_SCOPE(); - if (m_tokens.is_empty()) - return create_root_ast_node({}, {}); - auto unit = create_root_ast_node(m_tokens.first().start(), m_tokens.last().end()); - unit->set_declarations(parse_declarations_in_translation_unit(*unit)); - return unit; -} - -Vector> Parser::parse_declarations_in_translation_unit(ASTNode const& parent) -{ - Vector> declarations; - while (!eof()) { - auto declaration = parse_single_declaration_in_translation_unit(parent); - if (declaration) { - declarations.append(declaration.release_nonnull()); - } else { - error("unexpected token"sv); - consume(); - } - } - return declarations; -} - -RefPtr Parser::parse_single_declaration_in_translation_unit(ASTNode const& parent) -{ - while (!eof()) { - if (match_comment()) { - consume(Token::Type::Comment); - continue; - } - - if (match_preprocessor()) { - consume_preprocessor(); - continue; - } - - auto declaration = match_declaration_in_translation_unit(); - if (declaration.has_value()) { - return parse_declaration(parent, declaration.value()); - } - return {}; - } - return {}; -} - -NonnullRefPtr Parser::parse_declaration(ASTNode const& parent, DeclarationType declaration_type) -{ - switch (declaration_type) { - case DeclarationType::Function: - return parse_function_declaration(parent); - case DeclarationType::Variable: - return parse_variable_declaration(parent); - case DeclarationType::Enum: - return parse_enum_declaration(parent); - case DeclarationType::Class: - return parse_class_declaration(parent); - case DeclarationType::Namespace: - return parse_namespace_declaration(parent); - case DeclarationType::Constructor: - return parse_constructor(parent); - case DeclarationType::Destructor: - return parse_destructor(parent); - case DeclarationType::UsingNamespace: - return parse_using_namespace_declaration(parent); - case DeclarationType::UsingType: - return parse_using_type_declaration(parent); - case DeclarationType::Typedef: - return parse_typedef_declaration(parent); - default: - error("unexpected declaration type"sv); - return create_ast_node(parent, position(), position()); - } -} - -NonnullRefPtr Parser::parse_function_declaration(ASTNode const& parent) -{ - auto func = create_ast_node(parent, position(), {}); - - func->set_qualifiers(parse_function_qualifiers()); - func->set_return_type(parse_type(*func)); - - func->set_name(parse_name(*func)); - - consume(Token::Type::LeftParen); - auto parameters = parse_parameter_list(*func); - if (parameters.has_value()) - func->set_parameters(parameters.value()); - - consume(Token::Type::RightParen); - - while (match_keyword("const") || match_keyword("override")) { - consume(); - // FIXME: Note that this function is supposed to be a class member, and `this` has to be const, somehow. - } - - RefPtr body; - Position func_end {}; - if (peek(Token::Type::LeftCurly).has_value()) { - body = parse_function_definition(*func); - func_end = body->end(); - } else { - func_end = position(); - if (match_attribute_specification()) - consume_attribute_specification(); // we don't use the value of __attribute__ - consume(Token::Type::Semicolon); - } - - func->set_definition(move(body)); - func->set_end(func_end); - return func; -} - -NonnullRefPtr Parser::parse_function_definition(ASTNode const& parent) -{ - LOG_SCOPE(); - auto func = create_ast_node(parent, position(), {}); - consume(Token::Type::LeftCurly); - while (!eof() && peek().type() != Token::Type::RightCurly) { - func->add_statement(parse_statement(func)); - } - func->set_end(position()); - if (!eof()) - consume(Token::Type::RightCurly); - return func; -} - -NonnullRefPtr Parser::parse_statement(ASTNode const& parent) -{ - LOG_SCOPE(); - ArmedScopeGuard consume_semicolon([this]() { - consume(Token::Type::Semicolon); - }); - - if (match_block_statement()) { - consume_semicolon.disarm(); - return parse_block_statement(parent); - } - if (match_comment()) { - consume_semicolon.disarm(); - return parse_comment(parent); - } - if (match_variable_declaration()) { - return parse_variable_declaration(parent, false); - } - if (match_expression()) { - return parse_expression(parent); - } - if (match_keyword("return")) { - return parse_return_statement(parent); - } - if (match_keyword("for")) { - consume_semicolon.disarm(); - return parse_for_statement(parent); - } - if (match_keyword("if")) { - consume_semicolon.disarm(); - return parse_if_statement(parent); - } else { - error("unexpected statement type"sv); - consume_semicolon.disarm(); - consume(); - return create_ast_node(parent, position(), position()); - } -} - -NonnullRefPtr Parser::parse_comment(ASTNode const& parent) -{ - auto comment = create_ast_node(parent, position(), {}); - consume(Token::Type::Comment); - comment->set_end(position()); - return comment; -} - -bool Parser::match_block_statement() -{ - return peek().type() == Token::Type::LeftCurly; -} - -NonnullRefPtr Parser::parse_block_statement(ASTNode const& parent) -{ - LOG_SCOPE(); - auto block_statement = create_ast_node(parent, position(), {}); - consume(Token::Type::LeftCurly); - while (!eof() && peek().type() != Token::Type::RightCurly) { - block_statement->add_statement(parse_statement(*block_statement)); - } - consume(Token::Type::RightCurly); - block_statement->set_end(position()); - return block_statement; -} - -bool Parser::match_type() -{ - return match_named_type(); -} - -bool Parser::match_named_type() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - parse_type_qualifiers(); - if (match_keyword("auto")) { - return true; - } - - if (match_keyword("struct")) { - consume(Token::Type::Keyword); // Consume struct prefix - } - - if (!match_name()) - return false; - - return true; -} - -bool Parser::match_template_arguments() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (!peek(Token::Type::Less).has_value()) - return false; - consume(); - - while (!eof() && peek().type() != Token::Type::Greater) { - if (!match_named_type()) - return false; - (void)parse_type(get_dummy_node()); - } - - return peek().type() == Token::Type::Greater; -} - -Vector> Parser::parse_template_arguments(ASTNode const& parent) -{ - LOG_SCOPE(); - - consume(Token::Type::Less); - - Vector> template_arguments; - while (!eof() && peek().type() != Token::Type::Greater) { - template_arguments.append(parse_type(parent)); - } - - consume(Token::Type::Greater); - - return template_arguments; -} - -bool Parser::match_variable_declaration() -{ - LOG_SCOPE(); - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (!match_type()) { - return false; - } - - VERIFY(m_root_node); - (void)parse_type(get_dummy_node()); - - // Identifier - if (!match_name()) - return false; - - (void)parse_name(get_dummy_node()); - - while (!eof() && (peek().type() == Token::Type::LeftBracket)) { - consume(Token::Type::LeftBracket); - - if (match(Token::Type::Integer)) { - consume(Token::Type::Integer); - } - if (!match(Token::Type::RightBracket)) { - error("No closing right bracket"sv); - return false; - } - consume(Token::Type::RightBracket); - } - - if (match(Token::Type::Equals)) { - consume(Token::Type::Equals); - if (!match_expression()) { - error("initial value of variable is not an expression"sv); - return false; - } - return true; - } - - if (match_braced_init_list()) - (void)parse_braced_init_list(get_dummy_node()); - - return match(Token::Type::Semicolon); -} - -NonnullRefPtr Parser::parse_variable_declaration(ASTNode const& parent, bool expect_semicolon) -{ - LOG_SCOPE(); - auto var = create_ast_node(parent, position(), {}); - if (!match_variable_declaration()) { - error("unexpected token for variable type"sv); - var->set_end(position()); - return var; - } - var->set_type(parse_type(var)); - auto name = parse_name(*var); - RefPtr initial_value; - - if (match(Token::Type::Equals)) { - consume(Token::Type::Equals); - initial_value = parse_expression(var); - } - - if (match_braced_init_list()) { - initial_value = parse_braced_init_list(var); - } - - if (expect_semicolon) - consume(Token::Type::Semicolon); - - var->set_end(position()); - var->set_name(name); - var->set_initial_value(move(initial_value)); - - return var; -} - -NonnullRefPtr Parser::parse_expression(ASTNode const& parent) -{ - LOG_SCOPE(); - auto expression = parse_primary_expression(parent); - // TODO: remove eof() logic, should still work without it - if (eof() || match(Token::Type::Semicolon)) { - return expression; - } - - Vector> secondary_expressions; - - while (match_secondary_expression()) { - // FIXME: Handle operator precedence - expression = parse_secondary_expression(parent, expression); - secondary_expressions.append(expression); - } - - for (size_t i = 0; secondary_expressions.size() != 0 && i < secondary_expressions.size() - 1; ++i) { - const_cast(*secondary_expressions[i]).set_parent(secondary_expressions[i + 1]); - } - - return expression; -} - -bool Parser::match_secondary_expression() -{ - auto type = peek().type(); - return type == Token::Type::Plus - || type == Token::Type::PlusEquals - || type == Token::Type::Minus - || type == Token::Type::MinusEquals - || type == Token::Type::Asterisk - || type == Token::Type::AsteriskEquals - || type == Token::Type::Percent - || type == Token::Type::PercentEquals - || type == Token::Type::Equals - || type == Token::Type::Greater - || type == Token::Type::GreaterEquals - || type == Token::Type::Less - || type == Token::Type::LessEquals - || type == Token::Type::Dot - || type == Token::Type::PlusPlus - || type == Token::Type::MinusMinus - || type == Token::Type::And - || type == Token::Type::AndEquals - || type == Token::Type::Pipe - || type == Token::Type::PipeEquals - || type == Token::Type::Caret - || type == Token::Type::CaretEquals - || type == Token::Type::LessLess - || type == Token::Type::LessLessEquals - || type == Token::Type::GreaterGreater - || type == Token::Type::GreaterGreaterEquals - || type == Token::Type::EqualsEquals - || type == Token::Type::AndAnd - || type == Token::Type::PipePipe - || type == Token::Type::ExclamationMarkEquals - || type == Token::Type::Arrow - || type == Token::Type::LeftParen; -} - -NonnullRefPtr Parser::parse_primary_expression(ASTNode const& parent) -{ - LOG_SCOPE(); - // TODO: remove eof() logic, should still work without it - if (eof()) { - auto node = create_ast_node(parent, position(), position()); - return node; - } - - if (match_unary_expression()) - return parse_unary_expression(parent); - - if (match_literal()) { - return parse_literal(parent); - } - - if (match_cpp_cast_expression()) - return parse_cpp_cast_expression(parent); - - if (match_c_style_cast_expression()) - return parse_c_style_cast_expression(parent); - - if (match_sizeof_expression()) - return parse_sizeof_expression(parent); - - if (match_braced_init_list()) - return parse_braced_init_list(parent); - - if (match_name()) { - return parse_name(parent); - } - - error("could not parse primary expression"sv); - auto token = consume(); - return create_ast_node(parent, token.start(), token.end()); -} - -bool Parser::match_literal() -{ - switch (peek().type()) { - case Token::Type::Integer: - return true; - case Token::Type::SingleQuotedString: - return true; - case Token::Type::DoubleQuotedString: - return true; - case Token::Type::Float: - return true; - case Token::Type::Keyword: { - return match_boolean_literal() || peek().text() == "nullptr"; - } - default: - return false; - } -} - -bool Parser::match_unary_expression() -{ - auto type = peek().type(); - return type == Token::Type::PlusPlus - || type == Token::Type::MinusMinus - || type == Token::Type::ExclamationMark - || type == Token::Type::Tilde - || type == Token::Type::Plus - || type == Token::Type::Minus - || type == Token::Type::And; -} - -NonnullRefPtr Parser::parse_unary_expression(ASTNode const& parent) -{ - auto unary_exp = create_ast_node(parent, position(), {}); - auto op_token = consume(); - UnaryOp op { UnaryOp::Invalid }; - switch (op_token.type()) { - case Token::Type::Minus: - op = UnaryOp::Minus; - break; - case Token::Type::Plus: - op = UnaryOp::Plus; - break; - case Token::Type::ExclamationMark: - op = UnaryOp::Not; - break; - case Token::Type::Tilde: - op = UnaryOp::BitwiseNot; - break; - case Token::Type::PlusPlus: - op = UnaryOp::PlusPlus; - break; - case Token::Type::And: - op = UnaryOp::Address; - break; - default: - break; - } - unary_exp->set_op(op); - auto lhs = parse_expression(*unary_exp); - unary_exp->set_lhs(lhs); - unary_exp->set_end(lhs->end()); - return unary_exp; -} - -NonnullRefPtr Parser::parse_literal(ASTNode const& parent) -{ - switch (peek().type()) { - case Token::Type::Integer: { - auto token = consume(); - return create_ast_node(parent, token.start(), token.end(), text_of_token(token)); - } - case Token::Type::SingleQuotedString: - [[fallthrough]]; - case Token::Type::DoubleQuotedString: - return parse_string_literal(parent); - case Token::Type::Keyword: { - if (match_boolean_literal()) - return parse_boolean_literal(parent); - if (peek().text() == "nullptr") { - auto token = consume(); - return create_ast_node(parent, token.start(), token.end()); - } - [[fallthrough]]; - } - default: { - error("could not parse literal"sv); - auto token = consume(); - return create_ast_node(parent, token.start(), token.end()); - } - } -} - -NonnullRefPtr Parser::parse_secondary_expression(ASTNode const& parent, NonnullRefPtr lhs) -{ - LOG_SCOPE(); - switch (peek().type()) { - case Token::Type::Plus: - return parse_binary_expression(parent, lhs, BinaryOp::Addition); - case Token::Type::Less: - return parse_binary_expression(parent, lhs, BinaryOp::LessThan); - case Token::Type::EqualsEquals: - return parse_binary_expression(parent, lhs, BinaryOp::EqualsEquals); - case Token::Type::ExclamationMarkEquals: - return parse_binary_expression(parent, lhs, BinaryOp::NotEqual); - case Token::Type::And: - return parse_binary_expression(parent, lhs, BinaryOp::BitwiseAnd); - case Token::Type::AndAnd: - return parse_binary_expression(parent, lhs, BinaryOp::LogicalAnd); - case Token::Type::Pipe: - return parse_binary_expression(parent, lhs, BinaryOp::BitwiseOr); - case Token::Type::PipePipe: - return parse_binary_expression(parent, lhs, BinaryOp::LogicalOr); - case Token::Type::Arrow: - return parse_binary_expression(parent, lhs, BinaryOp::Arrow); - case Token::Type::Equals: - return parse_assignment_expression(parent, lhs, AssignmentOp::Assignment); - case Token::Type::Dot: { - consume(); - auto exp = create_ast_node(parent, lhs->start(), {}); - const_cast(*lhs).set_parent(*exp); - exp->set_object(move(lhs)); - auto identifier_token = consume(Token::Type::Identifier); - exp->set_property(create_ast_node(*exp, identifier_token.start(), identifier_token.end(), identifier_token.text())); - exp->set_end(position()); - return exp; - } - case Token::Type::LeftParen: { - consume(); - auto func = create_ast_node(parent, lhs->start(), {}); - const_cast(*lhs).set_parent(*func); - func->set_callee(move(lhs)); - while (peek().type() != Token::Type::RightParen && !eof()) { - func->add_argument(parse_expression(*func)); - if (peek().type() == Token::Type::Comma) - consume(Token::Type::Comma); - } - consume(Token::Type::RightParen); - func->set_end(position()); - return func; - } - default: { - error(ByteString::formatted("unexpected operator for expression. operator: {}", peek().to_byte_string())); - auto token = consume(); - return create_ast_node(parent, token.start(), token.end()); - } - } -} - -NonnullRefPtr Parser::parse_binary_expression(ASTNode const& parent, NonnullRefPtr lhs, BinaryOp op) -{ - consume(); // Operator - auto exp = create_ast_node(parent, lhs->start(), {}); - const_cast(*lhs).set_parent(*exp); - exp->set_op(op); - exp->set_lhs(move(lhs)); - auto rhs = parse_expression(exp); - exp->set_end(rhs->end()); - exp->set_rhs(move(rhs)); - return exp; -} - -NonnullRefPtr Parser::parse_assignment_expression(ASTNode const& parent, NonnullRefPtr lhs, AssignmentOp op) -{ - consume(); // Operator - auto exp = create_ast_node(parent, lhs->start(), {}); - const_cast(*lhs).set_parent(*exp); - exp->set_op(op); - exp->set_lhs(move(lhs)); - auto rhs = parse_expression(exp); - exp->set_end(rhs->end()); - exp->set_rhs(move(rhs)); - return exp; -} - -Optional Parser::match_declaration_in_translation_unit() -{ - if (match_function_declaration()) - return DeclarationType::Function; - if (match_enum_declaration()) - return DeclarationType::Enum; - if (match_class_declaration()) - return DeclarationType::Class; - if (match_namespace_declaration()) - return DeclarationType::Namespace; - if (match_variable_declaration()) - return DeclarationType::Variable; - if (match_using_namespace_declaration()) - return DeclarationType::UsingNamespace; - if (match_using_type_declaration()) - return DeclarationType::UsingType; - if (match_typedef_declaration()) - return DeclarationType::Typedef; - return {}; -} - -Optional Parser::match_class_member(StringView class_name) -{ - if (match_function_declaration()) - return DeclarationType::Function; - if (match_enum_declaration()) - return DeclarationType::Enum; - if (match_class_declaration()) - return DeclarationType::Class; - if (match_variable_declaration()) - return DeclarationType::Variable; - if (match_constructor(class_name)) - return DeclarationType::Constructor; - if (match_destructor(class_name)) - return DeclarationType::Destructor; - return {}; -} - -bool Parser::match_enum_declaration() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (!match_keyword("enum")) - return false; - - consume(Token::Type::Keyword); - - if (match_keyword("class")) - consume(Token::Type::Keyword); - - if (!match(Token::Type::Identifier)) - return false; - - consume(Token::Type::Identifier); - - return match(Token::Type::LeftCurly); -} - -bool Parser::match_class_declaration() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (!match_keyword("struct") && !match_keyword("class")) - return false; - - consume(Token::Type::Keyword); - - if (!match(Token::Type::Identifier)) - return false; - - consume(Token::Type::Identifier); - - auto has_final = match_keyword("final"); - - if (peek(has_final ? 1 : 0).type() == Token::Type::Colon) { - if (has_final) - consume(); - - do { - consume(); - - while (match_keyword("private") || match_keyword("public") || match_keyword("protected") || match_keyword("virtual")) - consume(); - - if (!match_name()) - return false; - (void)parse_name(get_dummy_node()); - } while (peek().type() == Token::Type::Comma); - } - - return match(Token::Type::LeftCurly); -} - -bool Parser::match_namespace_declaration() -{ - return match_keyword("namespace"); -} - -bool Parser::match_function_declaration() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - parse_function_qualifiers(); - - if (!match_type()) - return false; - - VERIFY(m_root_node); - (void)parse_type(get_dummy_node()); - - if (!match_name()) - return false; - - (void)parse_name(get_dummy_node()); - - if (!peek(Token::Type::LeftParen).has_value()) - return false; - consume(); - - while (consume().type() != Token::Type::RightParen && !eof()) { }; - - while (match_keyword("const") || match_keyword("override")) - consume(); - - if (peek(Token::Type::Semicolon).has_value() || peek(Token::Type::LeftCurly).has_value()) - return true; - - if (match_attribute_specification()) { - consume_attribute_specification(); - return peek(Token::Type::Semicolon).has_value(); - } - - return false; -} - -Optional>> Parser::parse_parameter_list(ASTNode const& parent) -{ - LOG_SCOPE(); - Vector> parameters; - while (peek().type() != Token::Type::RightParen && !eof()) { - if (match_ellipsis()) { - auto param = create_ast_node(parent, position(), {}, RefPtr {}); - consume(Token::Type::Dot); - consume(Token::Type::Dot); - auto last_dot = consume(Token::Type::Dot); - param->set_ellipsis(true); - param->set_end(last_dot.end()); - parameters.append(move(param)); - } else { - auto type = parse_type(parent); - - RefPtr name; - if (match_name()) { - name = parse_name(parent); - } - - auto param = create_ast_node(parent, type->start(), !name.is_null() ? name->end() : type->end(), name); - const_cast(*type).set_parent(*param.ptr()); - - param->set_type(move(type)); - parameters.append(move(param)); - } - - if (peek(Token::Type::Comma).has_value()) - consume(Token::Type::Comma); - } - return parameters; -} - -bool Parser::match_comment() -{ - return match(Token::Type::Comment); -} - -bool Parser::match_whitespace() -{ - return match(Token::Type::Whitespace); -} - -bool Parser::match_preprocessor() -{ - return match(Token::Type::PreprocessorStatement) || match(Token::Type::IncludeStatement); -} - -void Parser::consume_preprocessor() -{ - LOG_SCOPE(); - switch (peek().type()) { - case Token::Type::PreprocessorStatement: - consume(); - break; - case Token::Type::IncludeStatement: - consume(); - consume(Token::Type::IncludePath); - break; - default: - error("unexpected token while parsing preprocessor statement"sv); - consume(); - } -} - -Optional Parser::consume_whitespace() -{ - LOG_SCOPE(); - return consume(Token::Type::Whitespace); -} - -Token Parser::consume(Token::Type type) -{ - auto token = consume(); - if (token.type() != type) - error(ByteString::formatted("expected {} at {}:{}, found: {}", Token::type_to_string(type), token.start().line, token.start().column, Token::type_to_string(token.type()))); - return token; -} - -bool Parser::match(Token::Type type) -{ - return peek().type() == type; -} - -Token Parser::consume() -{ - if (eof()) { - error("C++ Parser: out of tokens"sv); - return { Token::Type::EOF_TOKEN, position(), position(), {} }; - } - return m_tokens[m_state.token_index++]; -} - -Token Parser::peek(size_t offset) const -{ - if (m_state.token_index + offset >= m_tokens.size()) - return { Token::Type::EOF_TOKEN, position(), position(), {} }; - return m_tokens[m_state.token_index + offset]; -} - -Optional Parser::peek(Token::Type type) const -{ - auto token = peek(); - if (token.type() == type) - return token; - return {}; -} - -void Parser::save_state() -{ - m_saved_states.append(m_state); - m_state.state_nodes.clear(); -} - -void Parser::load_state() -{ - m_state = m_saved_states.take_last(); -} - -StringView Parser::text_of_token(Cpp::Token const& token) const -{ - return token.text(); -} - -ByteString Parser::text_of_node(ASTNode const& node) const -{ - return text_in_range(node.start(), node.end()); -} - -ByteString Parser::text_in_range(Position start, Position end) const -{ - StringBuilder builder; - for (auto token : tokens_in_range(start, end)) { - builder.append(token.text()); - } - return builder.to_byte_string(); -} - -Vector Parser::tokens_in_range(Position start, Position end) const -{ - auto start_token_index = index_of_token_at(start); - auto end_node_index = index_of_token_at(end); - VERIFY(start_token_index.has_value()); - VERIFY(end_node_index.has_value()); - - Vector tokens; - for (size_t i = start_token_index.value(); i <= end_node_index.value(); ++i) { - tokens.append(m_tokens[i]); - } - return tokens; -} - -void Parser::error(StringView message) -{ - LOG_SCOPE(); - - if (!m_saved_states.is_empty()) - return; - - if (message.is_null() || message.is_empty()) - message = ""sv; - ByteString formatted_message; - if (m_state.token_index >= m_tokens.size()) { - formatted_message = ByteString::formatted("C++ Parsed error on EOF.{}", message); - } else { - formatted_message = ByteString::formatted("C++ Parser error: {}. token: {} ({}:{})", - message, - m_state.token_index < m_tokens.size() ? text_of_token(m_tokens[m_state.token_index]) : "EOF"sv, - m_tokens[m_state.token_index].start().line, - m_tokens[m_state.token_index].start().column); - } - - m_errors.append(formatted_message); -} - -bool Parser::match_expression() -{ - return match_literal() - || match_name() - || match_unary_expression() - || match_cpp_cast_expression() - || match_c_style_cast_expression() - || match_sizeof_expression() - || match_braced_init_list(); -} - -bool Parser::eof() const -{ - return m_state.token_index >= m_tokens.size(); -} - -Position Parser::position() const -{ - if (m_tokens.is_empty()) - return {}; - - if (eof()) - return m_tokens.last().end(); - - return peek().start(); -} - -Position Parser::previous_token_end() const -{ - if (m_state.token_index < 1) - return {}; - return m_tokens[m_state.token_index - 1].end(); -} - -RefPtr Parser::node_at(Position pos) const -{ - VERIFY(m_saved_states.is_empty()); - auto index = index_of_node_at(pos); - if (!index.has_value()) - return nullptr; - return m_nodes[index.value()]; -} - -Optional Parser::index_of_node_at(Position pos) const -{ - VERIFY(!m_tokens.is_empty()); - VERIFY(m_saved_states.is_empty()); - Optional match_node_index; - - auto node_span = [](ASTNode const& node) { - VERIFY(node.end().line >= node.start().line); - VERIFY((node.end().line > node.start().line) || (node.end().column >= node.start().column)); - return Position { node.end().line - node.start().line, node.start().line != node.end().line ? 0 : node.end().column - node.start().column }; - }; - - for (size_t node_index = 0; node_index < m_nodes.size(); ++node_index) { - auto& node = m_nodes[node_index]; - if (node->start() > pos || node->end() < pos) - continue; - - if (!match_node_index.has_value() || (node_span(node) <= node_span(m_nodes[match_node_index.value()]))) - match_node_index = node_index; - } - return match_node_index; -} - -Optional Parser::token_at(Position pos) const -{ - auto index = index_of_token_at(pos); - if (!index.has_value()) - return {}; - return m_tokens[index.value()]; -} - -Optional Parser::index_of_token_at(Position pos) const -{ - for (size_t token_index = 0; token_index < m_tokens.size(); ++token_index) { - auto token = m_tokens[token_index]; - if (token.start() > pos || token.end() < pos) - continue; - return token_index; - } - return {}; -} - -void Parser::print_tokens() const -{ - for (auto& token : m_tokens) { - outln("{}", token.to_byte_string()); - } -} - -Vector Parser::get_todo_entries() const -{ - Vector ret; - for (auto& token : m_tokens) { - if (token.type() == Token::Type::Comment) { - if (token.text().contains("TODO"sv) || token.text().contains("FIXME"sv)) { - ret.append({ token.text(), m_filename, token.start().line, token.start().column }); - } - } - } - return ret; -} - -NonnullRefPtr Parser::parse_string_literal(ASTNode const& parent) -{ - LOG_SCOPE(); - Optional start_token_index; - Optional end_token_index; - while (!eof()) { - auto token = peek(); - if (token.type() != Token::Type::DoubleQuotedString && token.type() != Token::Type::SingleQuotedString && token.type() != Token::Type::EscapeSequence) { - VERIFY(start_token_index.has_value()); - end_token_index = m_state.token_index - 1; - break; - } - if (!start_token_index.has_value()) - start_token_index = m_state.token_index; - consume(); - } - - // String was not terminated - if (!end_token_index.has_value()) { - end_token_index = m_tokens.size() - 1; - } - - VERIFY(start_token_index.has_value()); - VERIFY(end_token_index.has_value()); - - Token start_token = m_tokens[start_token_index.value()]; - Token end_token = m_tokens[end_token_index.value()]; - - auto text = text_in_range(start_token.start(), end_token.end()); - auto string_literal = create_ast_node(parent, start_token.start(), end_token.end()); - string_literal->set_value(move(text)); - return string_literal; -} - -NonnullRefPtr Parser::parse_return_statement(ASTNode const& parent) -{ - LOG_SCOPE(); - auto return_statement = create_ast_node(parent, position(), {}); - consume(Token::Type::Keyword); - if (!peek(Token::Type::Semicolon).has_value()) { - return_statement->set_value(parse_expression(*return_statement)); - } - return_statement->set_end(position()); - return return_statement; -} - -NonnullRefPtr Parser::parse_enum_declaration(ASTNode const& parent) -{ - LOG_SCOPE(); - auto enum_decl = create_ast_node(parent, position(), {}); - consume_keyword("enum"); - - if (match_keyword("class")) { - consume(Token::Type::Keyword); - enum_decl->set_type(EnumDeclaration::Type::EnumClass); - } else { - enum_decl->set_type(EnumDeclaration::Type::RegularEnum); - } - - auto name = parse_name(*enum_decl); - enum_decl->set_name(name); - consume(Token::Type::LeftCurly); - while (!eof() && peek().type() != Token::Type::RightCurly) { - auto name = text_of_token(consume(Token::Type::Identifier)); - RefPtr value; - if (peek().type() == Token::Type::Equals) { - consume(); - value = parse_expression(enum_decl); - } - enum_decl->add_entry(name, move(value)); - if (peek().type() != Token::Type::Comma) { - break; - } - consume(Token::Type::Comma); - } - consume(Token::Type::RightCurly); - consume(Token::Type::Semicolon); - enum_decl->set_end(position()); - return enum_decl; -} - -Token Parser::consume_keyword(ByteString const& keyword) -{ - auto token = consume(); - if (token.type() != Token::Type::Keyword) { - error(ByteString::formatted("unexpected token: {}, expected Keyword", token.to_byte_string())); - return token; - } - if (text_of_token(token) != keyword) { - error(ByteString::formatted("unexpected keyword: {}, expected {}", text_of_token(token), keyword)); - return token; - } - return token; -} - -bool Parser::match_keyword(ByteString const& keyword) -{ - auto token = peek(); - if (token.type() != Token::Type::Keyword) { - return false; - } - if (text_of_token(token) != keyword) { - return false; - } - return true; -} - -NonnullRefPtr Parser::parse_class_declaration(ASTNode const& parent) -{ - LOG_SCOPE(); - - auto type_token = consume(Token::Type::Keyword); - StructOrClassDeclaration::Type type {}; - - if (type_token.text() == "struct") - type = StructOrClassDeclaration::Type::Struct; - if (type_token.text() == "class") - type = StructOrClassDeclaration::Type::Class; - - auto decl = create_ast_node(parent, position(), {}, type); - - auto name = parse_name(*decl); - decl->set_name(name); - - auto has_final = match_keyword("final"); - - Vector> baseclasses; - - // FIXME: Don't ignore this. - if (peek(has_final ? 1 : 0).type() == Token::Type::Colon) { - if (has_final) - consume(); - - do { - consume(); - - while (match_keyword("private") || match_keyword("public") || match_keyword("protected") || match_keyword("virtual")) - consume(); - - baseclasses.append(parse_name(*decl)); - } while (peek().type() == Token::Type::Comma); - } - - decl->set_baseclasses(move(baseclasses)); - - consume(Token::Type::LeftCurly); - - while (!eof() && peek().type() != Token::Type::RightCurly) { - decl->set_members(parse_class_members(*decl)); - } - - consume(Token::Type::RightCurly); - consume(Token::Type::Semicolon); - decl->set_end(position()); - return decl; -} - -NonnullRefPtr Parser::parse_boolean_literal(ASTNode const& parent) -{ - LOG_SCOPE(); - auto token = consume(Token::Type::Keyword); - auto text = text_of_token(token); - // text == "true" || text == "false"; - bool value = (text == "true"); - return create_ast_node(parent, token.start(), token.end(), value); -} - -bool Parser::match_boolean_literal() -{ - auto token = peek(); - if (token.type() != Token::Type::Keyword) - return false; - auto text = text_of_token(token); - return text == "true" || text == "false"; -} - -NonnullRefPtr Parser::parse_type(ASTNode const& parent) -{ - LOG_SCOPE(); - - if (!match_named_type()) { - error("expected named named_type"sv); - auto token = consume(); - return create_ast_node(parent, token.start(), token.end()); - } - - auto named_type = create_ast_node(parent, position(), {}); - - auto qualifiers = parse_type_qualifiers(); - named_type->set_qualifiers(move(qualifiers)); - - if (match_keyword("auto")) { - consume(Token::Type::Keyword); - named_type->set_auto(true); - auto original_qualifiers = named_type->qualifiers(); - original_qualifiers.extend(parse_type_qualifiers()); - named_type->set_qualifiers(move(original_qualifiers)); - named_type->set_end(position()); - return named_type; - } - - if (match_keyword("struct")) { - consume(Token::Type::Keyword); // Consume struct prefix - } - - if (!match_name()) { - named_type->set_end(position()); - error(ByteString::formatted("expected name instead of: {}", peek().text())); - return named_type; - } - named_type->set_name(parse_name(*named_type)); - - auto original_qualifiers = named_type->qualifiers(); - original_qualifiers.extend(parse_type_qualifiers()); - named_type->set_qualifiers(move(original_qualifiers)); - - NonnullRefPtr type = named_type; - while (!eof() && peek().type() == Token::Type::Asterisk) { - type->set_end(position()); - auto asterisk = consume(); - auto ptr = create_ast_node(parent, type->start(), asterisk.end()); - type->set_parent(*ptr); - ptr->set_pointee(type); - ptr->set_qualifiers(parse_type_qualifiers()); - ptr->set_end(position()); - type = ptr; - } - - if (!eof() && (peek().type() == Token::Type::And || peek().type() == Token::Type::AndAnd)) { - type->set_end(position()); - auto ref_token = consume(); - auto ref = create_ast_node(parent, type->start(), ref_token.end(), ref_token.type() == Token::Type::And ? Reference::Kind::Lvalue : Reference::Kind::Rvalue); - type->set_parent(*ref); - ref->set_referenced_type(type); - ref->set_end(position()); - type = ref; - } - - if (peek().type() == Token::Type::LeftParen) { - type->set_end(previous_token_end()); - consume(); - auto fn_type = create_ast_node(parent, type->start(), position()); - fn_type->set_return_type(*type); - type->set_parent(*fn_type); - if (auto parameters = parse_parameter_list(*type); parameters.has_value()) - fn_type->set_parameters(parameters.release_value()); - consume(Token::Type::RightParen); - type = fn_type; - } - - type->set_end(previous_token_end()); - - return type; -} - -NonnullRefPtr Parser::parse_for_statement(ASTNode const& parent) -{ - LOG_SCOPE(); - auto for_statement = create_ast_node(parent, position(), {}); - consume(Token::Type::Keyword); - consume(Token::Type::LeftParen); - if (peek().type() != Token::Type::Semicolon) - for_statement->set_init(parse_variable_declaration(*for_statement, false)); - consume(Token::Type::Semicolon); - - if (peek().type() != Token::Type::Semicolon) - for_statement->set_test(parse_expression(*for_statement)); - consume(Token::Type::Semicolon); - - if (peek().type() != Token::Type::RightParen) - for_statement->set_update(parse_expression(*for_statement)); - consume(Token::Type::RightParen); - - for_statement->set_body(parse_statement(*for_statement)); - - for_statement->set_end(for_statement->body()->end()); - return for_statement; -} - -NonnullRefPtr Parser::parse_if_statement(ASTNode const& parent) -{ - LOG_SCOPE(); - auto if_statement = create_ast_node(parent, position(), {}); - consume(Token::Type::Keyword); - consume(Token::Type::LeftParen); - if_statement->set_predicate(parse_expression(*if_statement)); - consume(Token::Type::RightParen); - if_statement->set_then_statement(parse_statement(*if_statement)); - if (match_keyword("else")) { - consume(Token::Type::Keyword); - if_statement->set_else_statement(parse_statement(*if_statement)); - if_statement->set_end(if_statement->else_statement()->end()); - } else { - if_statement->set_end(if_statement->then_statement()->end()); - } - return if_statement; -} -Vector Parser::parse_type_qualifiers() -{ - LOG_SCOPE(); - Vector qualifiers; - while (!eof()) { - auto token = peek(); - if (token.type() != Token::Type::Keyword) - break; - auto text = text_of_token(token); - if (text == "static" || text == "const" || text == "extern") { - qualifiers.append(text); - consume(); - } else { - break; - } - } - return qualifiers; -} - -Vector Parser::parse_function_qualifiers() -{ - LOG_SCOPE(); - Vector qualifiers; - while (!eof()) { - auto token = peek(); - if (token.type() != Token::Type::Keyword) - break; - auto text = text_of_token(token); - if (text == "static" || text == "inline" || text == "extern" || text == "virtual") { - qualifiers.append(text); - consume(); - } else { - break; - } - } - return qualifiers; -} - -bool Parser::match_attribute_specification() -{ - return text_of_token(peek()) == "__attribute__"; -} -void Parser::consume_attribute_specification() -{ - consume(); // __attribute__ - consume(Token::Type::LeftParen); - size_t left_count = 1; - while (!eof()) { - auto token = consume(); - if (token.type() == Token::Type::LeftParen) { - ++left_count; - } - if (token.type() == Token::Type::RightParen) { - --left_count; - } - if (left_count == 0) - return; - } -} - -bool Parser::match_ellipsis() -{ - if (m_state.token_index > m_tokens.size() - 3) - return false; - return peek().type() == Token::Type::Dot && peek(1).type() == Token::Type::Dot && peek(2).type() == Token::Type::Dot; -} - -NonnullRefPtr Parser::parse_namespace_declaration(ASTNode const& parent, bool is_nested_namespace) -{ - auto namespace_decl = create_ast_node(parent, position(), {}); - - if (!is_nested_namespace) - consume(Token::Type::Keyword); - - auto name = parse_name(*namespace_decl); - namespace_decl->set_name(name); - - if (peek().type() == Token::Type::ColonColon) { - consume(Token::Type::ColonColon); - namespace_decl->add_declaration(parse_namespace_declaration(*namespace_decl, true)); - namespace_decl->set_end(position()); - return namespace_decl; - } - - consume(Token::Type::LeftCurly); - while (!eof() && peek().type() != Token::Type::RightCurly) { - auto declaration = parse_single_declaration_in_translation_unit(*namespace_decl); - if (declaration) { - namespace_decl->add_declaration(declaration.release_nonnull()); - } else { - error("unexpected token"sv); - consume(); - } - } - consume(Token::Type::RightCurly); - namespace_decl->set_end(position()); - return namespace_decl; -} - -bool Parser::match_name() -{ - auto type = peek().type(); - return type == Token::Type::Identifier || type == Token::Type::KnownType; -} - -NonnullRefPtr Parser::parse_name(ASTNode const& parent) -{ - LOG_SCOPE(); - NonnullRefPtr name_node = create_ast_node(parent, position(), {}); - while (!eof() && (peek().type() == Token::Type::Identifier || peek().type() == Token::Type::KnownType) && peek(1).type() == Token::Type::ColonColon) { - auto token = consume(); - name_node->add_to_scope(create_ast_node(*name_node, token.start(), token.end(), token.text())); - consume(Token::Type::ColonColon); - } - - if (peek().type() == Token::Type::Identifier || peek().type() == Token::Type::KnownType) { - auto token = consume(); - name_node->set_name(create_ast_node(*name_node, token.start(), token.end(), token.text())); - } else { - name_node->set_end(position()); - return name_node; - } - - bool is_templatized = false; - if (match_template_arguments()) { - is_templatized = true; - consume(Token::Type::Less); - NonnullRefPtr templatized_name = create_ast_node(parent, name_node->start(), {}); - templatized_name->set_name(name_node->name()); - templatized_name->set_scope(name_node->scope()); - name_node->set_end(position()); - name_node = templatized_name; - while (peek().type() != Token::Type::Greater && !eof()) { - templatized_name->add_template_argument(parse_type(*templatized_name)); - if (peek().type() == Token::Type::Comma) - consume(Token::Type::Comma); - } - consume(Token::Type::Greater); - } - - if (!is_templatized && (peek().type() == Token::Type::LeftBracket)) { - NonnullRefPtr sized_name = create_ast_node(parent, name_node->start(), {}); - sized_name->set_name(name_node->name()); - sized_name->set_scope(name_node->scope()); - - while (peek().type() == Token::Type::LeftBracket) { - consume(Token::Type::LeftBracket); - - StringView size = "0"sv; - if (peek().type() == Token::Type::Integer) { - auto token = consume(Token::Type::Integer); - size = token.text(); - } - sized_name->append_dimension(size); - - consume(Token::Type::RightBracket); - } - name_node->set_end(position()); - name_node = sized_name; - } - - name_node->set_end(previous_token_end()); - return name_node; -} - -bool Parser::match_cpp_cast_expression() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - auto token = consume(); - if (token.type() != Token::Type::Keyword) - return false; - - auto text = token.text(); - if (text == "static_cast" || text == "reinterpret_cast" || text == "dynamic_cast" || text == "const_cast") - return true; - return false; -} - -bool Parser::match_c_style_cast_expression() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (consume().type() != Token::Type::LeftParen) - return false; - - if (!match_type()) - return false; - (void)parse_type(get_dummy_node()); - - if (consume().type() != Token::Type::RightParen) - return false; - - if (!match_expression()) - return false; - - return true; -} - -NonnullRefPtr Parser::parse_c_style_cast_expression(ASTNode const& parent) -{ - auto parse_exp = create_ast_node(parent, position(), {}); - - consume(Token::Type::LeftParen); - parse_exp->set_type(parse_type(*parse_exp)); - consume(Token::Type::RightParen); - parse_exp->set_expression(parse_expression(*parse_exp)); - parse_exp->set_end(position()); - - return parse_exp; -} - -NonnullRefPtr Parser::parse_cpp_cast_expression(ASTNode const& parent) -{ - auto cast_expression = create_ast_node(parent, position(), {}); - - cast_expression->set_cast_type(consume(Token::Type::Keyword).text()); - - consume(Token::Type::Less); - cast_expression->set_type(parse_type(*cast_expression)); - consume(Token::Type::Greater); - - consume(Token::Type::LeftParen); - cast_expression->set_expression(parse_expression(*cast_expression)); - consume(Token::Type::RightParen); - - cast_expression->set_end(position()); - - return cast_expression; -} - -bool Parser::match_sizeof_expression() -{ - return match_keyword("sizeof"); -} - -NonnullRefPtr Parser::parse_sizeof_expression(ASTNode const& parent) -{ - auto exp = create_ast_node(parent, position(), {}); - consume(Token::Type::Keyword); - consume(Token::Type::LeftParen); - exp->set_type(parse_type(parent)); - consume(Token::Type::RightParen); - exp->set_end(position()); - return exp; -} - -bool Parser::match_braced_init_list() -{ - return match(Token::Type::LeftCurly); -} - -NonnullRefPtr Parser::parse_braced_init_list(ASTNode const& parent) -{ - auto init_list = create_ast_node(parent, position(), {}); - - consume(Token::Type::LeftCurly); - while (!eof() && peek().type() != Token::Type::RightCurly) { - init_list->add_expression(parse_expression(*init_list)); - if (peek().type() == Token::Type::Comma) - consume(Token::Type::Comma); - } - consume(Token::Type::RightCurly); - init_list->set_end(position()); - return init_list; -} -Vector> Parser::parse_class_members(StructOrClassDeclaration& parent) -{ - auto class_name = parent.full_name(); - - Vector> members; - while (!eof() && peek().type() != Token::Type::RightCurly) { - if (match_access_specifier()) - consume_access_specifier(); // FIXME: Do not ignore access specifiers - auto member_type = match_class_member(class_name); - if (member_type.has_value()) { - members.append(parse_declaration(parent, member_type.value())); - } else { - error("Expected class member"sv); - consume(); - } - } - return members; -} - -bool Parser::match_access_specifier() -{ - if (peek(1).type() != Token::Type::Colon) - return false; - - return match_keyword("private") || match_keyword("protected") || match_keyword("public"); -} - -void Parser::consume_access_specifier() -{ - consume(Token::Type::Keyword); - consume(Token::Type::Colon); -} - -bool Parser::match_constructor(StringView class_name) -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - auto token = consume(); - if (token.text() != class_name) - return false; - - if (!peek(Token::Type::LeftParen).has_value()) - return false; - consume(); - - while (consume().type() != Token::Type::RightParen && !eof()) { }; - - return (peek(Token::Type::Semicolon).has_value() || peek(Token::Type::LeftCurly).has_value()); -} - -bool Parser::match_destructor(StringView class_name) -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (match_keyword("virtual")) - consume(); - - if (!match(Token::Type::Tilde)) - return false; - consume(); - - auto token = peek(); - - if (token.text() != class_name) - return false; - consume(); - - if (!peek(Token::Type::LeftParen).has_value()) - return false; - consume(); - - while (consume().type() != Token::Type::RightParen && !eof()) { }; - - if (match_keyword("override")) - consume(); - - return (peek(Token::Type::Semicolon).has_value() || peek(Token::Type::LeftCurly).has_value()); -} - -void Parser::parse_constructor_or_destructor_impl(FunctionDeclaration& func, CtorOrDtor type) -{ - if (type == CtorOrDtor::Dtor) { - if (match_keyword("virtual")) - func.set_qualifiers({ consume().text() }); - consume(Token::Type::Tilde); - } - - auto name = parse_name(func); - func.set_name(name); - - consume(Token::Type::LeftParen); - auto parameters = parse_parameter_list(func); - if (parameters.has_value()) { - if (type == CtorOrDtor::Dtor && !parameters->is_empty()) - error("Destructor declaration that takes parameters"sv); - else - func.set_parameters(parameters.value()); - } - - consume(Token::Type::RightParen); - - if (type == CtorOrDtor::Dtor && match_keyword("override")) - consume(); - - // TODO: Parse =default, =delete. - - RefPtr body; - Position ctor_end {}; - if (peek(Token::Type::LeftCurly).has_value()) { - body = parse_function_definition(func); - ctor_end = body->end(); - } else { - ctor_end = position(); - if (match_attribute_specification()) - consume_attribute_specification(); // we don't use the value of __attribute__ - consume(Token::Type::Semicolon); - } - - func.set_definition(move(body)); - func.set_end(ctor_end); -} - -NonnullRefPtr Parser::parse_constructor(ASTNode const& parent) -{ - auto ctor = create_ast_node(parent, position(), {}); - parse_constructor_or_destructor_impl(*ctor, CtorOrDtor::Ctor); - return ctor; -} - -NonnullRefPtr Parser::parse_destructor(ASTNode const& parent) -{ - auto ctor = create_ast_node(parent, position(), {}); - parse_constructor_or_destructor_impl(*ctor, CtorOrDtor::Dtor); - return ctor; -} - -bool Parser::match_using_namespace_declaration() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (!match_keyword("using")) - return false; - consume(); - - if (!match_keyword("namespace")) - return false; - consume(); - - return true; -} - -bool Parser::match_using_type_declaration() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (!match_keyword("using")) - return false; - consume(); - - if (!match(Token::Type::Identifier)) - return false; - - return true; -} - -bool Parser::match_typedef_declaration() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (!match_keyword("typedef")) - return false; - consume(); - - // FIXME: typedef void (*fn)() - - if (!match_type()) - return false; - - if (!match(Token::Type::Identifier)) - return false; - - return true; -} - -NonnullRefPtr Parser::parse_using_namespace_declaration(ASTNode const& parent) -{ - auto decl = create_ast_node(parent, position(), {}); - - consume_keyword("using"); - consume_keyword("namespace"); - - auto name = parse_name(*decl); - - decl->set_end(position()); - consume(Token::Type::Semicolon); - - decl->set_name(name); - - return decl; -} - -NonnullRefPtr Parser::parse_typedef_declaration(Cpp::ASTNode const& parent) -{ - auto decl = create_ast_node(parent, position(), {}); - - consume_keyword("typedef"); - - auto type = parse_type(*decl); - decl->set_alias(type); - - auto name = parse_name(*decl); - decl->set_name(name); - - decl->set_end(position()); - consume(Token::Type::Semicolon); - - return decl; -} - -NonnullRefPtr Parser::parse_using_type_declaration(Cpp::ASTNode const& parent) -{ - auto decl = create_ast_node(parent, position(), {}); - - // FIXME: These can also be templated. - consume_keyword("using"); - - auto name = parse_name(*decl); - decl->set_name(name); - - if (match(Token::Type::Equals)) { - consume(); - auto type = parse_type(*decl); - decl->set_alias(type); - } - - decl->set_end(position()); - consume(Token::Type::Semicolon); - - return decl; -} - -} diff --git a/Userland/Libraries/LibCpp/Parser.h b/Userland/Libraries/LibCpp/Parser.h deleted file mode 100644 index 1f0d6d65343..00000000000 --- a/Userland/Libraries/LibCpp/Parser.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Cpp { - -class Parser final { - AK_MAKE_NONCOPYABLE(Parser); - -public: - explicit Parser(Vector tokens, ByteString const& filename); - ~Parser() = default; - - NonnullRefPtr parse(); - bool eof() const; - - RefPtr node_at(Position) const; - Optional index_of_node_at(Position) const; - Optional token_at(Position) const; - Optional index_of_token_at(Position) const; - RefPtr root_node() const { return m_root_node; } - ByteString text_of_node(ASTNode const&) const; - StringView text_of_token(Cpp::Token const& token) const; - void print_tokens() const; - Vector const& tokens() const { return m_tokens; } - Vector const& errors() const { return m_errors; } - - Vector get_todo_entries() const; - - Vector tokens_in_range(Position start, Position end) const; - -private: - enum class DeclarationType { - Function, - Variable, - Enum, - Class, - Namespace, - Constructor, - Destructor, - UsingNamespace, - Typedef, - UsingType, - }; - - Optional match_declaration_in_translation_unit(); - Optional match_class_member(StringView class_name); - - bool match_function_declaration(); - bool match_comment(); - bool match_preprocessor(); - bool match_whitespace(); - bool match_variable_declaration(); - bool match_expression(); - bool match_secondary_expression(); - bool match_enum_declaration(); - bool match_class_declaration(); - bool match_literal(); - bool match_unary_expression(); - bool match_boolean_literal(); - bool match_keyword(ByteString const&); - bool match_block_statement(); - bool match_namespace_declaration(); - bool match_template_arguments(); - bool match_name(); - bool match_cpp_cast_expression(); - bool match_c_style_cast_expression(); - bool match_sizeof_expression(); - bool match_braced_init_list(); - bool match_type(); - bool match_named_type(); - bool match_access_specifier(); - bool match_constructor(StringView class_name); - bool match_destructor(StringView class_name); - bool match_using_namespace_declaration(); - bool match_typedef_declaration(); - bool match_using_type_declaration(); - - Optional>> parse_parameter_list(ASTNode const& parent); - Optional consume_whitespace(); - void consume_preprocessor(); - - NonnullRefPtr parse_declaration(ASTNode const& parent, DeclarationType); - NonnullRefPtr parse_function_declaration(ASTNode const& parent); - NonnullRefPtr parse_function_definition(ASTNode const& parent); - NonnullRefPtr parse_statement(ASTNode const& parent); - NonnullRefPtr parse_variable_declaration(ASTNode const& parent, bool expect_semicolon = true); - NonnullRefPtr parse_expression(ASTNode const& parent); - NonnullRefPtr parse_primary_expression(ASTNode const& parent); - NonnullRefPtr parse_secondary_expression(ASTNode const& parent, NonnullRefPtr lhs); - NonnullRefPtr parse_string_literal(ASTNode const& parent); - NonnullRefPtr parse_return_statement(ASTNode const& parent); - NonnullRefPtr parse_enum_declaration(ASTNode const& parent); - NonnullRefPtr parse_class_declaration(ASTNode const& parent); - NonnullRefPtr parse_literal(ASTNode const& parent); - NonnullRefPtr parse_unary_expression(ASTNode const& parent); - NonnullRefPtr parse_boolean_literal(ASTNode const& parent); - NonnullRefPtr parse_type(ASTNode const& parent); - NonnullRefPtr parse_binary_expression(ASTNode const& parent, NonnullRefPtr lhs, BinaryOp); - NonnullRefPtr parse_assignment_expression(ASTNode const& parent, NonnullRefPtr lhs, AssignmentOp); - NonnullRefPtr parse_for_statement(ASTNode const& parent); - NonnullRefPtr parse_block_statement(ASTNode const& parent); - NonnullRefPtr parse_comment(ASTNode const& parent); - NonnullRefPtr parse_if_statement(ASTNode const& parent); - NonnullRefPtr parse_namespace_declaration(ASTNode const& parent, bool is_nested_namespace = false); - Vector> parse_declarations_in_translation_unit(ASTNode const& parent); - RefPtr parse_single_declaration_in_translation_unit(ASTNode const& parent); - Vector> parse_template_arguments(ASTNode const& parent); - NonnullRefPtr parse_name(ASTNode const& parent); - NonnullRefPtr parse_cpp_cast_expression(ASTNode const& parent); - NonnullRefPtr parse_sizeof_expression(ASTNode const& parent); - NonnullRefPtr parse_braced_init_list(ASTNode const& parent); - NonnullRefPtr parse_c_style_cast_expression(ASTNode const& parent); - Vector> parse_class_members(StructOrClassDeclaration& parent); - NonnullRefPtr parse_constructor(ASTNode const& parent); - NonnullRefPtr parse_destructor(ASTNode const& parent); - NonnullRefPtr parse_using_namespace_declaration(ASTNode const& parent); - NonnullRefPtr parse_typedef_declaration(ASTNode const& parent); - NonnullRefPtr parse_using_type_declaration(ASTNode const& parent); - - bool match(Token::Type); - Token consume(Token::Type); - Token consume(); - Token consume_keyword(ByteString const&); - Token peek(size_t offset = 0) const; - Optional peek(Token::Type) const; - Position position() const; - Position previous_token_end() const; - ByteString text_in_range(Position start, Position end) const; - - void save_state(); - void load_state(); - - struct State { - size_t token_index { 0 }; - Vector> state_nodes; - }; - - void error(StringView message = {}); - - template - NonnullRefPtr - create_ast_node(ASTNode const& parent, Position const& start, Optional end, Args&&... args) - { - auto node = adopt_ref(*new T(&parent, start, end, m_filename, forward(args)...)); - - if (m_saved_states.is_empty()) { - m_nodes.append(node); - } else { - m_state.state_nodes.append(node); - } - - return node; - } - - NonnullRefPtr - create_root_ast_node(Position const& start, Position end) - { - auto node = adopt_ref(*new TranslationUnit(nullptr, start, end, m_filename)); - m_nodes.append(node); - m_root_node = node; - return node; - } - - DummyAstNode& get_dummy_node() - { - static NonnullRefPtr dummy = adopt_ref(*new DummyAstNode(nullptr, {}, {}, {})); - return dummy; - } - - bool match_attribute_specification(); - void consume_attribute_specification(); - void consume_access_specifier(); - bool match_ellipsis(); - Vector parse_type_qualifiers(); - Vector parse_function_qualifiers(); - - enum class CtorOrDtor { - Ctor, - Dtor, - }; - void parse_constructor_or_destructor_impl(FunctionDeclaration&, CtorOrDtor); - - ByteString m_filename; - Vector m_tokens; - State m_state; - Vector m_saved_states; - RefPtr m_root_node; - Vector m_errors; - Vector> m_nodes; -}; - -} diff --git a/Userland/Libraries/LibCpp/Preprocessor.cpp b/Userland/Libraries/LibCpp/Preprocessor.cpp deleted file mode 100644 index 2de36a47b48..00000000000 --- a/Userland/Libraries/LibCpp/Preprocessor.cpp +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Preprocessor.h" -#include -#include -#include -#include -#include - -namespace Cpp { -Preprocessor::Preprocessor(ByteString const& filename, StringView program) - : m_filename(filename) - , m_program(program) -{ -} - -Vector Preprocessor::process_and_lex() -{ - Lexer lexer { m_program }; - lexer.set_ignore_whitespace(true); - auto tokens = lexer.lex(); - - m_unprocessed_tokens = tokens; - - for (size_t token_index = 0; token_index < tokens.size(); ++token_index) { - auto& token = tokens[token_index]; - m_current_line = token.start().line; - if (token.type() == Token::Type::PreprocessorStatement) { - handle_preprocessor_statement(token.text()); - m_processed_tokens.append(tokens[token_index]); - continue; - } - - if (m_state != State::Normal) - continue; - - if (token.type() == Token::Type::IncludeStatement) { - if (token_index >= tokens.size() - 1 || tokens[token_index + 1].type() != Token::Type::IncludePath) - continue; - handle_include_statement(tokens[token_index + 1].text()); - if (m_options.keep_include_statements) { - m_processed_tokens.append(tokens[token_index]); - m_processed_tokens.append(tokens[token_index + 1]); - } - ++token_index; // Also skip IncludePath token - continue; - } - - if (token.type() == Token::Type::Identifier) { - if (auto defined_value = m_definitions.find(token.text()); defined_value != m_definitions.end()) { - auto last_substituted_token_index = do_substitution(tokens, token_index, defined_value->value); - token_index = last_substituted_token_index; - continue; - } - } - - m_processed_tokens.append(token); - } - - return m_processed_tokens; -} - -static void consume_whitespace(GenericLexer& lexer) -{ - auto ignore_line = [&] { - for (;;) { - if (lexer.consume_specific("\\\n"sv)) { - lexer.ignore(2); - } else { - lexer.ignore_until('\n'); - lexer.ignore(); - break; - } - } - }; - for (;;) { - if (lexer.consume_specific("//"sv)) { - ignore_line(); - } else if (lexer.consume_specific("/*"sv)) { - lexer.ignore_until("*/"); - lexer.ignore(2); - } else if (lexer.next_is("\\\n"sv)) { - lexer.ignore(2); - } else if (lexer.is_eof() || !lexer.next_is(isspace)) { - break; - } else { - lexer.ignore(); - } - } -} - -void Preprocessor::handle_preprocessor_statement(StringView line) -{ - GenericLexer lexer(line); - - consume_whitespace(lexer); - lexer.consume_specific('#'); - consume_whitespace(lexer); - auto keyword = lexer.consume_until(' '); - lexer.ignore(); - if (keyword.is_empty() || keyword.is_whitespace()) - return; - - handle_preprocessor_keyword(keyword, lexer); -} - -void Preprocessor::handle_include_statement(StringView include_path) -{ - m_included_paths.append(include_path); - if (definitions_in_header_callback) { - for (auto& def : definitions_in_header_callback(include_path)) - m_definitions.set(def.key, def.value); - } -} - -void Preprocessor::handle_preprocessor_keyword(StringView keyword, GenericLexer& line_lexer) -{ - if (keyword == "include") { - // Should have called 'handle_include_statement'. - VERIFY_NOT_REACHED(); - } - - if (keyword == "else") { - if (m_options.ignore_invalid_statements && m_current_depth == 0) - return; - VERIFY(m_current_depth > 0); - if (m_depths_of_not_taken_branches.contains_slow(m_current_depth - 1)) { - m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth - 1; }); - m_state = State::Normal; - } - if (m_depths_of_taken_branches.contains_slow(m_current_depth - 1)) { - m_state = State::SkipElseBranch; - } - return; - } - - if (keyword == "endif") { - if (m_options.ignore_invalid_statements && m_current_depth == 0) - return; - VERIFY(m_current_depth > 0); - --m_current_depth; - if (m_depths_of_not_taken_branches.contains_slow(m_current_depth)) { - m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth; }); - } - if (m_depths_of_taken_branches.contains_slow(m_current_depth)) { - m_depths_of_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth; }); - } - m_state = State::Normal; - return; - } - - if (keyword == "define") { - if (m_state == State::Normal) { - auto definition = create_definition(line_lexer.consume_all()); - if (definition.has_value()) - m_definitions.set(definition->key, *definition); - } - return; - } - if (keyword == "undef") { - if (m_state == State::Normal) { - auto key = line_lexer.consume_until(' '); - line_lexer.consume_all(); - m_definitions.remove(key); - } - return; - } - if (keyword == "ifdef") { - ++m_current_depth; - if (m_state == State::Normal) { - auto key = line_lexer.consume_until(' '); - line_lexer.ignore(); - if (m_definitions.contains(key)) { - m_depths_of_taken_branches.append(m_current_depth - 1); - return; - } else { - m_depths_of_not_taken_branches.append(m_current_depth - 1); - m_state = State::SkipIfBranch; - return; - } - } - return; - } - if (keyword == "ifndef") { - ++m_current_depth; - if (m_state == State::Normal) { - auto key = line_lexer.consume_until(' '); - line_lexer.ignore(); - if (!m_definitions.contains(key)) { - m_depths_of_taken_branches.append(m_current_depth - 1); - return; - } else { - m_depths_of_not_taken_branches.append(m_current_depth - 1); - m_state = State::SkipIfBranch; - return; - } - } - return; - } - if (keyword == "if") { - ++m_current_depth; - if (m_state == State::Normal) { - // FIXME: Implement #if logic - // We currently always take #if branches. - m_depths_of_taken_branches.append(m_current_depth - 1); - } - return; - } - - if (keyword == "elif") { - if (m_options.ignore_invalid_statements && m_current_depth == 0) - return; - VERIFY(m_current_depth > 0); - // FIXME: Evaluate the elif expression - // We currently always treat the expression in #elif as true. - if (m_depths_of_not_taken_branches.contains_slow(m_current_depth - 1) /* && should_take*/) { - m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth - 1; }); - m_state = State::Normal; - } - if (m_depths_of_taken_branches.contains_slow(m_current_depth - 1)) { - m_state = State::SkipElseBranch; - } - return; - } - if (keyword == "pragma") { - line_lexer.consume_all(); - return; - } - if (keyword == "error") { - line_lexer.consume_all(); - return; - } - - if (!m_options.ignore_unsupported_keywords) { - dbgln("Unsupported preprocessor keyword: {}", keyword); - VERIFY_NOT_REACHED(); - } -} - -size_t Preprocessor::do_substitution(Vector const& tokens, size_t token_index, Definition const& defined_value) -{ - if (defined_value.value.is_empty()) - return token_index; - - Substitution sub; - sub.defined_value = defined_value; - - auto macro_call = parse_macro_call(tokens, token_index); - - if (!macro_call.has_value()) - return token_index; - - Vector original_tokens; - for (size_t i = token_index; i <= macro_call->end_token_index; ++i) { - original_tokens.append(tokens[i]); - } - VERIFY(!original_tokens.is_empty()); - - auto processed_value = evaluate_macro_call(*macro_call, defined_value); - m_substitutions.append({ original_tokens, defined_value, processed_value }); - - Lexer lexer(processed_value); - lexer.lex_iterable([&](auto token) { - if (token.type() == Token::Type::Whitespace) - return; - token.set_start(original_tokens.first().start()); - token.set_end(original_tokens.first().end()); - m_processed_tokens.append(token); - }); - return macro_call->end_token_index; -} - -Optional Preprocessor::parse_macro_call(Vector const& tokens, size_t token_index) -{ - auto name = tokens[token_index]; - ++token_index; - - if (token_index >= tokens.size() || tokens[token_index].type() != Token::Type::LeftParen) - return MacroCall { name, {}, token_index - 1 }; - ++token_index; - - Vector arguments; - Optional current_argument; - - size_t paren_depth = 1; - for (; token_index < tokens.size(); ++token_index) { - auto& token = tokens[token_index]; - if (token.type() == Token::Type::LeftParen) - ++paren_depth; - if (token.type() == Token::Type::RightParen) - --paren_depth; - - if (paren_depth == 0) { - if (current_argument.has_value()) - arguments.append(*current_argument); - break; - } - - if (paren_depth == 1 && token.type() == Token::Type::Comma) { - if (current_argument.has_value()) - arguments.append(*current_argument); - current_argument = {}; - } else { - if (!current_argument.has_value()) - current_argument = MacroCall::Argument {}; - current_argument->tokens.append(token); - } - } - - if (token_index >= tokens.size()) - return {}; - - return MacroCall { name, move(arguments), token_index }; -} - -Optional Preprocessor::create_definition(StringView line) -{ - Lexer lexer { line }; - lexer.set_ignore_whitespace(true); - auto tokens = lexer.lex(); - if (tokens.is_empty()) - return {}; - - if (tokens.first().type() != Token::Type::Identifier) - return {}; - - Definition definition; - definition.filename = m_filename; - definition.line = m_current_line; - - definition.key = tokens.first().text(); - - if (tokens.size() == 1) - return definition; - - size_t token_index = 1; - // Parse macro parameters (if any) - if (tokens[token_index].type() == Token::Type::LeftParen) { - ++token_index; - while (token_index < tokens.size() && tokens[token_index].type() != Token::Type::RightParen) { - auto param = tokens[token_index]; - if (param.type() != Token::Type::Identifier) - return {}; - - if (token_index + 1 >= tokens.size()) - return {}; - - ++token_index; - - if (tokens[token_index].type() == Token::Type::Comma) - ++token_index; - else if (tokens[token_index].type() != Token::Type::RightParen) - return {}; - - definition.parameters.empend(param.text()); - } - if (token_index >= tokens.size()) - return {}; - ++token_index; - } - - if (token_index < tokens.size()) - definition.value = remove_escaped_newlines(line.substring_view(tokens[token_index].start().column)); - - return definition; -} - -ByteString Preprocessor::remove_escaped_newlines(StringView value) -{ - static constexpr auto escaped_newline = "\\\n"sv; - AK::StringBuilder processed_value; - GenericLexer lexer { value }; - while (!lexer.is_eof()) { - processed_value.append(lexer.consume_until(escaped_newline)); - lexer.ignore(escaped_newline.length()); - } - return processed_value.to_byte_string(); -} - -ByteString Preprocessor::evaluate_macro_call(MacroCall const& macro_call, Definition const& definition) -{ - if (macro_call.arguments.size() != definition.parameters.size()) { - dbgln("mismatch in # of arguments for macro call: {}", macro_call.name.text()); - return {}; - } - - Lexer lexer { definition.value }; - StringBuilder processed_value; - lexer.lex_iterable([&](auto token) { - if (token.type() != Token::Type::Identifier) { - processed_value.append(token.text()); - return; - } - - auto param_index = definition.parameters.find_first_index(token.text()); - if (!param_index.has_value()) { - processed_value.append(token.text()); - return; - } - - auto& argument = macro_call.arguments[*param_index]; - for (auto& arg_token : argument.tokens) { - processed_value.append(arg_token.text()); - } - }); - - return processed_value.to_byte_string(); -} - -}; diff --git a/Userland/Libraries/LibCpp/Preprocessor.h b/Userland/Libraries/LibCpp/Preprocessor.h deleted file mode 100644 index 337c40d7090..00000000000 --- a/Userland/Libraries/LibCpp/Preprocessor.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Cpp { - -class Preprocessor { - -public: - explicit Preprocessor(ByteString const& filename, StringView program); - Vector process_and_lex(); - Vector included_paths() const { return m_included_paths; } - - struct Definition { - ByteString key; - Vector parameters; - ByteString value; - DeprecatedFlyString filename; - size_t line { 0 }; - size_t column { 0 }; - }; - using Definitions = HashMap; - - struct Substitution { - Vector original_tokens; - Definition defined_value; - ByteString processed_value; - }; - - Definitions const& definitions() const { return m_definitions; } - Vector const& substitutions() const { return m_substitutions; } - - void set_ignore_unsupported_keywords(bool ignore) { m_options.ignore_unsupported_keywords = ignore; } - void set_ignore_invalid_statements(bool ignore) { m_options.ignore_invalid_statements = ignore; } - void set_keep_include_statements(bool keep) { m_options.keep_include_statements = keep; } - - Function definitions_in_header_callback { nullptr }; - - Vector const& unprocessed_tokens() const { return m_unprocessed_tokens; } - -private: - void handle_preprocessor_statement(StringView); - void handle_include_statement(StringView); - void handle_preprocessor_keyword(StringView keyword, GenericLexer& line_lexer); - ByteString remove_escaped_newlines(StringView value); - - size_t do_substitution(Vector const& tokens, size_t token_index, Definition const&); - Optional create_definition(StringView line); - - struct MacroCall { - Token name; - struct Argument { - Vector tokens; - }; - Vector arguments; - size_t end_token_index { 0 }; - }; - Optional parse_macro_call(Vector const& tokens, size_t token_index); - ByteString evaluate_macro_call(MacroCall const&, Definition const&); - - ByteString m_filename; - ByteString m_program; - - Vector m_unprocessed_tokens; - Vector m_processed_tokens; - Definitions m_definitions; - Vector m_substitutions; - - size_t m_current_line { 0 }; - size_t m_current_depth { 0 }; - Vector m_depths_of_taken_branches; - Vector m_depths_of_not_taken_branches; - - enum class State { - Normal, - SkipIfBranch, - SkipElseBranch - }; - State m_state { State::Normal }; - - Vector m_included_paths; - - struct Options { - bool ignore_unsupported_keywords { false }; - bool ignore_invalid_statements { false }; - bool keep_include_statements { false }; - } m_options; -}; -} diff --git a/Userland/Libraries/LibCpp/SemanticSyntaxHighlighter.cpp b/Userland/Libraries/LibCpp/SemanticSyntaxHighlighter.cpp deleted file mode 100644 index cb2f941794d..00000000000 --- a/Userland/Libraries/LibCpp/SemanticSyntaxHighlighter.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2022, Itamar S. - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "SemanticSyntaxHighlighter.h" -#include "Lexer.h" -#include -#include -#include - -namespace Cpp { - -void SemanticSyntaxHighlighter::rehighlight(Palette const& palette) -{ - Vector new_tokens_info; - auto text = m_client->get_text(); - { - Threading::MutexLocker locker(m_lock); - Cpp::Lexer lexer(text); - lexer.set_ignore_whitespace(true); - auto current_tokens = lexer.lex(); - - // Identify folding regions - Vector folding_region_start_tokens; - Vector folding_regions; - for (auto& token : current_tokens) { - if (token.type() == Token::Type::LeftCurly) { - folding_region_start_tokens.append(token); - } else if (token.type() == Token::Type::RightCurly) { - if (!folding_region_start_tokens.is_empty()) { - auto start_token = folding_region_start_tokens.take_last(); - GUI::TextDocumentFoldingRegion folding_region; - folding_region.range.set_start({ start_token.end().line, start_token.end().column }); - folding_region.range.set_end({ token.start().line, token.start().column }); - folding_regions.append(move(folding_region)); - } - } - } - m_client->do_set_folding_regions(move(folding_regions)); - - StringBuilder current_tokens_as_lines; - StringBuilder previous_tokens_as_lines; - - for (auto& token : current_tokens) - current_tokens_as_lines.appendff("{}\n", token.type_as_byte_string()); - - for (Cpp::Token const& token : m_saved_tokens) - previous_tokens_as_lines.appendff("{}\n", token.type_as_byte_string()); - - auto previous = previous_tokens_as_lines.to_byte_string(); - auto current = current_tokens_as_lines.to_byte_string(); - - // FIXME: Computing the diff on the entire document's tokens is quite inefficient. - // An improvement over this could be only including the tokens that are in edited text ranges in the diff. - auto diff_hunks = Diff::from_text(previous.view(), current.view()).release_value_but_fixme_should_propagate_errors(); - for (auto& token : current_tokens) { - new_tokens_info.append(CodeComprehension::TokenInfo { CodeComprehension::TokenInfo::SemanticType::Unknown, - token.start().line, token.start().column, token.end().line, token.end().column }); - } - size_t previous_token_index = 0; - size_t current_token_index = 0; - for (auto const& hunk : diff_hunks) { - for (; previous_token_index < hunk.location.old_range.start_line; ++previous_token_index) { - new_tokens_info[current_token_index].type = m_tokens_info[previous_token_index].type; - ++current_token_index; - } - for (size_t i = 0; i < hunk.location.new_range.number_of_lines; ++i) { - ++current_token_index; - } - for (size_t i = 0; i < hunk.location.old_range.number_of_lines; ++i) { - ++previous_token_index; - } - } - while (current_token_index < new_tokens_info.size() && previous_token_index < m_tokens_info.size()) { - new_tokens_info[current_token_index].type = m_tokens_info[previous_token_index].type; - - ++previous_token_index; - ++current_token_index; - } - } - - update_spans(new_tokens_info, palette); -} - -static Gfx::TextAttributes style_for_token_type(Gfx::Palette const& palette, CodeComprehension::TokenInfo::SemanticType type) -{ - switch (type) { - case CodeComprehension::TokenInfo::SemanticType::Unknown: - return { palette.base_text() }; - case CodeComprehension::TokenInfo::SemanticType::Keyword: - return { palette.syntax_keyword(), {}, true }; - case CodeComprehension::TokenInfo::SemanticType::Type: - return { palette.syntax_type(), {}, true }; - case CodeComprehension::TokenInfo::SemanticType::Identifier: - return { palette.syntax_identifier() }; - case CodeComprehension::TokenInfo::SemanticType::String: - return { palette.syntax_string() }; - case CodeComprehension::TokenInfo::SemanticType::Number: - return { palette.syntax_number() }; - case CodeComprehension::TokenInfo::SemanticType::IncludePath: - return { palette.syntax_preprocessor_value() }; - case CodeComprehension::TokenInfo::SemanticType::PreprocessorStatement: - return { palette.syntax_preprocessor_statement() }; - case CodeComprehension::TokenInfo::SemanticType::Comment: - return { palette.syntax_comment() }; - case CodeComprehension::TokenInfo::SemanticType::Function: - return { palette.syntax_function() }; - case CodeComprehension::TokenInfo::SemanticType::Variable: - return { palette.syntax_variable() }; - case CodeComprehension::TokenInfo::SemanticType::CustomType: - return { palette.syntax_custom_type() }; - case CodeComprehension::TokenInfo::SemanticType::Namespace: - return { palette.syntax_namespace() }; - case CodeComprehension::TokenInfo::SemanticType::Member: - return { palette.syntax_member() }; - case CodeComprehension::TokenInfo::SemanticType::Parameter: - return { palette.syntax_parameter() }; - case CodeComprehension::TokenInfo::SemanticType::PreprocessorMacro: - return { palette.syntax_preprocessor_value() }; - default: - VERIFY_NOT_REACHED(); - return { palette.base_text() }; - } -} -void SemanticSyntaxHighlighter::update_spans(Vector const& tokens_info, Gfx::Palette const& palette) -{ - Vector spans; - for (auto& token : tokens_info) { - // FIXME: The +1 for the token end column is a quick hack due to not wanting to modify the lexer (which is also used by the parser). Maybe there's a better way to do this. - GUI::TextDocumentSpan span; - span.range.set_start({ token.start_line, token.start_column }); - span.range.set_end({ token.end_line, token.end_column + 1 }); - span.attributes = style_for_token_type(palette, token.type); - span.is_skippable = token.type == CodeComprehension::TokenInfo::SemanticType::Whitespace; - span.data = static_cast(token.type); - spans.append(span); - } - m_client->do_set_spans(move(spans)); - - m_has_brace_buddies = false; - highlight_matching_token_pair(); - - m_client->do_update(); -} - -void SemanticSyntaxHighlighter::update_tokens_info(Vector tokens_info) -{ - { - Threading::MutexLocker locker(m_lock); - m_tokens_info = move(tokens_info); - - m_saved_tokens_text = m_client->get_text(); - Cpp::Lexer lexer(m_saved_tokens_text); - lexer.set_ignore_whitespace(true); - m_saved_tokens = lexer.lex(); - } -} - -bool SemanticSyntaxHighlighter::is_identifier(u64 token_type) const -{ - auto type = static_cast(token_type); - - return type == CodeComprehension::TokenInfo::SemanticType::Identifier - || type == CodeComprehension::TokenInfo::SemanticType::Function - || type == CodeComprehension::TokenInfo::SemanticType::Variable - || type == CodeComprehension::TokenInfo::SemanticType::CustomType - || type == CodeComprehension::TokenInfo::SemanticType::Namespace - || type == CodeComprehension::TokenInfo::SemanticType::Member - || type == CodeComprehension::TokenInfo::SemanticType::Parameter - || type == CodeComprehension::TokenInfo::SemanticType::PreprocessorMacro; -} - -bool SemanticSyntaxHighlighter::is_navigatable(u64 token_type) const -{ - return static_cast(token_type) == CodeComprehension::TokenInfo::SemanticType::IncludePath; -} - -} diff --git a/Userland/Libraries/LibCpp/SemanticSyntaxHighlighter.h b/Userland/Libraries/LibCpp/SemanticSyntaxHighlighter.h deleted file mode 100644 index b3b0913803b..00000000000 --- a/Userland/Libraries/LibCpp/SemanticSyntaxHighlighter.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2022, Itamar S. - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "SyntaxHighlighter.h" -#include "Token.h" -#include -#include -#include - -namespace Cpp { - -class SemanticSyntaxHighlighter final : public Syntax::Highlighter { - -public: - SemanticSyntaxHighlighter() = default; - virtual ~SemanticSyntaxHighlighter() override = default; - - virtual bool is_identifier(u64 token) const override; - virtual bool is_navigatable(u64 token) const override; - - virtual Syntax::Language language() const override { return Syntax::Language::Cpp; } - virtual Optional comment_prefix() const override { return "//"sv; } - virtual Optional comment_suffix() const override { return {}; } - - virtual void rehighlight(Palette const&) override; - - void update_tokens_info(Vector); - - virtual bool is_cpp_semantic_highlighter() const override { return true; } - -protected: - virtual Vector matching_token_pairs_impl() const override { return m_simple_syntax_highlighter.matching_token_pairs_impl(); } - virtual bool token_types_equal(u64 token1, u64 token2) const override { return m_simple_syntax_highlighter.token_types_equal(token1, token2); } - -private: - void update_spans(Vector const&, Gfx::Palette const&); - - Cpp::SyntaxHighlighter m_simple_syntax_highlighter; - Vector m_tokens_info; - ByteString m_saved_tokens_text; - Vector m_saved_tokens; - Threading::Mutex m_lock; -}; -} -template<> -inline bool Syntax::Highlighter::fast_is() const { return is_cpp_semantic_highlighter(); } diff --git a/Userland/Libraries/LibCpp/SyntaxHighlighter.cpp b/Userland/Libraries/LibCpp/SyntaxHighlighter.cpp deleted file mode 100644 index da9bc8bc82e..00000000000 --- a/Userland/Libraries/LibCpp/SyntaxHighlighter.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2020-2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include - -namespace Cpp { - -static Gfx::TextAttributes style_for_token_type(Gfx::Palette const& palette, Cpp::Token::Type type) -{ - switch (type) { - case Cpp::Token::Type::Keyword: - return { palette.syntax_keyword(), {}, true }; - case Cpp::Token::Type::KnownType: - return { palette.syntax_type(), {}, true }; - case Cpp::Token::Type::Identifier: - return { palette.syntax_identifier() }; - case Cpp::Token::Type::DoubleQuotedString: - case Cpp::Token::Type::SingleQuotedString: - case Cpp::Token::Type::RawString: - return { palette.syntax_string() }; - case Cpp::Token::Type::Integer: - case Cpp::Token::Type::Float: - return { palette.syntax_number() }; - case Cpp::Token::Type::IncludePath: - return { palette.syntax_preprocessor_value() }; - case Cpp::Token::Type::EscapeSequence: - return { palette.syntax_keyword(), {}, true }; - case Cpp::Token::Type::PreprocessorStatement: - case Cpp::Token::Type::IncludeStatement: - return { palette.syntax_preprocessor_statement() }; - case Cpp::Token::Type::Comment: - return { palette.syntax_comment() }; - default: - return { palette.base_text() }; - } -} - -bool SyntaxHighlighter::is_identifier(u64 token) const -{ - auto cpp_token = static_cast(token); - return cpp_token == Cpp::Token::Type::Identifier; -} - -bool SyntaxHighlighter::is_navigatable(u64 token) const -{ - auto cpp_token = static_cast(token); - return cpp_token == Cpp::Token::Type::IncludePath; -} - -void SyntaxHighlighter::rehighlight(Palette const& palette) -{ - auto text = m_client->get_text(); - Cpp::Lexer lexer(text); - - Vector folding_region_start_tokens; - Vector folding_regions; - Vector spans; - lexer.lex_iterable([&](auto token) { - // FIXME: The +1 for the token end column is a quick hack due to not wanting to modify the lexer (which is also used by the parser). Maybe there's a better way to do this. - dbgln_if(SYNTAX_HIGHLIGHTING_DEBUG, "{} @ {}:{} - {}:{}", token.type_as_byte_string(), token.start().line, token.start().column, token.end().line, token.end().column + 1); - GUI::TextDocumentSpan span; - span.range.set_start({ token.start().line, token.start().column }); - span.range.set_end({ token.end().line, token.end().column + 1 }); - span.attributes = style_for_token_type(palette, token.type()); - span.is_skippable = token.type() == Cpp::Token::Type::Whitespace; - span.data = static_cast(token.type()); - spans.append(span); - - if (token.type() == Token::Type::LeftCurly) { - folding_region_start_tokens.append(token); - } else if (token.type() == Token::Type::RightCurly) { - if (!folding_region_start_tokens.is_empty()) { - auto start_token = folding_region_start_tokens.take_last(); - GUI::TextDocumentFoldingRegion folding_region; - folding_region.range.set_start({ start_token.end().line, start_token.end().column }); - folding_region.range.set_end({ token.start().line, token.start().column }); - folding_regions.append(move(folding_region)); - } - } - }); - m_client->do_set_spans(move(spans)); - m_client->do_set_folding_regions(move(folding_regions)); - - m_has_brace_buddies = false; - highlight_matching_token_pair(); - - m_client->do_update(); -} - -Vector SyntaxHighlighter::matching_token_pairs_impl() const -{ - static Vector pairs; - if (pairs.is_empty()) { - pairs.append({ static_cast(Cpp::Token::Type::LeftCurly), static_cast(Cpp::Token::Type::RightCurly) }); - pairs.append({ static_cast(Cpp::Token::Type::LeftParen), static_cast(Cpp::Token::Type::RightParen) }); - pairs.append({ static_cast(Cpp::Token::Type::LeftBracket), static_cast(Cpp::Token::Type::RightBracket) }); - } - return pairs; -} - -bool SyntaxHighlighter::token_types_equal(u64 token1, u64 token2) const -{ - return static_cast(token1) == static_cast(token2); -} - -} diff --git a/Userland/Libraries/LibCpp/SyntaxHighlighter.h b/Userland/Libraries/LibCpp/SyntaxHighlighter.h deleted file mode 100644 index f737b042894..00000000000 --- a/Userland/Libraries/LibCpp/SyntaxHighlighter.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2020-2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace Cpp { - -class SemanticSyntaxHighlighter; - -class SyntaxHighlighter final : public Syntax::Highlighter { - friend SemanticSyntaxHighlighter; - -public: - SyntaxHighlighter() = default; - virtual ~SyntaxHighlighter() override = default; - - virtual bool is_identifier(u64) const override; - virtual bool is_navigatable(u64) const override; - - virtual Syntax::Language language() const override { return Syntax::Language::Cpp; } - virtual Optional comment_prefix() const override { return "//"sv; } - virtual Optional comment_suffix() const override { return {}; } - virtual void rehighlight(Palette const&) override; - -protected: - virtual Vector matching_token_pairs_impl() const override; - virtual bool token_types_equal(u64, u64) const override; -}; - -} diff --git a/Userland/Libraries/LibCpp/Tests/.clang-format b/Userland/Libraries/LibCpp/Tests/.clang-format deleted file mode 100644 index 48ad0abce45..00000000000 --- a/Userland/Libraries/LibCpp/Tests/.clang-format +++ /dev/null @@ -1,4 +0,0 @@ -# These are all test files, don't format them, as they maybe -# intentionally miss-formatted. -DisableFormat: true -SortIncludes: Never diff --git a/Userland/Libraries/LibCpp/Tests/parser/array-initialization.ast b/Userland/Libraries/LibCpp/Tests/parser/array-initialization.ast deleted file mode 100644 index 2d29850149b..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/array-initialization.ast +++ /dev/null @@ -1,19 +0,0 @@ -TranslationUnit[0:0->2:0] - FunctionDeclaration[0:0->2:0] - NamedType[0:0->0:3] - void - foo - ( - ) - FunctionDefinition[0:11->2:0] - { - VariableDeclaration[1:4->1:20] - NamedType[1:4->1:6] - int - x - BracedInitList[1:15->1:20] - NumericLiteral[1:16->1:16] - 1 - NumericLiteral[1:18->1:18] - 2 - } diff --git a/Userland/Libraries/LibCpp/Tests/parser/array-initialization.cpp b/Userland/Libraries/LibCpp/Tests/parser/array-initialization.cpp deleted file mode 100644 index b03eb20dee1..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/array-initialization.cpp +++ /dev/null @@ -1,3 +0,0 @@ -void foo() { - int x[0] = {1,2}; -} diff --git a/Userland/Libraries/LibCpp/Tests/parser/class.ast b/Userland/Libraries/LibCpp/Tests/parser/class.ast deleted file mode 100644 index c53eddc1b7c..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/class.ast +++ /dev/null @@ -1,28 +0,0 @@ -TranslationUnit[0:0->10:1] - StructOrClassDeclaration[0:6->10:1] - A - - C'tor - ( - Parameter[1:6->1:10] - z - NamedType[1:6->1:8] - int - ) - D'tor - ( - ) - FunctionDeclaration[3:4->3:14] - NamedType[3:4->3:7] - void - foo - ( - ) - VariableDeclaration[6:4->8:0] - NamedType[6:4->6:6] - int - x - VariableDeclaration[9:4->10:0] - NamedType[9:4->9:6] - int - y diff --git a/Userland/Libraries/LibCpp/Tests/parser/class.cpp b/Userland/Libraries/LibCpp/Tests/parser/class.cpp deleted file mode 100644 index 4ba773a943b..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/class.cpp +++ /dev/null @@ -1,11 +0,0 @@ -class A { - A(int z); - ~A(); - void foo(); - -private: - int x; - -public: - int y; -}; diff --git a/Userland/Libraries/LibCpp/Tests/parser/function-decl.ast b/Userland/Libraries/LibCpp/Tests/parser/function-decl.ast deleted file mode 100644 index 1fed5ce8f9b..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/function-decl.ast +++ /dev/null @@ -1,10 +0,0 @@ -TranslationUnit[0:0->2:0] - FunctionDeclaration[0:0->2:0] - NamedType[0:0->0:2] - int - foo - ( - ) - FunctionDefinition[1:0->2:0] - { - } diff --git a/Userland/Libraries/LibCpp/Tests/parser/function-decl.cpp b/Userland/Libraries/LibCpp/Tests/parser/function-decl.cpp deleted file mode 100644 index 1c646d6c17c..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/function-decl.cpp +++ /dev/null @@ -1,3 +0,0 @@ -int foo() -{ -} diff --git a/Userland/Libraries/LibCpp/Tests/parser/if-else.ast b/Userland/Libraries/LibCpp/Tests/parser/if-else.ast deleted file mode 100644 index c62b99dc4ab..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/if-else.ast +++ /dev/null @@ -1,33 +0,0 @@ -TranslationUnit[0:0->7:0] - FunctionDeclaration[0:0->7:0] - NamedType[0:0->0:2] - int - foo - ( - ) - FunctionDefinition[1:0->7:0] - { - IfStatement[2:4->3:16] - Predicate: - NumericLiteral[2:8->2:8] - 2 - Then: - ReturnStatement[3:8->3:16] - NumericLiteral[3:15->3:15] - 2 - IfStatement[4:4->5:16] - Predicate: - BinaryExpression[4:8->4:12] - NumericLiteral[4:8->4:8] - 1 - < - NumericLiteral[4:12->4:12] - 2 - Then: - ReturnStatement[5:8->5:16] - NumericLiteral[5:15->5:15] - 1 - ReturnStatement[6:4->6:12] - NumericLiteral[6:11->6:11] - 0 - } diff --git a/Userland/Libraries/LibCpp/Tests/parser/if-else.cpp b/Userland/Libraries/LibCpp/Tests/parser/if-else.cpp deleted file mode 100644 index 91d0fe62feb..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/if-else.cpp +++ /dev/null @@ -1,8 +0,0 @@ -int foo() -{ - if (2) - return 2; - if (1 < 2) - return 1; - return 0; -} diff --git a/Userland/Libraries/LibCpp/Tests/parser/inheritance.ast b/Userland/Libraries/LibCpp/Tests/parser/inheritance.ast deleted file mode 100644 index eb67cb13e98..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/inheritance.ast +++ /dev/null @@ -1,14 +0,0 @@ -TranslationUnit[0:0->3:1] - StructOrClassDeclaration[0:6->3:1] - A - : - Name[0:17->0:32] - SomeNamespace::B - , - Name[0:43->0:43] - C - - VariableDeclaration[2:4->3:0] - NamedType[2:4->2:6] - int - x diff --git a/Userland/Libraries/LibCpp/Tests/parser/inheritance.cpp b/Userland/Libraries/LibCpp/Tests/parser/inheritance.cpp deleted file mode 100644 index 84d3fd0c525..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/inheritance.cpp +++ /dev/null @@ -1,4 +0,0 @@ -class A : public SomeNamespace::B, private C -{ - int x; -}; diff --git a/Userland/Libraries/LibCpp/Tests/parser/local-vars.ast b/Userland/Libraries/LibCpp/Tests/parser/local-vars.ast deleted file mode 100644 index c8d0fbaf07c..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/local-vars.ast +++ /dev/null @@ -1,33 +0,0 @@ -TranslationUnit[1:0->7:0] - FunctionDeclaration[1:0->7:0] - NamedType[1:0->1:2] - int - foo - ( - ) - FunctionDefinition[2:0->7:0] - { - VariableDeclaration[3:4->3:9] - NamedType[3:4->3:6] - int - x - VariableDeclaration[4:4->4:16] - NamedType[4:4->4:9] - double - y - NumericLiteral[4:15->4:15] - 2 - VariableDeclaration[5:4->5:20] - NamedType[5:4->5:9] - double - z - BinaryExpression[5:15->5:19] - Name[5:15->5:15] - x - + - Name[5:19->5:19] - y - ReturnStatement[6:4->6:12] - Name[6:11->6:11] - z - } diff --git a/Userland/Libraries/LibCpp/Tests/parser/local-vars.cpp b/Userland/Libraries/LibCpp/Tests/parser/local-vars.cpp deleted file mode 100644 index 42a2c3d235a..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/local-vars.cpp +++ /dev/null @@ -1,8 +0,0 @@ - -int foo() -{ - int x; - double y = 2; - double z = x + y; - return z; -} diff --git a/Userland/Libraries/LibCpp/Tests/parser/out-of-line.ast b/Userland/Libraries/LibCpp/Tests/parser/out-of-line.ast deleted file mode 100644 index d8e08c34f03..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/out-of-line.ast +++ /dev/null @@ -1,22 +0,0 @@ -TranslationUnit[2:0->9:0] - StructOrClassDeclaration[2:6->7:0] - A - - FunctionDeclaration[4:4->4:14] - NamedType[4:4->4:7] - bool - foo - ( - ) - FunctionDeclaration[7:0->9:0] - NamedType[7:0->7:3] - bool - A::foo - ( - ) - FunctionDefinition[7:14->9:0] - { - ReturnStatement[8:4->8:15] - BooleanLiteral[8:11->8:14] - true - } diff --git a/Userland/Libraries/LibCpp/Tests/parser/out-of-line.cpp b/Userland/Libraries/LibCpp/Tests/parser/out-of-line.cpp deleted file mode 100644 index 8be70f1b123..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/out-of-line.cpp +++ /dev/null @@ -1,10 +0,0 @@ - - -class A -{ - bool foo(); -}; - -bool A::foo() { - return true; -} diff --git a/Userland/Libraries/LibCpp/Tests/parser/strace.ast b/Userland/Libraries/LibCpp/Tests/parser/strace.ast deleted file mode 100644 index 2d36ac0ba70..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/strace.ast +++ /dev/null @@ -1,923 +0,0 @@ -TranslationUnit[0:0->150:0] - VariableDeclaration[0:0->2:0] - NamedType[0:0->0:9] - [static] int - g_pid - UnaryExpression[0:19->0:20] - - - NumericLiteral[0:20->0:20] - 1 - FunctionDeclaration[2:0->10:0] - [static] - NamedType[2:7->2:10] - void - handle_sigint - ( - Parameter[2:26->2:28] - NamedType[2:26->2:28] - int - ) - FunctionDefinition[3:0->10:0] - { - IfStatement[4:4->5:14] - Predicate: - BinaryExpression[4:8->4:18] - Name[4:8->4:12] - g_pid - == - UnaryExpression[4:17->4:18] - - - NumericLiteral[4:18->4:18] - 1 - Then: - ReturnStatement[5:8->5:14] - IfStatement[7:4->10:0] - Predicate: - BinaryExpression[7:8->7:43] - FunctionCall[7:8->7:39] - Name[7:8->7:13] - ptrace - Name[7:15->7:23] - PT_DETACH - Name[7:26->7:30] - g_pid - NumericLiteral[7:33->7:33] - 0 - NumericLiteral[7:36->7:36] - 0 - == - UnaryExpression[7:42->7:43] - - - NumericLiteral[7:43->7:43] - 1 - Then: - BlockStatement[7:46->10:0] - FunctionCall[8:8->8:24] - Name[8:8->8:13] - perror - StringLiteral[8:15->8:22] - "detach" - } - FunctionDeclaration[12:0->150:0] - NamedType[12:0->12:2] - int - main - ( - Parameter[12:9->12:16] - argc - NamedType[12:9->12:11] - int - Parameter[12:19->12:29] - argv - Pointer[12:19->12:24] - Pointer[12:19->12:24] - NamedType[12:19->12:23] - char - ) - FunctionDefinition[13:0->150:0] - { - IfStatement[14:4->19:4] - Predicate: - BinaryExpression[14:8->14:74] - FunctionCall[14:8->14:72] - Name[14:8->14:13] - pledge - StringLiteral[14:15->14:60] - "stdio wpath cpath proc exec ptrace sigaction" - NullPointerLiteral[14:63->14:69] - < - NumericLiteral[14:74->14:74] - 0 - Then: - BlockStatement[14:77->19:4] - FunctionCall[15:8->15:24] - Name[15:8->15:13] - perror - StringLiteral[15:15->15:22] - "pledge" - ReturnStatement[16:8->16:16] - NumericLiteral[16:15->16:15] - 1 - VariableDeclaration[19:4->19:34] - NamedType[19:4->19:22] - Vector<[const] char*> - child_argv - VariableDeclaration[21:4->21:41] - Pointer[21:4->21:14] - NamedType[21:4->21:14] - [const] char - output_filename - NullPointerLiteral[21:34->21:40] - VariableDeclaration[22:4->22:59] - NamedType[22:4->22:7] - auto - trace_file_or_error - FunctionCall[22:31->22:59] - Name[22:31->22:56] - Core::File::standard_error - IfStatement[23:4->27:4] - Predicate: - FunctionCall[23:8->23:38] - MemberExpression[23:8->23:36] - Name[23:8->23:26] - trace_file_or_error - Identifier[23:28->23:35] - is_error - Then: - BlockStatement[23:40->27:4] - FunctionCall[24:8->24:79] - Name[24:8->24:12] - outln - Name[24:14->24:19] - stderr - StringLiteral[24:22->24:48] - "Failed to open stderr: {}" - FunctionCall[24:51->24:78] - MemberExpression[24:51->24:76] - Name[24:51->24:69] - trace_file_or_error - Identifier[24:71->24:75] - error - ReturnStatement[25:8->25:16] - NumericLiteral[25:15->25:15] - 1 - VariableDeclaration[27:4->27:57] - NamedType[27:4->27:7] - auto - trace_file - FunctionCall[27:22->27:57] - MemberExpression[27:22->27:55] - Name[27:22->27:40] - trace_file_or_error - Identifier[27:42->27:54] - release_value - VariableDeclaration[29:4->29:27] - NamedType[29:4->29:19] - Core::ArgsParser - parser - FunctionCall[30:4->31:47] - MemberExpression[30:4->30:27] - Name[30:4->30:9] - parser - Identifier[30:11->30:26] - set_general_help - StringLiteral[31:8->31:45] - "Trace all syscalls and their result." - FunctionCall[32:4->32:70] - MemberExpression[32:4->32:21] - Name[32:4->32:9] - parser - Identifier[32:11->32:20] - add_option - Name[32:22->32:26] - g_pid - StringLiteral[32:29->32:49] - "Trace the given PID" - StringLiteral[32:52->32:56] - "pid" - StringLiteral[32:59->32:61] - 'p' - StringLiteral[32:64->32:68] - "pid" - FunctionCall[33:4->33:94] - MemberExpression[33:4->33:21] - Name[33:4->33:9] - parser - Identifier[33:11->33:20] - add_option - Name[33:22->33:36] - output_filename - StringLiteral[33:39->33:67] - "Filename to write output to" - StringLiteral[33:70->33:77] - "output" - StringLiteral[33:80->33:82] - 'o' - StringLiteral[33:85->33:92] - "output" - FunctionCall[34:4->34:111] - MemberExpression[34:4->34:34] - Name[34:4->34:9] - parser - Identifier[34:11->34:33] - add_positional_argument - Name[34:35->34:44] - child_argv - StringLiteral[34:47->34:65] - "Arguments to exec" - StringLiteral[34:68->34:77] - "argument" - Name[34:80->34:109] - Core::ArgsParser::Required::No - FunctionCall[36:4->36:28] - MemberExpression[36:4->36:16] - Name[36:4->36:9] - parser - Identifier[36:11->36:15] - parse - Name[36:17->36:20] - argc - Name[36:23->36:26] - argv - IfStatement[38:4->47:4] - Predicate: - BinaryExpression[38:8->38:33] - Name[38:8->38:22] - output_filename - != - NullPointerLiteral[38:27->38:33] - Then: - BlockStatement[38:36->47:4] - VariableDeclaration[39:8->39:89] - NamedType[39:8->39:11] - auto - open_result - FunctionCall[39:27->39:89] - Name[39:27->39:42] - Core::File::open - Name[39:44->39:58] - output_filename - Name[39:61->39:87] - Core::File::OpenMode::Write - IfStatement[40:8->44:8] - Predicate: - FunctionCall[40:12->40:34] - MemberExpression[40:12->40:32] - Name[40:12->40:22] - open_result - Identifier[40:24->40:31] - is_error - Then: - BlockStatement[40:36->44:8] - FunctionCall[41:12->41:80] - Name[41:12->41:16] - outln - Name[41:18->41:23] - stderr - StringLiteral[41:26->41:57] - "Failed to open output file: {}" - FunctionCall[41:60->41:79] - MemberExpression[41:60->41:77] - Name[41:60->41:70] - open_result - Identifier[41:72->41:76] - error - ReturnStatement[42:12->42:20] - NumericLiteral[42:19->42:19] - 1 - AssignmentExpression[44:8->44:48] - Name[44:8->44:17] - trace_file - = - FunctionCall[44:21->44:48] - MemberExpression[44:21->44:46] - Name[44:21->44:31] - open_result - Identifier[44:33->44:45] - release_value - IfStatement[47:4->52:4] - Predicate: - BinaryExpression[47:8->47:62] - FunctionCall[47:8->47:60] - Name[47:8->47:13] - pledge - StringLiteral[47:15->47:48] - "stdio proc exec ptrace sigaction" - NullPointerLiteral[47:51->47:57] - < - NumericLiteral[47:62->47:62] - 0 - Then: - BlockStatement[47:65->52:4] - FunctionCall[48:8->48:24] - Name[48:8->48:13] - perror - StringLiteral[48:15->48:22] - "pledge" - ReturnStatement[49:8->49:16] - NumericLiteral[49:15->49:15] - 1 - VariableDeclaration[52:4->52:14] - NamedType[52:4->52:6] - int - status - IfStatement[53:4->86:4] - Predicate: - BinaryExpression[53:8->53:18] - Name[53:8->53:12] - g_pid - == - UnaryExpression[53:17->53:18] - - - NumericLiteral[53:18->53:18] - 1 - Then: - BlockStatement[53:21->86:4] - IfStatement[54:8->59:8] - Predicate: - FunctionCall[54:12->54:33] - MemberExpression[54:12->54:31] - Name[54:12->54:21] - child_argv - Identifier[54:23->54:30] - is_empty - Then: - BlockStatement[54:35->59:8] - FunctionCall[55:12->55:78] - Name[55:12->55:16] - outln - Name[55:18->55:23] - stderr - StringLiteral[55:26->55:76] - "strace: Expected either a pid or some arguments\n" - ReturnStatement[56:12->56:20] - NumericLiteral[56:19->56:19] - 1 - FunctionCall[59:8->59:34] - MemberExpression[59:8->59:25] - Name[59:8->59:17] - child_argv - Identifier[59:19->59:24] - append - NullPointerLiteral[59:26->59:32] - VariableDeclaration[60:8->60:24] - NamedType[60:8->60:10] - int - pid - FunctionCall[60:18->60:24] - Name[60:18->60:21] - fork - IfStatement[61:8->66:8] - Predicate: - BinaryExpression[61:12->61:18] - Name[61:12->61:14] - pid - < - NumericLiteral[61:18->61:18] - 0 - Then: - BlockStatement[61:21->66:8] - FunctionCall[62:12->62:26] - Name[62:12->62:17] - perror - StringLiteral[62:19->62:24] - "fork" - ReturnStatement[63:12->63:20] - NumericLiteral[63:19->63:19] - 1 - IfStatement[66:8->79:8] - Predicate: - UnaryExpression[66:12->66:15] - ! - Name[66:13->66:15] - pid - Then: - BlockStatement[66:18->79:8] - IfStatement[67:12->71:12] - Predicate: - BinaryExpression[67:16->67:49] - FunctionCall[67:16->67:45] - Name[67:16->67:21] - ptrace - Name[67:23->67:33] - PT_TRACE_ME - NumericLiteral[67:36->67:36] - 0 - NumericLiteral[67:39->67:39] - 0 - NumericLiteral[67:42->67:42] - 0 - == - UnaryExpression[67:48->67:49] - - - NumericLiteral[67:49->67:49] - 1 - Then: - BlockStatement[67:52->71:12] - FunctionCall[68:16->68:33] - Name[68:16->68:21] - perror - StringLiteral[68:23->68:31] - "traceme" - ReturnStatement[69:16->69:24] - NumericLiteral[69:23->69:23] - 1 - VariableDeclaration[71:12->71:86] - NamedType[71:12->71:14] - int - rc - FunctionCall[71:21->71:86] - Name[71:21->71:26] - execvp - FunctionCall[71:28->71:46] - MemberExpression[71:28->71:44] - Name[71:28->71:37] - child_argv - Identifier[71:39->71:43] - first - CppCastExpression[71:48->71:85] - const_cast - < - Pointer[71:59->71:64] - Pointer[71:59->71:64] - NamedType[71:59->71:63] - char - > - FunctionCall[71:67->71:84] - MemberExpression[71:67->71:82] - Name[71:67->71:76] - child_argv - Identifier[71:78->71:81] - data - IfStatement[72:12->76:12] - Predicate: - BinaryExpression[72:16->72:21] - Name[72:16->72:17] - rc - < - NumericLiteral[72:21->72:21] - 0 - Then: - BlockStatement[72:24->76:12] - FunctionCall[73:16->73:32] - Name[73:16->73:21] - perror - StringLiteral[73:23->73:30] - "execvp" - FunctionCall[74:16->74:23] - Name[74:16->74:19] - exit - NumericLiteral[74:21->74:21] - 1 - FunctionCall[76:12->76:32] - Name[76:12->76:29] - VERIFY_NOT_REACHED - AssignmentExpression[79:8->79:18] - Name[79:8->79:12] - g_pid - = - Name[79:16->79:18] - pid - IfStatement[80:8->84:4] - Predicate: - BinaryExpression[80:12->80:83] - FunctionCall[80:12->80:54] - Name[80:12->80:18] - waitpid - Name[80:20->80:22] - pid - UnaryExpression[80:25->80:31] - & - Name[80:26->80:31] - status - BinaryExpression[80:34->80:51] - Name[80:34->80:41] - WSTOPPED - | - Name[80:45->80:51] - WEXITED - != - BinaryExpression[80:57->80:83] - Name[80:57->80:59] - pid - || - UnaryExpression[80:64->80:83] - ! - FunctionCall[80:65->80:83] - Name[80:65->80:74] - WIFSTOPPED - Name[80:76->80:81] - status - Then: - BlockStatement[80:85->84:4] - FunctionCall[81:12->81:29] - Name[81:12->81:17] - perror - StringLiteral[81:19->81:27] - "waitpid" - ReturnStatement[82:12->82:20] - NumericLiteral[82:19->82:19] - 1 - VariableDeclaration[86:4->86:23] - NamedType[86:4->86:19] - sigaction - sa - FunctionCall[87:4->87:44] - Name[87:4->87:9] - memset - UnaryExpression[87:11->87:13] - & - Name[87:12->87:13] - sa - NumericLiteral[87:16->87:16] - 0 - SizeofExpression[87:19->87:43] - NamedType[87:26->87:41] - sigaction - AssignmentExpression[88:4->88:32] - MemberExpression[88:4->88:18] - Name[88:4->88:5] - sa - Identifier[88:7->88:16] - sa_handler - = - Name[88:20->88:32] - handle_sigint - FunctionCall[89:4->89:35] - Name[89:4->89:12] - sigaction - Name[89:14->89:19] - SIGINT - UnaryExpression[89:22->89:24] - & - Name[89:23->89:24] - sa - NullPointerLiteral[89:27->89:33] - IfStatement[91:4->95:4] - Predicate: - BinaryExpression[91:8->91:43] - FunctionCall[91:8->91:39] - Name[91:8->91:13] - ptrace - Name[91:15->91:23] - PT_ATTACH - Name[91:26->91:30] - g_pid - NumericLiteral[91:33->91:33] - 0 - NumericLiteral[91:36->91:36] - 0 - == - UnaryExpression[91:42->91:43] - - - NumericLiteral[91:43->91:43] - 1 - Then: - BlockStatement[91:46->95:4] - FunctionCall[92:8->92:24] - Name[92:8->92:13] - perror - StringLiteral[92:15->92:22] - "attach" - ReturnStatement[93:8->93:16] - NumericLiteral[93:15->93:15] - 1 - IfStatement[95:4->100:4] - Predicate: - BinaryExpression[95:8->95:83] - FunctionCall[95:8->95:52] - Name[95:8->95:14] - waitpid - Name[95:16->95:20] - g_pid - UnaryExpression[95:23->95:29] - & - Name[95:24->95:29] - status - BinaryExpression[95:32->95:49] - Name[95:32->95:39] - WSTOPPED - | - Name[95:43->95:49] - WEXITED - != - BinaryExpression[95:55->95:83] - Name[95:55->95:59] - g_pid - || - UnaryExpression[95:64->95:83] - ! - FunctionCall[95:65->95:83] - Name[95:65->95:74] - WIFSTOPPED - Name[95:76->95:81] - status - Then: - BlockStatement[95:85->100:4] - FunctionCall[96:8->96:25] - Name[96:8->96:13] - perror - StringLiteral[96:15->96:23] - "waitpid" - ReturnStatement[97:8->97:16] - NumericLiteral[97:15->97:15] - 1 - ForStatement[100:4->149:4] - BlockStatement[100:13->149:4] - IfStatement[101:8->105:8] - Predicate: - BinaryExpression[101:12->101:48] - FunctionCall[101:12->101:44] - Name[101:12->101:17] - ptrace - Name[101:19->101:28] - PT_SYSCALL - Name[101:31->101:35] - g_pid - NumericLiteral[101:38->101:38] - 0 - NumericLiteral[101:41->101:41] - 0 - == - UnaryExpression[101:47->101:48] - - - NumericLiteral[101:48->101:48] - 1 - Then: - BlockStatement[101:51->105:8] - FunctionCall[102:12->102:29] - Name[102:12->102:17] - perror - StringLiteral[102:19->102:27] - "syscall" - ReturnStatement[103:12->103:20] - NumericLiteral[103:19->103:19] - 1 - IfStatement[105:8->109:8] - Predicate: - BinaryExpression[105:12->105:87] - FunctionCall[105:12->105:56] - Name[105:12->105:18] - waitpid - Name[105:20->105:24] - g_pid - UnaryExpression[105:27->105:33] - & - Name[105:28->105:33] - status - BinaryExpression[105:36->105:53] - Name[105:36->105:43] - WSTOPPED - | - Name[105:47->105:53] - WEXITED - != - BinaryExpression[105:59->105:87] - Name[105:59->105:63] - g_pid - || - UnaryExpression[105:68->105:87] - ! - FunctionCall[105:69->105:87] - Name[105:69->105:78] - WIFSTOPPED - Name[105:80->105:85] - status - Then: - BlockStatement[105:89->109:8] - FunctionCall[106:12->106:30] - Name[106:12->106:17] - perror - StringLiteral[106:19->106:28] - "wait_pid" - ReturnStatement[107:12->107:20] - NumericLiteral[107:19->107:19] - 1 - VariableDeclaration[109:8->109:33] - NamedType[109:8->109:22] - PtraceRegisters - regs - BracedInitList[109:31->109:33] - IfStatement[110:8->114:8] - Predicate: - BinaryExpression[110:12->110:52] - FunctionCall[110:12->110:48] - Name[110:12->110:17] - ptrace - Name[110:19->110:28] - PT_GETREGS - Name[110:31->110:35] - g_pid - UnaryExpression[110:38->110:42] - & - Name[110:39->110:42] - regs - NumericLiteral[110:45->110:45] - 0 - == - UnaryExpression[110:51->110:52] - - - NumericLiteral[110:52->110:52] - 1 - Then: - BlockStatement[110:55->114:8] - FunctionCall[111:12->111:29] - Name[111:12->111:17] - perror - StringLiteral[111:19->111:27] - "getregs" - ReturnStatement[112:12->112:20] - NumericLiteral[112:19->112:19] - 1 - VariableDeclaration[114:8->114:36] - NamedType[114:8->114:10] - u32 - syscall_index - MemberExpression[114:28->114:36] - Name[114:28->114:31] - regs - Identifier[114:33->114:35] - eax - VariableDeclaration[115:8->115:27] - NamedType[115:8->115:10] - u32 - arg1 - MemberExpression[115:19->115:27] - Name[115:19->115:22] - regs - Identifier[115:24->115:26] - edx - VariableDeclaration[116:8->116:27] - NamedType[116:8->116:10] - u32 - arg2 - MemberExpression[116:19->116:27] - Name[116:19->116:22] - regs - Identifier[116:24->116:26] - ecx - VariableDeclaration[117:8->117:27] - NamedType[117:8->117:10] - u32 - arg3 - MemberExpression[117:19->117:27] - Name[117:19->117:22] - regs - Identifier[117:24->117:26] - ebx - IfStatement[119:8->123:8] - Predicate: - BinaryExpression[119:12->119:48] - FunctionCall[119:12->119:44] - Name[119:12->119:17] - ptrace - Name[119:19->119:28] - PT_SYSCALL - Name[119:31->119:35] - g_pid - NumericLiteral[119:38->119:38] - 0 - NumericLiteral[119:41->119:41] - 0 - == - UnaryExpression[119:47->119:48] - - - NumericLiteral[119:48->119:48] - 1 - Then: - BlockStatement[119:51->123:8] - FunctionCall[120:12->120:29] - Name[120:12->120:17] - perror - StringLiteral[120:19->120:27] - "syscall" - ReturnStatement[121:12->121:20] - NumericLiteral[121:19->121:19] - 1 - IfStatement[123:8->128:8] - Predicate: - BinaryExpression[123:12->123:87] - FunctionCall[123:12->123:56] - Name[123:12->123:18] - waitpid - Name[123:20->123:24] - g_pid - UnaryExpression[123:27->123:33] - & - Name[123:28->123:33] - status - BinaryExpression[123:36->123:53] - Name[123:36->123:43] - WSTOPPED - | - Name[123:47->123:53] - WEXITED - != - BinaryExpression[123:59->123:87] - Name[123:59->123:63] - g_pid - || - UnaryExpression[123:68->123:87] - ! - FunctionCall[123:69->123:87] - Name[123:69->123:78] - WIFSTOPPED - Name[123:80->123:85] - status - Then: - BlockStatement[123:89->128:8] - FunctionCall[124:12->124:30] - Name[124:12->124:17] - perror - StringLiteral[124:19->124:28] - "wait_pid" - ReturnStatement[125:12->125:20] - NumericLiteral[125:19->125:19] - 1 - IfStatement[128:8->133:8] - Predicate: - BinaryExpression[128:12->128:52] - FunctionCall[128:12->128:48] - Name[128:12->128:17] - ptrace - Name[128:19->128:28] - PT_GETREGS - Name[128:31->128:35] - g_pid - UnaryExpression[128:38->128:42] - & - Name[128:39->128:42] - regs - NumericLiteral[128:45->128:45] - 0 - == - UnaryExpression[128:51->128:52] - - - NumericLiteral[128:52->128:52] - 1 - Then: - BlockStatement[128:55->133:8] - FunctionCall[129:12->129:29] - Name[129:12->129:17] - perror - StringLiteral[129:19->129:27] - "getregs" - ReturnStatement[130:12->130:20] - NumericLiteral[130:19->130:19] - 1 - VariableDeclaration[133:8->133:26] - NamedType[133:8->133:10] - u32 - res - MemberExpression[133:18->133:26] - Name[133:18->133:21] - regs - Identifier[133:23->133:25] - eax - VariableDeclaration[135:8->140:16] - NamedType[135:8->135:11] - auto - string - FunctionCall[135:22->140:16] - Name[135:22->135:38] - String::formatted - StringLiteral[135:40->135:77] - "{}({:#08x}, {:#08x}, {:#08x})\t={}\n" - FunctionCall[136:12->136:64] - Name[136:12->136:29] - Syscall::to_string - CStyleCastExpression[136:31->136:63] - NamedType[136:32->136:48] - Syscall::Function - Name[136:50->136:62] - syscall_index - Name[137:12->137:15] - arg1 - Name[138:12->138:15] - arg2 - Name[139:12->139:15] - arg3 - Name[140:12->140:14] - res - VariableDeclaration[142:8->142:53] - NamedType[142:8->142:11] - auto - result - BinaryExpression[142:22->142:53] - Name[142:22->142:31] - trace_file - -> - FunctionCall[142:34->142:53] - Name[142:34->142:44] - write_value - Name[142:46->142:51] - string - IfStatement[143:8->147:4] - Predicate: - FunctionCall[143:12->143:29] - MemberExpression[143:12->143:27] - Name[143:12->143:17] - result - Identifier[143:19->143:26] - is_error - Then: - BlockStatement[143:31->147:4] - FunctionCall[144:12->144:48] - Name[144:12->144:17] - warnln - StringLiteral[144:19->144:29] - "write: {}" - BinaryExpression[144:32->144:47] - Name[144:32->144:37] - result - -> - FunctionCall[144:40->144:47] - Name[144:40->144:44] - error - ReturnStatement[145:12->145:20] - NumericLiteral[145:19->145:19] - 1 - ReturnStatement[149:4->149:12] - NumericLiteral[149:11->149:11] - 0 - } diff --git a/Userland/Libraries/LibCpp/Tests/parser/strace.cpp b/Userland/Libraries/LibCpp/Tests/parser/strace.cpp deleted file mode 100644 index c005e67a8a6..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/strace.cpp +++ /dev/null @@ -1,151 +0,0 @@ -static int g_pid = -1; - -static void handle_sigint(int) -{ - if (g_pid == -1) - return; - - if (ptrace(PT_DETACH, g_pid, 0, 0) == -1) { - perror("detach"); - } -} - -int main(int argc, char** argv) -{ - if (pledge("stdio wpath cpath proc exec ptrace sigaction", nullptr) < 0) { - perror("pledge"); - return 1; - } - - Vector child_argv; - - const char* output_filename = nullptr; - auto trace_file_or_error = Core::File::standard_error(); - if (trace_file_or_error.is_error()) { - outln(stderr, "Failed to open stderr: {}", trace_file_or_error.error()); - return 1; - } - auto trace_file = trace_file_or_error.release_value(); - - Core::ArgsParser parser; - parser.set_general_help( - "Trace all syscalls and their result."); - parser.add_option(g_pid, "Trace the given PID", "pid", 'p', "pid"); - parser.add_option(output_filename, "Filename to write output to", "output", 'o', "output"); - parser.add_positional_argument(child_argv, "Arguments to exec", "argument", Core::ArgsParser::Required::No); - - parser.parse(argc, argv); - - if (output_filename != nullptr) { - auto open_result = Core::File::open(output_filename, Core::File::OpenMode::Write); - if (open_result.is_error()) { - outln(stderr, "Failed to open output file: {}", open_result.error()); - return 1; - } - trace_file = open_result.release_value(); - } - - if (pledge("stdio proc exec ptrace sigaction", nullptr) < 0) { - perror("pledge"); - return 1; - } - - int status; - if (g_pid == -1) { - if (child_argv.is_empty()) { - outln(stderr, "strace: Expected either a pid or some arguments\n"); - return 1; - } - - child_argv.append(nullptr); - int pid = fork(); - if (pid < 0) { - perror("fork"); - return 1; - } - - if (!pid) { - if (ptrace(PT_TRACE_ME, 0, 0, 0) == -1) { - perror("traceme"); - return 1; - } - int rc = execvp(child_argv.first(), const_cast(child_argv.data())); - if (rc < 0) { - perror("execvp"); - exit(1); - } - VERIFY_NOT_REACHED(); - } - - g_pid = pid; - if (waitpid(pid, &status, WSTOPPED | WEXITED) != pid || !WIFSTOPPED(status)) { - perror("waitpid"); - return 1; - } - } - - struct sigaction sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = handle_sigint; - sigaction(SIGINT, &sa, nullptr); - - if (ptrace(PT_ATTACH, g_pid, 0, 0) == -1) { - perror("attach"); - return 1; - } - if (waitpid(g_pid, &status, WSTOPPED | WEXITED) != g_pid || !WIFSTOPPED(status)) { - perror("waitpid"); - return 1; - } - - for (;;) { - if (ptrace(PT_SYSCALL, g_pid, 0, 0) == -1) { - perror("syscall"); - return 1; - } - if (waitpid(g_pid, &status, WSTOPPED | WEXITED) != g_pid || !WIFSTOPPED(status)) { - perror("wait_pid"); - return 1; - } - PtraceRegisters regs = {}; - if (ptrace(PT_GETREGS, g_pid, ®s, 0) == -1) { - perror("getregs"); - return 1; - } - u32 syscall_index = regs.eax; - u32 arg1 = regs.edx; - u32 arg2 = regs.ecx; - u32 arg3 = regs.ebx; - - if (ptrace(PT_SYSCALL, g_pid, 0, 0) == -1) { - perror("syscall"); - return 1; - } - if (waitpid(g_pid, &status, WSTOPPED | WEXITED) != g_pid || !WIFSTOPPED(status)) { - perror("wait_pid"); - return 1; - } - - if (ptrace(PT_GETREGS, g_pid, ®s, 0) == -1) { - perror("getregs"); - return 1; - } - - u32 res = regs.eax; - - auto string = String::formatted("{}({:#08x}, {:#08x}, {:#08x})\t={}\n", - Syscall::to_string((Syscall::Function)syscall_index), - arg1, - arg2, - arg3, - res); - - auto result = trace_file->write_value(string); - if (result.is_error()) { - warnln("write: {}", result->error()); - return 1; - } - } - - return 0; -} diff --git a/Userland/Libraries/LibCpp/Tests/parser/struct.ast b/Userland/Libraries/LibCpp/Tests/parser/struct.ast deleted file mode 100644 index 112dffe2639..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/struct.ast +++ /dev/null @@ -1,42 +0,0 @@ -TranslationUnit[1:0->12:0] - StructOrClassDeclaration[1:7->7:0] - MyStruct - - VariableDeclaration[3:4->4:4] - NamedType[3:4->3:6] - int - x - VariableDeclaration[4:4->5:0] - Pointer[4:4->4:12] - NamedType[4:4->4:12] - s - next - FunctionDeclaration[7:0->12:0] - NamedType[7:0->7:2] - int - foo - ( - ) - FunctionDefinition[8:0->12:0] - { - VariableDeclaration[9:4->9:14] - NamedType[9:4->9:11] - MyStruct - s - FunctionCall[10:4->10:23] - Name[10:4->10:9] - printf - StringLiteral[10:11->10:16] - "%d\n" - MemberExpression[10:19->10:22] - Name[10:19->10:19] - s - Identifier[10:21->10:21] - x - ReturnStatement[11:4->11:14] - MemberExpression[11:11->11:14] - Name[11:11->11:11] - s - Identifier[11:13->11:13] - x - } diff --git a/Userland/Libraries/LibCpp/Tests/parser/struct.cpp b/Userland/Libraries/LibCpp/Tests/parser/struct.cpp deleted file mode 100644 index 4cc7953275e..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/struct.cpp +++ /dev/null @@ -1,13 +0,0 @@ - -struct MyStruct -{ - int x; - struct s* next; -}; - -int foo() -{ - MyStruct s; - printf("%d\n", s.x); - return s.x; -} diff --git a/Userland/Libraries/LibCpp/Tests/parser/using-namespace.ast b/Userland/Libraries/LibCpp/Tests/parser/using-namespace.ast deleted file mode 100644 index 8d4efa999ec..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/using-namespace.ast +++ /dev/null @@ -1,3 +0,0 @@ -TranslationUnit[0:0->0:23] - UsingNamespaceDeclaration[0:0->0:23] - a::b::c diff --git a/Userland/Libraries/LibCpp/Tests/parser/using-namespace.cpp b/Userland/Libraries/LibCpp/Tests/parser/using-namespace.cpp deleted file mode 100644 index bf15c1c9112..00000000000 --- a/Userland/Libraries/LibCpp/Tests/parser/using-namespace.cpp +++ /dev/null @@ -1,2 +0,0 @@ -using namespace a::b::c; - diff --git a/Userland/Libraries/LibCpp/Tests/preprocessor/macro1.cpp b/Userland/Libraries/LibCpp/Tests/preprocessor/macro1.cpp deleted file mode 100644 index 25a9b4a71b9..00000000000 --- a/Userland/Libraries/LibCpp/Tests/preprocessor/macro1.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#define ADD(x,y) x+y -ADD(2,5); diff --git a/Userland/Libraries/LibCpp/Tests/preprocessor/macro1.txt b/Userland/Libraries/LibCpp/Tests/preprocessor/macro1.txt deleted file mode 100644 index 1a83132df21..00000000000 --- a/Userland/Libraries/LibCpp/Tests/preprocessor/macro1.txt +++ /dev/null @@ -1,5 +0,0 @@ -PreprocessorStatement 0:0-0:19 (#define ADD(x,y) x+y) -Integer 1:0-1:2 (2) -Plus 1:0-1:2 (+) -Integer 1:0-1:2 (5) -Semicolon 1:8-1:8 (;) diff --git a/Userland/Libraries/LibCpp/Tests/preprocessor/macro2.cpp b/Userland/Libraries/LibCpp/Tests/preprocessor/macro2.cpp deleted file mode 100644 index cf6ef31b837..00000000000 --- a/Userland/Libraries/LibCpp/Tests/preprocessor/macro2.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#define M(x) String {x + "lo"} - -M("he" + "l") diff --git a/Userland/Libraries/LibCpp/Tests/preprocessor/macro2.txt b/Userland/Libraries/LibCpp/Tests/preprocessor/macro2.txt deleted file mode 100644 index 7130e0c92ff..00000000000 --- a/Userland/Libraries/LibCpp/Tests/preprocessor/macro2.txt +++ /dev/null @@ -1,9 +0,0 @@ -PreprocessorStatement 0:0-0:29 (#define M(x) String {x + "lo"}) -KnownType 2:0-2:0 (String) -LeftCurly 2:0-2:0 ({) -DoubleQuotedString 2:0-2:0 ("he") -Plus 2:0-2:0 (+) -DoubleQuotedString 2:0-2:0 ("l") -Plus 2:0-2:0 (+) -DoubleQuotedString 2:0-2:0 ("lo") -RightCurly 2:0-2:0 (}) diff --git a/Userland/Libraries/LibCpp/Tests/preprocessor/macro3.cpp b/Userland/Libraries/LibCpp/Tests/preprocessor/macro3.cpp deleted file mode 100644 index b02baa5d933..00000000000 --- a/Userland/Libraries/LibCpp/Tests/preprocessor/macro3.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#define M(x, y, z) x y = z; - -M(Vector, vec, ({1,2})) - diff --git a/Userland/Libraries/LibCpp/Tests/preprocessor/macro3.txt b/Userland/Libraries/LibCpp/Tests/preprocessor/macro3.txt deleted file mode 100644 index 8d81e325db1..00000000000 --- a/Userland/Libraries/LibCpp/Tests/preprocessor/macro3.txt +++ /dev/null @@ -1,12 +0,0 @@ -PreprocessorStatement 0:0-0:26 (#define M(x, y, z) x y = z;) -KnownType 2:0-2:0 (Vector) -Identifier 2:0-2:0 (vec) -Equals 2:0-2:0 (=) -LeftParen 2:0-2:0 (() -LeftCurly 2:0-2:0 ({) -Integer 2:0-2:0 (1) -Comma 2:0-2:0 (,) -Integer 2:0-2:0 (2) -RightCurly 2:0-2:0 (}) -RightParen 2:0-2:0 ()) -Semicolon 2:0-2:0 (;) diff --git a/Userland/Libraries/LibCpp/Tests/preprocessor/simple_define.cpp b/Userland/Libraries/LibCpp/Tests/preprocessor/simple_define.cpp deleted file mode 100644 index c25f7cdef40..00000000000 --- a/Userland/Libraries/LibCpp/Tests/preprocessor/simple_define.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#define NUMBER 1337 -int x = NUMBER; diff --git a/Userland/Libraries/LibCpp/Tests/preprocessor/simple_define.txt b/Userland/Libraries/LibCpp/Tests/preprocessor/simple_define.txt deleted file mode 100644 index 48d7d9d31df..00000000000 --- a/Userland/Libraries/LibCpp/Tests/preprocessor/simple_define.txt +++ /dev/null @@ -1,6 +0,0 @@ -PreprocessorStatement 0:0-0:18 (#define NUMBER 1337) -KnownType 1:0-1:2 (int) -Identifier 1:4-1:4 (x) -Equals 1:6-1:6 (=) -Integer 1:8-1:13 (1337) -Semicolon 1:14-1:14 (;) diff --git a/Userland/Libraries/LibCpp/Token.cpp b/Userland/Libraries/LibCpp/Token.cpp deleted file mode 100644 index b82bcd6d9fb..00000000000 --- a/Userland/Libraries/LibCpp/Token.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Token.h" -#include - -namespace Cpp { - -bool Position::operator<(Position const& other) const -{ - return line < other.line || (line == other.line && column < other.column); -} -bool Position::operator>(Position const& other) const -{ - return !(*this < other) && !(*this == other); -} -bool Position::operator==(Position const& other) const -{ - return line == other.line && column == other.column; -} -bool Position::operator<=(Position const& other) const -{ - return !(*this > other); -} - -ByteString Token::to_byte_string() const -{ - return ByteString::formatted("{} {}:{}-{}:{} ({})", type_to_string(m_type), start().line, start().column, end().line, end().column, text()); -} - -ByteString Token::type_as_byte_string() const -{ - return type_to_string(m_type); -} - -} diff --git a/Userland/Libraries/LibCpp/Token.h b/Userland/Libraries/LibCpp/Token.h deleted file mode 100644 index 2448e7f06f7..00000000000 --- a/Userland/Libraries/LibCpp/Token.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace Cpp { - -#define FOR_EACH_TOKEN_TYPE \ - __TOKEN(Unknown) \ - __TOKEN(Whitespace) \ - __TOKEN(PreprocessorStatement) \ - __TOKEN(IncludeStatement) \ - __TOKEN(IncludePath) \ - __TOKEN(LeftParen) \ - __TOKEN(RightParen) \ - __TOKEN(LeftCurly) \ - __TOKEN(RightCurly) \ - __TOKEN(LeftBracket) \ - __TOKEN(RightBracket) \ - __TOKEN(Less) \ - __TOKEN(Greater) \ - __TOKEN(LessEquals) \ - __TOKEN(GreaterEquals) \ - __TOKEN(LessLess) \ - __TOKEN(GreaterGreater) \ - __TOKEN(LessLessEquals) \ - __TOKEN(GreaterGreaterEquals) \ - __TOKEN(LessGreater) \ - __TOKEN(Comma) \ - __TOKEN(Plus) \ - __TOKEN(PlusPlus) \ - __TOKEN(PlusEquals) \ - __TOKEN(Minus) \ - __TOKEN(MinusMinus) \ - __TOKEN(MinusEquals) \ - __TOKEN(Asterisk) \ - __TOKEN(AsteriskEquals) \ - __TOKEN(Slash) \ - __TOKEN(SlashEquals) \ - __TOKEN(Percent) \ - __TOKEN(PercentEquals) \ - __TOKEN(Caret) \ - __TOKEN(CaretEquals) \ - __TOKEN(ExclamationMark) \ - __TOKEN(ExclamationMarkEquals) \ - __TOKEN(Equals) \ - __TOKEN(EqualsEquals) \ - __TOKEN(And) \ - __TOKEN(AndAnd) \ - __TOKEN(AndEquals) \ - __TOKEN(Pipe) \ - __TOKEN(PipePipe) \ - __TOKEN(PipeEquals) \ - __TOKEN(Tilde) \ - __TOKEN(QuestionMark) \ - __TOKEN(Colon) \ - __TOKEN(ColonColon) \ - __TOKEN(ColonColonAsterisk) \ - __TOKEN(Semicolon) \ - __TOKEN(Dot) \ - __TOKEN(DotAsterisk) \ - __TOKEN(Arrow) \ - __TOKEN(ArrowAsterisk) \ - __TOKEN(DoubleQuotedString) \ - __TOKEN(SingleQuotedString) \ - __TOKEN(RawString) \ - __TOKEN(EscapeSequence) \ - __TOKEN(Comment) \ - __TOKEN(Integer) \ - __TOKEN(Float) \ - __TOKEN(Keyword) \ - __TOKEN(KnownType) \ - __TOKEN(Identifier) \ - __TOKEN(EOF_TOKEN) - -struct Position { - size_t line { 0 }; - size_t column { 0 }; - - bool operator<(Position const&) const; - bool operator<=(Position const&) const; - bool operator>(Position const&) const; - bool operator==(Position const&) const; -}; - -struct Token { - enum class Type { -#define __TOKEN(x) x, - FOR_EACH_TOKEN_TYPE -#undef __TOKEN - }; - - Token(Type type, Position const& start, Position const& end, StringView text) - : m_type(type) - , m_start(start) - , m_end(end) - , m_text(text) - { - } - - static char const* type_to_string(Type t) - { - switch (t) { -#define __TOKEN(x) \ - case Type::x: \ - return #x; - FOR_EACH_TOKEN_TYPE -#undef __TOKEN - } - VERIFY_NOT_REACHED(); - } - - ByteString to_byte_string() const; - ByteString type_as_byte_string() const; - - Position const& start() const { return m_start; } - Position const& end() const { return m_end; } - - void set_start(Position const& other) { m_start = other; } - void set_end(Position const& other) { m_end = other; } - Type type() const { return m_type; } - StringView text() const { return m_text; } - -private: - Type m_type { Type::Unknown }; - Position m_start; - Position m_end; - StringView m_text; -}; - -} - -#undef FOR_EACH_TOKEN_TYPE diff --git a/Userland/Libraries/LibELF/Arch/GenericDynamicRelocationType.h b/Userland/Libraries/LibELF/Arch/GenericDynamicRelocationType.h deleted file mode 100644 index aaf6b37b2a4..00000000000 --- a/Userland/Libraries/LibELF/Arch/GenericDynamicRelocationType.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2024, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -#if ARCH(AARCH64) -# include -#elif ARCH(RISCV64) -# include -#elif ARCH(X86_64) -# include -#else -# error Unknown architecture -#endif diff --git a/Userland/Libraries/LibELF/Arch/aarch64/GenericDynamicRelocationType.h b/Userland/Libraries/LibELF/Arch/aarch64/GenericDynamicRelocationType.h deleted file mode 100644 index 48e4d2db10b..00000000000 --- a/Userland/Libraries/LibELF/Arch/aarch64/GenericDynamicRelocationType.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2024, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -#include -VALIDATE_IS_AARCH64() - -namespace ELF { - -enum class GenericDynamicRelocationType : unsigned { - NONE = R_AARCH64_NONE, - ABSOLUTE = R_AARCH64_ABS64, - COPY = R_AARCH64_COPY, - GLOB_DAT = R_AARCH64_GLOB_DAT, - JUMP_SLOT = R_AARCH64_JUMP_SLOT, - RELATIVE = R_AARCH64_RELATIVE, - TLS_DTPMOD = R_AARCH64_TLS_DTPMOD, - TLS_DTPREL = R_AARCH64_TLS_DTPREL, - TLS_TPREL = R_AARCH64_TLS_TPREL, - TLSDESC = R_AARCH64_TLSDESC, - IRELATIVE = R_AARCH64_IRELATIVE, -}; - -} diff --git a/Userland/Libraries/LibELF/Arch/aarch64/entry.S b/Userland/Libraries/LibELF/Arch/aarch64/entry.S deleted file mode 100644 index 52f23be7fa7..00000000000 --- a/Userland/Libraries/LibELF/Arch/aarch64/entry.S +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) 2021, Nico Weber - * Copyright (c) 2023, Timon Kruiper - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -.globl _invoke_entry -.hidden _invoke_entry -.type _invoke_entry,@function -_invoke_entry: # (argc, argv, envp, entry) - br x3 diff --git a/Userland/Libraries/LibELF/Arch/aarch64/plt_trampoline.S b/Userland/Libraries/LibELF/Arch/aarch64/plt_trampoline.S deleted file mode 100644 index b2c5dfd35ba..00000000000 --- a/Userland/Libraries/LibELF/Arch/aarch64/plt_trampoline.S +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2021, Nico Weber - * Copyright (c) 2023, Daniel Bertalan - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -.p2align 4 -.globl _plt_trampoline -.hidden _plt_trampoline -.type _plt_trampoline,@function - -// This function is called by the PLT stub to resolve functions lazily at runtime. -// It saves off any argument registers that might be clobbered by the symbol -// resolution code, calls that, and then jumps to the resolved function. -// -// See section 9.3 "Procedure Linkage Table" of the AArch64 ELF ABI. -// https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst -// -// The calling convention is: -// x16 = &got.plt[2] -// x17 = &_plt_trampoline -// [sp, #0] = &got.plt[relocation_index + 3] -// [sp, #8] = return address -_plt_trampoline: - mov x17, sp - - // Save argument registers: x0-x7, v0-v7. - stp x0, x1, [sp, #-16]! - stp x2, x3, [sp, #-16]! - stp x4, x5, [sp, #-16]! - stp x6, x7, [sp, #-16]! - - stp q0, q1, [sp, #-32]! - stp q2, q3, [sp, #-32]! - stp q4, q5, [sp, #-32]! - stp q6, q7, [sp, #-32]! - - // Load DynamicObject* from got.plt[1]. - ldr x0, [x16, #-8] - - // Calculate the rela.plt relocation offset. - ldr x2, [x17] - sub x1, x2, x16 - sub x1, x1, #8 - // GOT entries are 8 bytes, but sizeof(Elf64_Rela) == 24, so multiply - // by 3 to get the relocation offset. - add x1, x1, x1, lsl #1 - - bl _fixup_plt_entry - - // Save the resolved function's address. - mov x16, x0 - - // Restore argument registers. - ldp q6, q7, [sp], #32 - ldp q4, q5, [sp], #32 - ldp q2, q3, [sp], #32 - ldp q0, q1, [sp], #32 - - ldp x6, x7, [sp], #16 - ldp x4, x5, [sp], #16 - ldp x2, x3, [sp], #16 - ldp x0, x1, [sp], #16 - - // Restore link register saved by the PLT stub. - ldp xzr, x30, [sp], #16 - - // Jump to the resolved function. - br x16 - diff --git a/Userland/Libraries/LibELF/Arch/aarch64/tls.S b/Userland/Libraries/LibELF/Arch/aarch64/tls.S deleted file mode 100644 index 5f5836679fd..00000000000 --- a/Userland/Libraries/LibELF/Arch/aarch64/tls.S +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2023, Daniel Bertalan - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -// This file implements the runtime components of the AArch64 TLSDESC ABI, -// which is used when accessing thread-local variables which might not be -// stored in the static TLS block (global-dynamic and local-dynamic access -// models). Compilers default to this when creating shared libraries, as they -// may be loaded after program startup by `dlopen()`. -// -// Each referenced thread-local symbol is associated with a descriptor: -// -// struct TlsDescriptor { -// size_t (*resolver)(TlsDescriptor*); -// union { -// size_t tpoff; // for static TLS -// struct { -// size_t module_id; -// size_t module_offset; -// } *dynamic; // for dynamic TLS, not yet implemented -// }; -// }; -// -// The resolver takes a pointer to the descriptor as an argument and returns -// the symbol's offset to the thread pointer (tpidr_el0). The second field of -// the descriptor is an implementation-defined value which the resolver uses to -// identify the symbol. -// -// Thus, the address of a thread-local variable is retrieved as follows: -// -// &var = thread_pointer + descriptor.resolver(&descriptor); -// -// The two essential types of resolver functions are: -// -// - `__tlsdesc_static`: If the variable is located in the static TLS block, -// its thread pointer offset is a load-time constant, which can be stored in -// the descriptor. This function simply returns that. -// -// - `tlsdesc_dynamic`: Looks up a variable by its module ID and module offset. -// This is used if the TLS block is allocated separately, so might have a -// different thread pointer offset for each thread. This works similarly to -// the traditional TLS ABI's __tls_get_addr function. Not yet implemented in -// SerenityOS. -// -// The TLSDESC format strives to make the code sequence for thread-local -// variable access as short as possible, hence the resolver functions follow a -// special calling convention: they must not clobber any registers. To ensure -// that even the usually volatile registers are saved off, we need to implement -// the resolvers in assembly. - -// size_t __tlsdesc_static(TlsDescriptor* desc) -// { -// return desc->tpoff; -// } -.p2align 4 -.globl __tlsdesc_static -.hidden __tlsdesc_static -.type __tlsdesc_static,@function -__tlsdesc_static: - ldr x0, [x0, #8] - // The first static TLS block is 16 bytes after the thread pointer on AArch64. - add x0, x0, 16 - ret diff --git a/Userland/Libraries/LibELF/Arch/aarch64/tls.cpp b/Userland/Libraries/LibELF/Arch/aarch64/tls.cpp deleted file mode 100644 index b7393c14c18..00000000000 --- a/Userland/Libraries/LibELF/Arch/aarch64/tls.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2024, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace ELF { - -void set_thread_pointer_register(FlatPtr value) -{ - asm volatile("msr tpidr_el0, %0" ::"r"(value)); -} - -} diff --git a/Userland/Libraries/LibELF/Arch/aarch64/tls.h b/Userland/Libraries/LibELF/Arch/aarch64/tls.h deleted file mode 100644 index 7722bb30737..00000000000 --- a/Userland/Libraries/LibELF/Arch/aarch64/tls.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2024, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace ELF { - -struct ThreadControlBlock { - // Variant I of the ELF TLS data structures requires that the TCB has to contain a pointer to the dtv at offset 0. - // This member is unused, as we currently only support static TLS blocks. - void* dynamic_thread_vector; - - FlatPtr padding; -}; - -// The TCB needs to have a size of 2 * sizeof(FlatPtr) on AArch64. -static_assert(AssertSize()); - -static constexpr size_t TLS_VARIANT = 1; -static constexpr size_t TLS_DTV_OFFSET = 0; -static constexpr size_t TLS_TP_STATIC_TLS_BLOCK_OFFSET = sizeof(ThreadControlBlock); - -// AArch64 ELF TLS Layout -// -// [TCB][static TLS.....] -// ^tp (tpidr_el0) - -inline size_t calculate_static_tls_region_size(size_t tls_template_size, size_t tls_alignment) -{ - (void)tls_alignment; - return sizeof(ThreadControlBlock) + tls_template_size; -} - -inline FlatPtr calculate_tp_value_from_static_tls_region_address(FlatPtr static_tls_region_address, size_t tls_template_size, size_t tls_alignment) -{ - (void)tls_template_size; - (void)tls_alignment; - return static_tls_region_address; -} - -inline ThreadControlBlock* get_tcb_pointer_from_thread_pointer(FlatPtr thread_pointer) -{ - return bit_cast(thread_pointer); -} - -inline void* get_pointer_to_first_static_tls_block_from_thread_pointer(FlatPtr thread_pointer, size_t tls_template_size, size_t tls_alignment) -{ - (void)tls_template_size; - (void)tls_alignment; - return bit_cast(thread_pointer + sizeof(ThreadControlBlock)); -} - -inline void* get_pointer_to_static_tls_region_from_thread_pointer(FlatPtr thread_pointer, size_t tls_template_size, size_t tls_alignment) -{ - (void)tls_template_size; - (void)tls_alignment; - return bit_cast(thread_pointer); -} - -} diff --git a/Userland/Libraries/LibELF/Arch/riscv64/GenericDynamicRelocationType.h b/Userland/Libraries/LibELF/Arch/riscv64/GenericDynamicRelocationType.h deleted file mode 100644 index 39bbc13f004..00000000000 --- a/Userland/Libraries/LibELF/Arch/riscv64/GenericDynamicRelocationType.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2024, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -#include -VALIDATE_IS_RISCV64() - -namespace ELF { - -enum class GenericDynamicRelocationType : unsigned { - NONE = R_RISCV_NONE, - ABSOLUTE = R_RISCV_64, - COPY = R_RISCV_COPY, - // there is no R_RISCV_GLOB_DAT - JUMP_SLOT = R_RISCV_JUMP_SLOT, - RELATIVE = R_RISCV_RELATIVE, - TLS_DTPMOD = R_RISCV_TLS_DTPMOD64, - TLS_DTPREL = R_RISCV_TLS_DTPREL64, - TLS_TPREL = R_RISCV_TLS_TPREL64, - TLSDESC = R_RISCV_TLSDESC, - IRELATIVE = R_RISCV_IRELATIVE, -}; - -} diff --git a/Userland/Libraries/LibELF/Arch/riscv64/entry.S b/Userland/Libraries/LibELF/Arch/riscv64/entry.S deleted file mode 100644 index 15e0ff55bf1..00000000000 --- a/Userland/Libraries/LibELF/Arch/riscv64/entry.S +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2023, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -.globl _invoke_entry -.hidden _invoke_entry -.type _invoke_entry,@function -_invoke_entry: # (argc, argv, envp, entry) - jr a3 diff --git a/Userland/Libraries/LibELF/Arch/riscv64/plt_trampoline.S b/Userland/Libraries/LibELF/Arch/riscv64/plt_trampoline.S deleted file mode 100644 index c2bc97295ef..00000000000 --- a/Userland/Libraries/LibELF/Arch/riscv64/plt_trampoline.S +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2023-2024, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -.p2align 4 -.globl _plt_trampoline -.hidden _plt_trampoline -.type _plt_trampoline,@function - -// This function is called by the PLT stub to resolve functions lazily at runtime. -// It saves off any argument registers that might be clobbered by the symbol -// resolution code, calls that, and then jumps to the resolved function. -// -// See section 8.4.6 "Program Linkage Table" of the RISC-V psABI. -// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/download/v1.0/riscv-abi.pdf -// -// The calling convention is: -// t0 = .got.plt[1] (DynamicObject*) -// t1 = .got.plt offset -_plt_trampoline: - // Save argument registers a0-a7, fa0-fa7 and ra. - addi sp, sp, -(18 * 8) - - sd a0, 0*8(sp) - sd a1, 1*8(sp) - sd a2, 2*8(sp) - sd a3, 3*8(sp) - sd a4, 4*8(sp) - sd a5, 5*8(sp) - sd a6, 6*8(sp) - sd a7, 7*8(sp) - - // NOTE: We only support ABI_FLEN=64 in LibELF/Validation.cpp, - // so we only save the lower 64 bits of the fa* registers. - fsd fa0, 8*8(sp) - fsd fa1, 9*8(sp) - fsd fa2, 10*8(sp) - fsd fa3, 11*8(sp) - fsd fa4, 12*8(sp) - fsd fa5, 13*8(sp) - fsd fa6, 14*8(sp) - fsd fa7, 15*8(sp) - - sd ra, 16*8(sp) - - // The DynamicObject* is in t0. - mv a0, t0 - - // GOT entries are 8 bytes, but sizeof(Elf64_Rela) == 24, so multiply - // t1 by 3 to get the relocation offset. - slli a1, t1, 1 - add a1, a1, t1 - - call _fixup_plt_entry - - // Save the resolved function's address. - mv t0, a0 - - // Restore argument registers and ra. - ld a0, 0*8(sp) - ld a1, 1*8(sp) - ld a2, 2*8(sp) - ld a3, 3*8(sp) - ld a4, 4*8(sp) - ld a5, 5*8(sp) - ld a6, 6*8(sp) - ld a7, 7*8(sp) - - fld fa0, 8*8(sp) - fld fa1, 9*8(sp) - fld fa2, 10*8(sp) - fld fa3, 11*8(sp) - fld fa4, 12*8(sp) - fld fa5, 13*8(sp) - fld fa6, 14*8(sp) - fld fa7, 15*8(sp) - - ld ra, 16*8(sp) - - addi sp, sp, 18 * 8 - - // Jump to the resolved function. - jr t0 diff --git a/Userland/Libraries/LibELF/Arch/riscv64/tls.cpp b/Userland/Libraries/LibELF/Arch/riscv64/tls.cpp deleted file mode 100644 index 13971de4199..00000000000 --- a/Userland/Libraries/LibELF/Arch/riscv64/tls.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2024, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace ELF { - -void set_thread_pointer_register(FlatPtr value) -{ - asm volatile("mv tp, %0" ::"r"(value)); -} - -} diff --git a/Userland/Libraries/LibELF/Arch/riscv64/tls.h b/Userland/Libraries/LibELF/Arch/riscv64/tls.h deleted file mode 100644 index 47873b14141..00000000000 --- a/Userland/Libraries/LibELF/Arch/riscv64/tls.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2024, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace ELF { - -struct ThreadControlBlock { - // NOTE: "ELF Handling For Thread-Local Storage" says that when using variant I of the data structures (which RISC-V does), - // the TCB has to have a pointer to the dtv at offset 0. - // However, that document also says that the thread pointer has to point to the TCB. - // It's probably still a good idea to put the dtv pointer at offset 0. - // This member is unused, as we currently only support static TLS blocks. - void* dynamic_thread_vector; -}; - -static constexpr size_t TLS_VARIANT = 1; -static constexpr size_t TLS_DTV_OFFSET = 0x800; -static constexpr size_t TLS_TP_STATIC_TLS_BLOCK_OFFSET = 0; - -// RISC-V ELF TLS Layout -// The padding is needed so tp is correctly aligned. -// -// [..padding..][TCB][static TLS.....] -// ^tp - -inline size_t calculate_static_tls_region_size(size_t tls_template_size, size_t tls_alignment) -{ - return align_up_to(sizeof(ThreadControlBlock), tls_alignment) + tls_template_size; -} - -inline FlatPtr calculate_tp_value_from_static_tls_region_address(FlatPtr static_tls_region_address, size_t tls_template_size, size_t tls_alignment) -{ - (void)tls_template_size; - return static_tls_region_address + align_up_to(sizeof(ThreadControlBlock), tls_alignment); -} - -inline ThreadControlBlock* get_tcb_pointer_from_thread_pointer(FlatPtr thread_pointer) -{ - return bit_cast(thread_pointer - sizeof(ThreadControlBlock)); -} - -inline void* get_pointer_to_first_static_tls_block_from_thread_pointer(FlatPtr thread_pointer, size_t tls_template_size, size_t tls_alignment) -{ - (void)tls_template_size; - (void)tls_alignment; - return bit_cast(thread_pointer); -} - -inline void* get_pointer_to_static_tls_region_from_thread_pointer(FlatPtr thread_pointer, size_t tls_template_size, size_t tls_alignment) -{ - (void)tls_template_size; - return bit_cast(thread_pointer - align_up_to(sizeof(ThreadControlBlock), tls_alignment)); -} - -} diff --git a/Userland/Libraries/LibELF/Arch/tls.h b/Userland/Libraries/LibELF/Arch/tls.h deleted file mode 100644 index fefe0b4af89..00000000000 --- a/Userland/Libraries/LibELF/Arch/tls.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2024, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace ELF { - -void set_thread_pointer_register(FlatPtr); - -} - -#if ARCH(AARCH64) -# include -#elif ARCH(RISCV64) -# include -#elif ARCH(X86_64) -# include -#else -# error Unknown architecture -#endif diff --git a/Userland/Libraries/LibELF/Arch/x86_64/GenericDynamicRelocationType.h b/Userland/Libraries/LibELF/Arch/x86_64/GenericDynamicRelocationType.h deleted file mode 100644 index 74ba9aa498d..00000000000 --- a/Userland/Libraries/LibELF/Arch/x86_64/GenericDynamicRelocationType.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2024, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -#include -VALIDATE_IS_X86() - -namespace ELF { - -enum class GenericDynamicRelocationType : unsigned { - NONE = R_X86_64_NONE, - ABSOLUTE = R_X86_64_64, - COPY = R_X86_64_COPY, - GLOB_DAT = R_X86_64_GLOB_DAT, - JUMP_SLOT = R_X86_64_JUMP_SLOT, - RELATIVE = R_X86_64_RELATIVE, - TLS_DTPMOD = R_X86_64_DTPMOD64, - TLS_DTPREL = R_X86_64_DTPOFF64, - TLS_TPREL = R_X86_64_TPOFF64, - TLSDESC = R_X86_64_TLSDESC, - IRELATIVE = R_X86_64_IRELATIVE, -}; - -} diff --git a/Userland/Libraries/LibELF/Arch/x86_64/entry.S b/Userland/Libraries/LibELF/Arch/x86_64/entry.S deleted file mode 100644 index b4721a31ca0..00000000000 --- a/Userland/Libraries/LibELF/Arch/x86_64/entry.S +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2021, Gunnar Beutner - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -.align 4 -.globl _invoke_entry -.hidden _invoke_entry -.type _invoke_entry,@function -_invoke_entry: # (argc, argv, envp, entry) - // The System V ABI for x86 and x86_64 prescribes that the stack pointer is 16-byte aligned - andq $~15, %rsp - - // FIXME: The way we're setting up the stack and passing arguments to the entry point isn't ABI-compliant - jmp *%rcx diff --git a/Userland/Libraries/LibELF/Arch/x86_64/plt_trampoline.S b/Userland/Libraries/LibELF/Arch/x86_64/plt_trampoline.S deleted file mode 100644 index 3b210d27142..00000000000 --- a/Userland/Libraries/LibELF/Arch/x86_64/plt_trampoline.S +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2021, Gunnar Beutner - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -.align 4 -.globl _plt_trampoline -.hidden _plt_trampoline -.type _plt_trampoline,@function -_plt_trampoline: # (object, relocation_index) - # save flags/registers (https://stackoverflow.com/questions/18024672/what-registers-are-preserved-through-a-linux-x86-64-function-call) - subq $128, %rsp - movdqu %xmm0, 0x0(%rsp) - movdqu %xmm1, 0x10(%rsp) - movdqu %xmm2, 0x20(%rsp) - movdqu %xmm3, 0x30(%rsp) - movdqu %xmm4, 0x40(%rsp) - movdqu %xmm5, 0x50(%rsp) - movdqu %xmm6, 0x60(%rsp) - movdqu %xmm7, 0x70(%rsp) - pushfq - pushq %rax - pushq %rcx - pushq %rdx - pushq %rsi - pushq %rdi - pushq %r8 - pushq %r9 - pushq %r10 - pushq %r11 - - movq 208(%rsp), %rdi # object - movq 216(%rsp), %rsi # relocation_index - - # offset = index * sizeof(Elf64_Rela) - shlq $3, %rsi - leaq (%rsi, %rsi, 2), %rsi - - pushq %rbp - movq %rsp, %rbp - andq $~15, %rsp - call _fixup_plt_entry@PLT - movq %rbp, %rsp - popq %rbp - - movq %rax, 216(%rsp) # replace object argument with symbol address - - # restore flags/registers - popq %r11 - popq %r10 - popq %r9 - popq %r8 - popq %rdi - popq %rsi - popq %rdx - popq %rcx - popq %rax - popfq - - movdqu 0x0(%rsp), %xmm0 - movdqu 0x10(%rsp), %xmm1 - movdqu 0x20(%rsp), %xmm2 - movdqu 0x30(%rsp), %xmm3 - movdqu 0x40(%rsp), %xmm4 - movdqu 0x50(%rsp), %xmm5 - movdqu 0x60(%rsp), %xmm6 - movdqu 0x70(%rsp), %xmm7 - addq $128, %rsp - addq $8, %rsp # remove relocation_index argument - - retq diff --git a/Userland/Libraries/LibELF/Arch/x86_64/tls.cpp b/Userland/Libraries/LibELF/Arch/x86_64/tls.cpp deleted file mode 100644 index ae31698d0ed..00000000000 --- a/Userland/Libraries/LibELF/Arch/x86_64/tls.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2024, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace ELF { - -void set_thread_pointer_register(FlatPtr value) -{ - // TODO: Consider if we want to support the FSGSBASE extension: https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/best-practices/guidance-enabling-fsgsbase.html - VERIFY(archctl(ARCHCTL_X86_64_SET_FS_BASE_FOR_CURRENT_THREAD, value) == 0); -} - -} diff --git a/Userland/Libraries/LibELF/Arch/x86_64/tls.h b/Userland/Libraries/LibELF/Arch/x86_64/tls.h deleted file mode 100644 index 2d44059a458..00000000000 --- a/Userland/Libraries/LibELF/Arch/x86_64/tls.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2024, Sönke Holz - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace ELF { - -struct ThreadControlBlock { - // The %fs segment register is the thread pointer register on x86-64. - // x86-64 uses variant II of the TLS data structures described in "ELF Handling For Thread-Local Storage", - // which requires the thread pointer to point to the TCB. - // That document also requires that the pointer shall be accessible with "movq %fs:0, %", - // so the first member in the TCB has to be a copy of the thread pointer. - void* thread_pointer; - - // Variant II requires that the TCB has to contain a pointer to the dtv at an unspecified offset. - // This member is unused, as we currently only support static TLS blocks. - void* dynamic_thread_vector; -}; - -static constexpr size_t TLS_VARIANT = 2; -static constexpr size_t TLS_DTV_OFFSET = 0; -static constexpr size_t TLS_TP_STATIC_TLS_BLOCK_OFFSET = 0; - -// x86-64 ELF TLS Layout -// The padding is needed so tp (fs_base) is correctly aligned. -// -// [.....static TLS][..padding..][TCB] -// ^tp (fs_base) - -inline size_t calculate_static_tls_region_size(size_t tls_template_size, size_t tls_alignment) -{ - return align_up_to(tls_template_size, tls_alignment) + sizeof(ThreadControlBlock); -} - -inline FlatPtr calculate_tp_value_from_static_tls_region_address(FlatPtr static_tls_region_address, size_t tls_template_size, size_t tls_alignment) -{ - return static_tls_region_address + align_up_to(tls_template_size, tls_alignment); -} - -inline ThreadControlBlock* get_tcb_pointer_from_thread_pointer(FlatPtr thread_pointer) -{ - return bit_cast(thread_pointer); -} - -inline void* get_pointer_to_first_static_tls_block_from_thread_pointer(FlatPtr thread_pointer, size_t tls_template_size, size_t tls_alignment) -{ - return bit_cast(thread_pointer - align_up_to(tls_template_size, tls_alignment)); -} - -inline void* get_pointer_to_static_tls_region_from_thread_pointer(FlatPtr thread_pointer, size_t tls_template_size, size_t tls_alignment) -{ - return bit_cast(thread_pointer - align_up_to(tls_template_size, tls_alignment)); -} - -} diff --git a/Userland/Libraries/LibELF/AuxiliaryVector.h b/Userland/Libraries/LibELF/AuxiliaryVector.h deleted file mode 100644 index 80f4e847cff..00000000000 --- a/Userland/Libraries/LibELF/AuxiliaryVector.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -static_assert(sizeof(auxv_t) % sizeof(FlatPtr) == 0); - -namespace ELF { - -struct AuxiliaryValue { - enum Type { - Null = AT_NULL, - Ignore = AT_IGNORE, - ExecFileDescriptor = AT_EXECFD, - Phdr = AT_PHDR, - Phent = AT_PHENT, - Phnum = AT_PHNUM, - PageSize = AT_PAGESZ, - BaseAddress = AT_BASE, - Flags = AT_FLAGS, - Entry = AT_ENTRY, - NotELF = AT_NOTELF, - Uid = AT_UID, - EUid = AT_EUID, - Gid = AT_GID, - EGid = AT_EGID, - Platform = AT_PLATFORM, - HwCap = AT_HWCAP, - ClockTick = AT_CLKTCK, - Secure = AT_SECURE, - BasePlatform = AT_BASE_PLATFORM, - Random = AT_RANDOM, - HwCap2 = AT_HWCAP2, - ExecFilename = AT_EXECFN, - ExeBaseAddress = AT_EXE_BASE, - ExeSize = AT_EXE_SIZE - }; - - AuxiliaryValue(Type type, long val) - { - auxv.a_type = type; - auxv.a_un.a_val = val; - } - AuxiliaryValue(Type type, void* ptr) - { - auxv.a_type = type; - auxv.a_un.a_ptr = (void*)ptr; - } - AuxiliaryValue(Type type, StringView string) - : optional_string(string) - { - auxv.a_type = type; - auxv.a_un.a_ptr = nullptr; - } - - auxv_t auxv {}; - StringView optional_string; -}; - -} diff --git a/Userland/Libraries/LibELF/CMakeLists.txt b/Userland/Libraries/LibELF/CMakeLists.txt deleted file mode 100644 index 40cb30a04e9..00000000000 --- a/Userland/Libraries/LibELF/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -set(SOURCES - Image.cpp - Validation.cpp -) - -serenity_install_headers("LibELF") -serenity_install_sources("Userland/Libraries/LibELF") - -if (SERENITYOS) - list(APPEND SOURCES - Arch/${SERENITY_ARCH}/entry.S - Arch/${SERENITY_ARCH}/plt_trampoline.S - Arch/${SERENITY_ARCH}/tls.cpp - DynamicLinker.cpp - DynamicLoader.cpp - DynamicObject.cpp - ELFBuild.cpp - Relocation.cpp - ) - - if (SERENITY_ARCH STREQUAL "aarch64") - list(APPEND SOURCES - Arch/aarch64/tls.S - ) - endif() - - add_library(DynamicLoader_LibELF STATIC ${SOURCES}) - target_link_libraries(DynamicLoader_LibELF - PUBLIC DynamicLoader_CompileOptions - PRIVATE DynamicLoader_LibC - ) -endif() - -serenity_lib(LibELF elf ${SOURCES}) -target_link_libraries(LibELF PRIVATE LibSystem) diff --git a/Userland/Libraries/LibELF/Core.h b/Userland/Libraries/LibELF/Core.h deleted file mode 100644 index ac0ac5962d8..00000000000 --- a/Userland/Libraries/LibELF/Core.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -#ifndef KERNEL -# include -#endif - -namespace ELF::Core { - -struct [[gnu::packed]] NotesEntryHeader { - enum Type : u8 { - Null = 0, // Terminates segment - ProcessInfo, - ThreadInfo, - MemoryRegionInfo, - Metadata, - }; - Type type; -}; - -struct [[gnu::packed]] NotesEntry { - NotesEntryHeader header; - char data[]; -}; - -struct [[gnu::packed]] ProcessInfo { - NotesEntryHeader header; - // Information is stored as JSON blob to allow arbitrary - // number and length of strings/objects/arrays. - // - // Keys: - // - "pid" (int) - // - "termination_signal" (u8) - // - "executable_path" (ByteString) - // - "arguments" (Vector) - // - "environment" (Vector) - char json_data[]; // Null terminated -}; - -struct [[gnu::packed]] ThreadInfo { - NotesEntryHeader header; - int tid; - PtraceRegisters regs; -}; - -struct [[gnu::packed]] MemoryRegionInfo { - NotesEntryHeader header; - uint64_t region_start; - uint64_t region_end; - uint16_t program_header_index; - char region_name[]; // Null terminated - -#ifndef KERNEL - ByteString object_name() const - { - StringView memory_region_name { region_name, strlen(region_name) }; - if (memory_region_name.contains("Loader.so"sv)) - return "Loader.so"sv; - auto maybe_colon_index = memory_region_name.find(':'); - if (!maybe_colon_index.has_value()) - return {}; - return memory_region_name.substring_view(0, *maybe_colon_index).to_byte_string(); - } -#endif -}; - -struct [[gnu::packed]] Metadata { - NotesEntryHeader header; - // Arbitrary metadata, set via SC_set_coredump_metadata. - // Limited to 16 entries and 16 KiB keys/values by the kernel. - // - // Well-known keys: - // - "assertion": Used by LibC's __assertion_failed() to store assertion info - // - "pledge_violation": Used by the Kernel's require_promise() to store pledge violation info - char json_data[]; // Null terminated -}; - -} diff --git a/Userland/Libraries/LibELF/DynamicLinker.cpp b/Userland/Libraries/LibELF/DynamicLinker.cpp deleted file mode 100644 index e2c06051d35..00000000000 --- a/Userland/Libraries/LibELF/DynamicLinker.cpp +++ /dev/null @@ -1,773 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. - * Copyright (c) 2021, Andreas Kling - * Copyright (c) 2021, the SerenityOS developers. - * Copyright (c) 2022, Jesse Buhagiar - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ELF { - -static ByteString s_main_program_path; - -// The order of objects here corresponds to the "load order" from POSIX specification. -static OrderedHashMap> s_global_objects; - -using LibCExitFunction = void (*)(int); -using DlIteratePhdrCallbackFunction = int (*)(struct dl_phdr_info*, size_t, void*); -using DlIteratePhdrFunction = int (*)(DlIteratePhdrCallbackFunction, void*); -using CallFiniFunctionsFunction = void (*)(); - -struct TLSData { - size_t total_tls_size { 0 }; - void* tls_template { nullptr }; - size_t tls_template_size { 0 }; - size_t alignment { 0 }; - size_t static_tls_region_size { 0 }; - size_t static_tls_region_alignment { 0 }; -}; -static TLSData s_tls_data; - -static char** s_envp = nullptr; -static __pthread_mutex_t s_loader_lock = __PTHREAD_MUTEX_INITIALIZER; -static ByteString s_cwd; - -static bool s_allowed_to_check_environment_variables { false }; -static bool s_do_breakpoint_trap_before_entry { false }; -static StringView s_ld_library_path; -static StringView s_main_program_pledge_promises; -static ByteString s_loader_pledge_promises; - -static HashMap s_magic_functions; - -Optional DynamicLinker::lookup_global_symbol(StringView name) -{ - auto symbol = DynamicObject::HashSymbol { name }; - - for (auto& lib : s_global_objects) { - auto res = lib.value->lookup_symbol(symbol); - if (!res.has_value()) - continue; - if (res.value().bind == STB_GLOBAL || res.value().bind == STB_WEAK) - return res; - // We don't want to allow local symbols to be pulled in to other modules - } - - if (auto magic_lookup = s_magic_functions.get(name); magic_lookup.has_value()) - return *magic_lookup; - return {}; -} - -static Result, DlErrorMessage> map_library(ByteString const& filepath, int fd) -{ - VERIFY(filepath.starts_with('/')); - - auto loader = TRY(ELF::DynamicLoader::try_create(fd, filepath)); - - static size_t s_current_tls_offset = 0; - - if constexpr (TLS_VARIANT == 1) { - if (loader->tls_alignment_of_current_object() != 0) - s_current_tls_offset = align_up_to(s_current_tls_offset, loader->tls_alignment_of_current_object()); - loader->set_tls_offset(s_current_tls_offset); - - s_current_tls_offset += loader->tls_size_of_current_object(); - } else if constexpr (TLS_VARIANT == 2) { - s_current_tls_offset -= loader->tls_size_of_current_object(); - if (loader->tls_alignment_of_current_object() != 0) - s_current_tls_offset = align_down_to(s_current_tls_offset, loader->tls_alignment_of_current_object()); - loader->set_tls_offset(s_current_tls_offset); - } - - // This actually maps the library at the intended and final place. - auto main_library_object = loader->map(); - s_global_objects.set(filepath, *main_library_object); - - return loader; -} - -Optional DynamicLinker::resolve_library(ByteString const& name, DynamicObject const& parent_object) -{ - // Absolute and relative (to the current working directory) paths are already considered resolved. - // However, ensure that the returned path is absolute and canonical, so pass it through LexicalPath. - if (name.contains('/')) - return LexicalPath::absolute_path(s_cwd, name); - - Vector search_paths; - - // Search RPATH values indicated by the ELF (only if RUNPATH is not present). - if (parent_object.runpath().is_empty()) - search_paths.extend(parent_object.rpath().split_view(':')); - - // Scan the LD_LIBRARY_PATH environment variable if applicable. - search_paths.extend(s_ld_library_path.split_view(':')); - - // Search RUNPATH values indicated by the ELF. - search_paths.extend(parent_object.runpath().split_view(':')); - - // Last are the default search paths. - search_paths.append("/usr/lib"sv); - search_paths.append("/usr/local/lib"sv); - - for (auto const& search_path : search_paths) { - LexicalPath library_path(search_path.replace("$ORIGIN"sv, LexicalPath::dirname(parent_object.filepath()), ReplaceMode::FirstOnly)); - ByteString library_name = library_path.append(name).string(); - - if (access(library_name.characters(), F_OK) == 0) { - if (!library_name.starts_with('/')) { - // FIXME: Non-absolute paths should resolve from the current working directory. However, - // since that's almost never the effect that is actually desired, let's print - // a warning and only implement it once something actually needs that behavior. - dbgln("\033[33mWarning:\033[0m Resolving library '{}' resulted in non-absolute path '{}'. Check your binary for relative RPATHs and RUNPATHs.", name, library_name); - } - - return library_name; - } - } - - return {}; -} - -static Result, DlErrorMessage> map_library(ByteString const& path) -{ - VERIFY(path.starts_with('/')); - - int fd = open(path.characters(), O_RDONLY); - if (fd < 0) - return DlErrorMessage { ByteString::formatted("Could not open shared library '{}': {}", path, strerror(errno)) }; - - return map_library(path, fd); -} - -static Vector get_dependencies(NonnullRefPtr const& loader) -{ - auto name = LexicalPath::basename(loader->filepath()); - Vector dependencies; - - loader->for_each_needed_library([&dependencies, &name](auto needed_name) { - if (name == needed_name) - return; - dependencies.append(needed_name); - }); - return dependencies; -} - -struct DependencyOrdering { - Vector> load_order; - // In addition to "load order" (and "dependency order") from POSIX, we also define "topological - // order". This is a topological ordering of "NEEDED" dependencies, where we ignore edges that - // result in cycles. Edges that are not ignored are called true dependencies. - Vector> topological_order; -}; - -static ErrorOr map_dependencies(NonnullRefPtr const& loader) -{ - Vector> load_order = { loader }; - HashMap> current_loaders; - current_loaders.set(loader->filepath(), loader); - - // First, we do BFS on NEEDED dependencies graph while using load_order as a poor man's queue. - // NOTE: BFS is mandated by POSIX: https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html#:~:text=Dependency%20ordering%20uses%20a%20breadth%2Dfirst%20order%20starting . - for (size_t i = 0; i < load_order.size(); ++i) { - auto loader = load_order[i]; - auto const& parent_object = loader->dynamic_object(); - - dbgln_if(DYNAMIC_LOAD_DEBUG, "mapping dependencies for: {}", loader->filepath()); - - for (auto const& needed_name : get_dependencies(loader)) { - dbgln_if(DYNAMIC_LOAD_DEBUG, "needed library: {}", needed_name.characters()); - - auto maybe_dependency_path = DynamicLinker::resolve_library(needed_name, parent_object); - if (!maybe_dependency_path.has_value()) - return DlErrorMessage { ByteString::formatted("Could not find required shared library: {}", needed_name) }; - auto dependency_path = maybe_dependency_path.release_value(); - - if (!s_global_objects.contains(dependency_path)) { - auto dependency_loader = TRY(map_library(dependency_path)); - load_order.append(dependency_loader); - current_loaders.set(dependency_loader->filepath(), dependency_loader); - } - if (auto it = current_loaders.find(dependency_path); it != current_loaders.end()) { - // Even if the object is already mapped, the dependency might still affect topological order. - loader->add_dependency(it->value); - } - } - - dbgln_if(DYNAMIC_LOAD_DEBUG, "mapped dependencies for {}", loader->filepath()); - } - - // Next, we compute topological order using the classical algorithm involving DFS. Topological - // ordering is used for calling initializers: https://www.sco.com/developers/gabi/latest/ch5.dynamic.html#init_fini . - Vector> topological_order; - topological_order.ensure_capacity(load_order.size()); - loader->compute_topological_order(topological_order); - - VERIFY(topological_order.size() == load_order.size()); - VERIFY(topological_order.last()->filepath() == loader->filepath()); - - return DependencyOrdering { - .load_order = move(load_order), - .topological_order = move(topological_order), - }; -} - -static ErrorOr __create_new_tls_region() -{ - void* static_tls_region = serenity_mmap(nullptr, s_tls_data.static_tls_region_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0, s_tls_data.static_tls_region_alignment, "Static TLS Data"); - if (static_tls_region == MAP_FAILED) - return Error::from_syscall("mmap"sv, -errno); - - auto thread_pointer = calculate_tp_value_from_static_tls_region_address(bit_cast(static_tls_region), s_tls_data.tls_template_size, s_tls_data.static_tls_region_alignment); - VERIFY(thread_pointer % s_tls_data.static_tls_region_alignment == 0); - - auto* tcb = get_tcb_pointer_from_thread_pointer(thread_pointer); - - // FIXME: Add support for dynamically-allocated TLS blocks. - tcb->dynamic_thread_vector = nullptr; - -#if ARCH(X86_64) - tcb->thread_pointer = bit_cast(thread_pointer); -#endif - - auto* static_tls_blocks = get_pointer_to_first_static_tls_block_from_thread_pointer(thread_pointer, s_tls_data.tls_template_size, s_tls_data.static_tls_region_alignment); - - if (s_tls_data.tls_template_size != 0) - memcpy(static_tls_blocks, s_tls_data.tls_template, s_tls_data.tls_template_size); - - return thread_pointer; -} - -static ErrorOr __free_tls_region(FlatPtr thread_pointer) -{ - auto* static_tls_region = get_pointer_to_static_tls_region_from_thread_pointer(thread_pointer, s_tls_data.tls_template_size, s_tls_data.static_tls_region_alignment); - - if (munmap(static_tls_region, s_tls_data.static_tls_region_size) != 0) - return Error::from_syscall("mmap"sv, -errno); - - return {}; -} - -static void allocate_tls(Vector> const& loaded_objects) -{ - // FIXME: Use the max p_align of all TLS segments. - // We currently pass s_tls_data.static_tls_region_alignment as the alignment to mmap, - // so we would have to manually insert padding, as mmap only accepts alignments that - // are multiples of PAGE_SIZE. Or instead use aligned_alloc/posix_memalign? - s_tls_data.alignment = PAGE_SIZE; - - for (auto const& object : loaded_objects) { - dbgln_if(DYNAMIC_LOAD_DEBUG, "{}: TLS Size: {}, TLS Alignment: {}", object->filepath(), object->tls_size_of_current_object(), object->tls_alignment_of_current_object()); - s_tls_data.total_tls_size += object->tls_size_of_current_object() + object->tls_alignment_of_current_object(); - } - - if (s_tls_data.total_tls_size == 0) - return; - - s_tls_data.tls_template_size = align_up_to(s_tls_data.total_tls_size, PAGE_SIZE); - s_tls_data.tls_template = mmap_with_name(nullptr, s_tls_data.tls_template_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0, "TLS Template"); - - if (s_tls_data.tls_template == MAP_FAILED) { - dbgln("Failed to allocate memory for the TLS template"); - VERIFY_NOT_REACHED(); - } - - s_tls_data.static_tls_region_alignment = max(s_tls_data.alignment, sizeof(ThreadControlBlock)); - s_tls_data.static_tls_region_size = calculate_static_tls_region_size(s_tls_data.tls_template_size, s_tls_data.static_tls_region_alignment); - - auto tls_template = Bytes(s_tls_data.tls_template, s_tls_data.tls_template_size); - - // Initialize TLS data - for (auto const& object : loaded_objects) - object->copy_initial_tls_data_into(tls_template); - - set_thread_pointer_register(MUST(__create_new_tls_region())); -} - -static int __dl_iterate_phdr(DlIteratePhdrCallbackFunction callback, void* data) -{ - pthread_mutex_lock(&s_loader_lock); - ScopeGuard unlock_guard = [] { pthread_mutex_unlock(&s_loader_lock); }; - - for (auto& it : s_global_objects) { - auto& object = it.value; - auto info = dl_phdr_info { - .dlpi_addr = (Elf_Addr)object->base_address().as_ptr(), - .dlpi_name = object->filepath().characters(), - .dlpi_phdr = object->program_headers(), - .dlpi_phnum = object->program_header_count() - }; - - auto res = callback(&info, sizeof(info), data); - if (res != 0) - return res; - } - - return 0; -} - -int DynamicLinker::iterate_over_loaded_shared_objects(int (*callback)(struct dl_phdr_info* info, size_t size, void* data), void* data) -{ - return __dl_iterate_phdr(callback, data); -} - -static void initialize_libc(DynamicObject& libc) -{ - auto res = libc.lookup_symbol("__libc_init"sv); - VERIFY(res.has_value()); - using libc_init_func = decltype(__libc_init); - ((libc_init_func*)res.value().address.as_ptr())(); -} - -static void drop_loader_promise(StringView promise_to_drop) -{ - if (s_main_program_pledge_promises.is_empty() || s_loader_pledge_promises.is_empty()) - return; - - s_loader_pledge_promises = s_loader_pledge_promises.replace(promise_to_drop, ""sv, ReplaceMode::All); - - auto extended_promises = ByteString::formatted("{} {}", s_main_program_pledge_promises, s_loader_pledge_promises); - Syscall::SC_pledge_params params { - { extended_promises.characters(), extended_promises.length() }, - { nullptr, 0 }, - }; - int rc = syscall(SC_pledge, ¶ms); - if (rc < 0 && rc > -EMAXERRNO) { - warnln("Failed to drop loader pledge promise: {}. errno={}", promise_to_drop, errno); - _exit(1); - } -} - -static ErrorOr link_main_library(int flags, DependencyOrdering const& objects) -{ - // Verify that all objects are already mapped - for (auto& loader : objects.load_order) - VERIFY(!loader->map()); - - // FIXME: Are there any observable differences between doing stages 2 and 3 in topological vs - // load order? POSIX says to do relocations in load order but does the order really - // matter here? - for (auto& loader : objects.load_order) { - bool success = loader->link(flags); - if (!success) { - return DlErrorMessage { ByteString::formatted("Failed to link library {}", loader->filepath()) }; - } - } - - for (auto& loader : objects.load_order) { - auto result = loader->load_stage_3(flags); - VERIFY(!result.is_error()); - auto& object = result.value(); - - if (loader->filepath().ends_with("/libc.so"sv)) { - initialize_libc(*object); - } - - if (loader->filepath().ends_with("/libsystem.so"sv)) { - VERIFY(!loader->text_segments().is_empty()); - for (auto const& segment : loader->text_segments()) { - auto flags = static_cast(VirtualMemoryRangeFlags::SyscallCode) | static_cast(VirtualMemoryRangeFlags::Immutable); - if (syscall(SC_annotate_mapping, segment.address().get(), flags)) { - VERIFY_NOT_REACHED(); - } - } - } else { - for (auto const& segment : loader->text_segments()) { - auto flags = static_cast(VirtualMemoryRangeFlags::Immutable); - if (syscall(SC_annotate_mapping, segment.address().get(), flags)) { - VERIFY_NOT_REACHED(); - } - } - } - } - - drop_loader_promise("prot_exec"sv); - - for (auto& loader : objects.topological_order) - loader->load_stage_4(); - - return {}; -} - -static Result __dlclose(void* handle) -{ - dbgln_if(DYNAMIC_LOAD_DEBUG, "__dlclose: {}", handle); - - pthread_mutex_lock(&s_loader_lock); - ScopeGuard unlock_guard = [] { pthread_mutex_unlock(&s_loader_lock); }; - - // FIXME: this will not currently destroy the dynamic object - // because we're intentionally holding a strong reference to it - // via s_global_objects until there's proper unload support. - auto object = static_cast(handle); - object->unref(); - return {}; -} - -static Optional verify_tls_for_dlopen(DynamicLoader const& loader) -{ - if (loader.tls_size_of_current_object() == 0) - return {}; - - if (s_tls_data.total_tls_size + loader.tls_size_of_current_object() + loader.tls_alignment_of_current_object() > s_tls_data.tls_template_size) - return DlErrorMessage("TLS size too large"); - - bool tls_data_is_all_zero = true; - loader.image().for_each_program_header([&loader, &tls_data_is_all_zero](ELF::Image::ProgramHeader program_header) { - if (program_header.type() != PT_TLS) - return IterationDecision::Continue; - - auto* tls_data = (u8 const*)loader.image().base_address() + program_header.offset(); - for (size_t i = 0; i < program_header.size_in_image(); ++i) { - if (tls_data[i] != 0) { - tls_data_is_all_zero = false; - break; - } - } - return IterationDecision::Break; - }); - - if (tls_data_is_all_zero) - return {}; - - return DlErrorMessage("Using dlopen() with libraries that have non-zeroed TLS is currently not supported"); -} - -static Result __dlopen(char const* filename, int flags) -{ - // FIXME: RTLD_NOW and RTLD_LOCAL are not supported - flags &= ~RTLD_NOW; - flags |= RTLD_LAZY; - flags &= ~RTLD_LOCAL; - flags |= RTLD_GLOBAL; - - dbgln_if(DYNAMIC_LOAD_DEBUG, "__dlopen invoked, filename={}, flags={}", filename, flags); - - if (pthread_mutex_trylock(&s_loader_lock) != 0) - return DlErrorMessage { "Nested calls to dlopen() are not permitted." }; - ScopeGuard unlock_guard = [] { pthread_mutex_unlock(&s_loader_lock); }; - - // FIXME: We must resolve filename relative to the caller, not the main executable. - auto const& [name, parent_object] = *s_global_objects.begin(); - VERIFY(name == s_main_program_path); - - auto library_path = (filename ? DynamicLinker::resolve_library(filename, parent_object) : s_main_program_path); - - if (!library_path.has_value()) - return DlErrorMessage { ByteString::formatted("Could not find required shared library: {}", filename) }; - - auto existing_elf_object = s_global_objects.get(library_path.value()); - if (existing_elf_object.has_value()) { - // It's up to the caller to release the ref with dlclose(). - existing_elf_object.value()->ref(); - return *existing_elf_object; - } - - auto loader = TRY(map_library(library_path.value())); - - // FIXME: This only checks main shared object but not its dependencies. - if (auto error = verify_tls_for_dlopen(loader); error.has_value()) - return error.value(); - - auto objects = TRY(map_dependencies(loader)); - - TRY(link_main_library(flags, objects)); - - s_tls_data.total_tls_size += loader->tls_size_of_current_object() + loader->tls_alignment_of_current_object(); - - auto object = s_global_objects.get(library_path.value()); - if (!object.has_value()) - return DlErrorMessage { "Could not load ELF object." }; - - // It's up to the caller to release the ref with dlclose(). - object.value()->ref(); - return *object; -} - -static Result __dlsym(void* handle, char const* symbol_name) -{ - dbgln_if(DYNAMIC_LOAD_DEBUG, "__dlsym: {}, {}", handle, symbol_name); - - pthread_mutex_lock(&s_loader_lock); - ScopeGuard unlock_guard = [] { pthread_mutex_unlock(&s_loader_lock); }; - - StringView symbol_name_view { symbol_name, strlen(symbol_name) }; - Optional symbol; - - if (handle) { - auto object = static_cast(handle); - symbol = object->lookup_symbol(symbol_name_view); - } else { - // When handle is 0 (RTLD_DEFAULT) we should look up the symbol in all global modules - // https://pubs.opengroup.org/onlinepubs/009604499/functions/dlsym.html - symbol = DynamicLinker::lookup_global_symbol(symbol_name_view); - } - - if (!symbol.has_value()) - return DlErrorMessage { ByteString::formatted("Symbol {} not found", symbol_name_view) }; - - if (symbol.value().type == STT_GNU_IFUNC) - return (void*)reinterpret_cast(symbol.value().address.as_ptr())(); - return symbol.value().address.as_ptr(); -} - -static Result __dladdr(void const* addr, Dl_info* info) -{ - VirtualAddress user_addr { addr }; - pthread_mutex_lock(&s_loader_lock); - ScopeGuard unlock_guard = [] { pthread_mutex_unlock(&s_loader_lock); }; - - RefPtr best_matching_library; - VirtualAddress best_library_offset; - for (auto& lib : s_global_objects) { - if (user_addr < lib.value->base_address()) - continue; - auto offset = user_addr - lib.value->base_address(); - if (!best_matching_library || offset < best_library_offset) { - best_matching_library = lib.value; - best_library_offset = offset; - } - } - - if (!best_matching_library) { - return DlErrorMessage { "No library found which contains the specified address" }; - } - - Optional best_matching_symbol; - best_matching_library->for_each_symbol([&](auto const& symbol) { - if (user_addr < symbol.address() || user_addr > symbol.address().offset(symbol.size())) - return; - best_matching_symbol = symbol; - }); - - info->dli_fbase = best_matching_library->base_address().as_ptr(); - // This works because we don't support unloading objects. - info->dli_fname = best_matching_library->filepath().characters(); - if (best_matching_symbol.has_value()) { - info->dli_saddr = best_matching_symbol.value().address().as_ptr(); - info->dli_sname = best_matching_symbol.value().raw_name(); - } else { - info->dli_saddr = nullptr; - info->dli_sname = nullptr; - } - return {}; -} - -static void __call_fini_functions() -{ - typedef void (*FiniFunc)(); - - // FIXME: This is not and never has been the correct order to call finalizers in. - for (auto& it : s_global_objects) { - auto object = it.value; - - if (object->has_fini_array_section()) { - auto fini_array_section = object->fini_array_section(); - - FiniFunc* fini_begin = (FiniFunc*)(fini_array_section.address().as_ptr()); - FiniFunc* fini_end = fini_begin + fini_array_section.entry_count(); - while (fini_begin != fini_end) { - --fini_end; - - // Android sources claim that these can be -1, to be ignored. - // 0 deffiniely shows up. Apparently 0/-1 are valid? Confusing. - if (!*fini_end || ((FlatPtr)*fini_end == (FlatPtr)-1)) - continue; - (*fini_end)(); - } - } - - if (object->has_fini_section()) { - auto fini_function = object->fini_section_function(); - (fini_function)(); - } - } -} - -static char** __environ_value() -{ - return s_envp; -} - -static void read_environment_variables() -{ - for (char** env = s_envp; *env; ++env) { - StringView env_string { *env, strlen(*env) }; - if (env_string == "_LOADER_BREAKPOINT=1"sv) { - s_do_breakpoint_trap_before_entry = true; - } - - constexpr auto library_path_string = "LD_LIBRARY_PATH="sv; - if (env_string.starts_with(library_path_string)) { - s_ld_library_path = env_string.substring_view(library_path_string.length()); - } - - constexpr auto main_pledge_promises_key = "_LOADER_MAIN_PROGRAM_PLEDGE_PROMISES="sv; - if (env_string.starts_with(main_pledge_promises_key)) { - s_main_program_pledge_promises = env_string.substring_view(main_pledge_promises_key.length()); - } - - constexpr auto loader_pledge_promises_key = "_LOADER_PLEDGE_PROMISES="sv; - if (env_string.starts_with(loader_pledge_promises_key)) { - s_loader_pledge_promises = env_string.substring_view(loader_pledge_promises_key.length()); - } - } -} - -EntryPointFunction ELF::DynamicLinker::linker_main(ByteString&& main_program_path, int main_program_fd, bool is_secure, char** envp) -{ - VERIFY(main_program_path.starts_with('/')); - - s_envp = envp; - - auto define_magic_function = [&](StringView name, auto function) { - s_magic_functions.set(name, - DynamicObject::SymbolLookupResult { - .size = 8, - .address = VirtualAddress { reinterpret_cast(function) }, - .bind = STB_GLOBAL, - .type = STT_FUNC, - }); - }; - define_magic_function("__call_fini_functions"sv, __call_fini_functions); - define_magic_function("__create_new_tls_region"sv, __create_new_tls_region); - define_magic_function("__dl_iterate_phdr"sv, __dl_iterate_phdr); - define_magic_function("__dladdr"sv, __dladdr); - define_magic_function("__dlclose"sv, __dlclose); - define_magic_function("__dlopen"sv, __dlopen); - define_magic_function("__dlsym"sv, __dlsym); - define_magic_function("__environ_value"sv, __environ_value); - define_magic_function("__free_tls_region"sv, __free_tls_region); - - char* raw_current_directory = getcwd(nullptr, 0); - s_cwd = raw_current_directory; - free(raw_current_directory); - - s_allowed_to_check_environment_variables = !is_secure; - if (s_allowed_to_check_environment_variables) - read_environment_variables(); - - s_main_program_path = main_program_path; - - // NOTE: We always map the main library first, since it may require - // placement at a specific address. - auto result1 = map_library(main_program_path, main_program_fd); - if (result1.is_error()) { - warnln("{}", result1.error().text); - fflush(stderr); - _exit(1); - } - - auto executable = result1.release_value(); - size_t needed_dependencies = 0; - executable->for_each_needed_library([&needed_dependencies](auto) { - needed_dependencies++; - }); - bool has_interpreter = false; - executable->image().for_each_program_header([&has_interpreter](const ELF::Image::ProgramHeader& program_header) { - if (program_header.type() == PT_INTERP) - has_interpreter = true; - }); - // NOTE: Refuse to run a program if it has a dynamic section, - // it is pie, and does not have an interpreter or needed libraries - // which is also called "static-pie". These binaries are probably - // some sort of ELF packers or dynamic loaders, and there's no added - // value in trying to run them, as they will probably crash due to trying - // to invoke syscalls from a non-syscall memory executable (code) region. - if (executable->is_dynamic() && (!has_interpreter || needed_dependencies == 0) && executable->dynamic_object().is_pie()) { - char const message[] = R"(error: the dynamic loader can't reasonably run static-pie ELF. static-pie ELFs might run executable code that invokes syscalls -outside of the defined syscall memory executable (code) region security measure we implement. -Examples of static-pie ELF objects are ELF packers, and the system dynamic loader itself.)"; - fprintf(stderr, "%s", message); - fflush(stderr); - _exit(1); - } - - auto result2 = map_dependencies(executable); - if (result2.is_error()) { - warnln("{}", result2.error().text); - fflush(stderr); - _exit(1); - } - - auto objects = result2.release_value(); - - dbgln_if(DYNAMIC_LOAD_DEBUG, "loaded all dependencies"); - for ([[maybe_unused]] auto& object : objects.load_order) { - dbgln_if(DYNAMIC_LOAD_DEBUG, "{} - tls size: {}, tls alignment: {}, tls offset: {}", - object->filepath(), object->tls_size_of_current_object(), object->tls_alignment_of_current_object(), object->tls_offset()); - } - - allocate_tls(objects.load_order); - - auto result = link_main_library(RTLD_GLOBAL | RTLD_LAZY, objects); - if (result.is_error()) { - warnln("{}", result.error().text); - _exit(1); - } - - drop_loader_promise("rpath"sv); - - auto& main_executable_loader = objects.load_order.first(); - auto entry_point = main_executable_loader->image().entry(); - if (main_executable_loader->is_dynamic()) - entry_point = entry_point.offset(main_executable_loader->base_address().get()); - auto entry_point_function = reinterpret_cast(entry_point.as_ptr()); - - int rc = syscall(SC_prctl, PR_SET_NO_NEW_SYSCALL_REGION_ANNOTATIONS, 0, 0, nullptr); - if (rc < 0) { - VERIFY_NOT_REACHED(); - } - - rc = syscall(SC_prctl, PR_SET_NO_TRANSITION_TO_EXECUTABLE_FROM_WRITABLE_PROT, 0, 0, nullptr); - if (rc < 0) { - VERIFY_NOT_REACHED(); - } - - dbgln_if(DYNAMIC_LOAD_DEBUG, "Jumping to entry point: {:p}", entry_point_function); - if (s_do_breakpoint_trap_before_entry) { -#if ARCH(AARCH64) - asm("brk #0"); -#elif ARCH(RISCV64) - asm("ebreak"); -#elif ARCH(X86_64) - asm("int3"); -#else -# error "Unknown architecture" -#endif - } - - return entry_point_function; -} - -} diff --git a/Userland/Libraries/LibELF/DynamicLinker.h b/Userland/Libraries/LibELF/DynamicLinker.h deleted file mode 100644 index 64e7d0bb6ee..00000000000 --- a/Userland/Libraries/LibELF/DynamicLinker.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2021, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace ELF { - -using EntryPointFunction = int (*)(int, char**, char**); - -class DynamicLinker { -public: - static Optional lookup_global_symbol(StringView symbol); - static EntryPointFunction linker_main(ByteString&& main_program_path, int fd, bool is_secure, char** envp); - static int iterate_over_loaded_shared_objects(int (*callback)(struct dl_phdr_info* info, size_t size, void* data), void* data); - - static Optional resolve_library(ByteString const& name, DynamicObject const& parent_object); - -private: - DynamicLinker() = delete; - ~DynamicLinker() = delete; -}; - -} diff --git a/Userland/Libraries/LibELF/DynamicLoader.cpp b/Userland/Libraries/LibELF/DynamicLoader.cpp deleted file mode 100644 index 779316d089a..00000000000 --- a/Userland/Libraries/LibELF/DynamicLoader.cpp +++ /dev/null @@ -1,845 +0,0 @@ -/* - * Copyright (c) 2019-2020, Andrew Kaster - * Copyright (c) 2020, Itamar S. - * Copyright (c) 2021, Andreas Kling - * Copyright (c) 2022-2023, Daniel Bertalan - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef AK_OS_SERENITY -static void* mmap_with_name(void* addr, size_t length, int prot, int flags, int fd, off_t offset, char const*) -{ - return mmap(addr, length, prot, flags, fd, offset); -} - -# define MAP_RANDOMIZED 0 -#endif - -#if ARCH(AARCH64) -# define HAS_TLSDESC_SUPPORT -extern "C" { -void* __tlsdesc_static(void*); -} -#endif - -namespace ELF { - -Result, DlErrorMessage> DynamicLoader::try_create(int fd, ByteString filepath) -{ - VERIFY(filepath.starts_with('/')); - - struct stat stat; - if (fstat(fd, &stat) < 0) { - return DlErrorMessage { "DynamicLoader::try_create fstat" }; - } - - VERIFY(stat.st_size >= 0); - auto size = static_cast(stat.st_size); - if (size < sizeof(Elf_Ehdr)) - return DlErrorMessage { ByteString::formatted("File {} has invalid ELF header", filepath) }; - - ByteString file_mmap_name = ByteString::formatted("ELF_DYN: {}", filepath); - auto* data = mmap_with_name(nullptr, size, PROT_READ, MAP_SHARED, fd, 0, file_mmap_name.characters()); - if (data == MAP_FAILED) { - return DlErrorMessage { "DynamicLoader::try_create mmap" }; - } - - auto loader = adopt_ref(*new DynamicLoader(fd, move(filepath), data, size)); - if (!loader->is_valid()) - return DlErrorMessage { "ELF image validation failed" }; - return loader; -} - -DynamicLoader::DynamicLoader(int fd, ByteString filepath, void* data, size_t size) - : m_filepath(move(filepath)) - , m_file_size(size) - , m_image_fd(fd) - , m_file_data(data) -{ - m_elf_image = adopt_own(*new ELF::Image((u8*)m_file_data, m_file_size)); - m_valid = validate(); - if (m_valid) - find_tls_size_and_alignment(); - else - dbgln("Image validation failed for file {}", m_filepath); -} - -DynamicLoader::~DynamicLoader() -{ - if (munmap(m_file_data, m_file_size) < 0) { - perror("munmap"); - VERIFY_NOT_REACHED(); - } - if (close(m_image_fd) < 0) { - perror("close"); - VERIFY_NOT_REACHED(); - } -} - -void DynamicLoader::find_tls_size_and_alignment() -{ - image().for_each_program_header([this](auto program_header) { - if (program_header.type() == PT_TLS) { - m_tls_size_of_current_object = program_header.size_in_memory(); - auto alignment = program_header.alignment(); - VERIFY(!alignment || is_power_of_two(alignment)); - m_tls_alignment_of_current_object = alignment > 1 ? alignment : 0; // No need to reserve extra space for single byte alignment - return IterationDecision::Break; - } - return IterationDecision::Continue; - }); -} - -bool DynamicLoader::validate() -{ - if (!image().is_valid()) - return false; - - auto* elf_header = (Elf_Ehdr*)m_file_data; - if (!validate_elf_header(*elf_header, m_file_size)) - return false; - auto result_or_error = validate_program_headers(*elf_header, m_file_size, { m_file_data, m_file_size }); - if (result_or_error.is_error() || !result_or_error.value()) - return false; - return true; -} - -RefPtr DynamicLoader::map() -{ - if (m_dynamic_object) { - // Already mapped. - return nullptr; - } - - if (!m_valid) { - dbgln("DynamicLoader::map failed: image is invalid"); - return nullptr; - } - - load_program_headers(); - - VERIFY(!m_base_address.is_null()); - - m_dynamic_object = DynamicObject::create(m_filepath, m_base_address, m_dynamic_section_address); - m_dynamic_object->set_tls_offset(m_tls_offset); - m_dynamic_object->set_tls_size(m_tls_size_of_current_object); - - return m_dynamic_object; -} - -bool DynamicLoader::link(unsigned flags) -{ - return load_stage_2(flags); -} - -bool DynamicLoader::load_stage_2(unsigned flags) -{ - VERIFY(flags & RTLD_GLOBAL); - - if (m_dynamic_object->has_text_relocations()) { - dbgln("\033[33mWarning:\033[0m Dynamic object {} has text relocations", m_dynamic_object->filepath()); - for (auto& text_segment : m_text_segments) { - VERIFY(text_segment.address().get() != 0); - -#ifndef AK_OS_MACOS - // Remap this text region as private. - if (mremap(text_segment.address().as_ptr(), text_segment.size(), text_segment.size(), MAP_PRIVATE) == MAP_FAILED) { - perror("mremap .text: MAP_PRIVATE"); - return false; - } -#endif - - if (0 > mprotect(text_segment.address().as_ptr(), text_segment.size(), PROT_READ | PROT_WRITE)) { - perror("mprotect .text: PROT_READ | PROT_WRITE"); // FIXME: dlerror? - return false; - } - } - } else { - // .text needs to be executable while we process relocations because it might contain IFUNC resolvers. - // We don't allow IFUNC resolvers in objects with textrels. - for (auto& text_segment : m_text_segments) { - if (mprotect(text_segment.address().as_ptr(), text_segment.size(), PROT_READ | PROT_EXEC) < 0) { - perror("mprotect .text: PROT_READ | PROT_EXEC"); - return false; - } - } - } - do_main_relocations(); - return true; -} - -void DynamicLoader::do_main_relocations() -{ - do_relr_relocations(); - - Optional cached_result; - m_dynamic_object->relocation_section().for_each_relocation([&](DynamicObject::Relocation const& relocation) { - switch (do_direct_relocation(relocation, cached_result, ShouldCallIfuncResolver::No)) { - case RelocationResult::Failed: - dbgln("Loader.so: {} unresolved symbol '{}'", m_filepath, relocation.symbol().name()); - VERIFY_NOT_REACHED(); - case RelocationResult::CallIfuncResolver: - m_direct_ifunc_relocations.append(relocation); - break; - case RelocationResult::Success: - break; - } - }); - - // If the object is position-independent, the pointer to the PLT trampoline needs to be relocated. - auto fixup_trampoline_pointer = [&](DynamicObject::Relocation const& relocation) { - VERIFY(static_cast(relocation.type()) == GenericDynamicRelocationType::JUMP_SLOT); - if (image().is_dynamic()) - *((FlatPtr*)relocation.address().as_ptr()) += m_dynamic_object->base_address().get(); - }; - - m_dynamic_object->plt_relocation_section().for_each_relocation([&](DynamicObject::Relocation const& relocation) { - if (static_cast(relocation.type()) == GenericDynamicRelocationType::IRELATIVE) { - m_direct_ifunc_relocations.append(relocation); - return; - } - if (static_cast(relocation.type()) == GenericDynamicRelocationType::TLSDESC) { - // GNU ld for some reason puts TLSDESC relocations into .rela.plt - // https://sourceware.org/bugzilla/show_bug.cgi?id=28387 - auto result = do_direct_relocation(relocation, cached_result, ShouldCallIfuncResolver::No); - VERIFY(result == RelocationResult::Success); - return; - } - - // FIXME: Or LD_BIND_NOW is set? - if (m_dynamic_object->must_bind_now()) { - switch (do_plt_relocation(relocation, ShouldCallIfuncResolver::No)) { - case RelocationResult::Failed: - dbgln("Loader.so: {} unresolved symbol '{}'", m_filepath, relocation.symbol().name()); - VERIFY_NOT_REACHED(); - case RelocationResult::CallIfuncResolver: - m_plt_ifunc_relocations.append(relocation); - // Set up lazy binding, in case an IFUNC resolver calls another IFUNC that hasn't been resolved yet. - fixup_trampoline_pointer(relocation); - break; - case RelocationResult::Success: - break; - } - } else { - fixup_trampoline_pointer(relocation); - } - }); -} - -Result, DlErrorMessage> DynamicLoader::load_stage_3(unsigned flags) -{ - if (flags & RTLD_LAZY) { - if (m_dynamic_object->has_plt()) - setup_plt_trampoline(); - } - - // IFUNC resolvers can only be called after the PLT has been populated, - // as they may call arbitrary functions via the PLT. - for (auto const& relocation : m_plt_ifunc_relocations) { - auto result = do_plt_relocation(relocation, ShouldCallIfuncResolver::Yes); - VERIFY(result == RelocationResult::Success); - } - - Optional cached_result; - for (auto const& relocation : m_direct_ifunc_relocations) { - auto result = do_direct_relocation(relocation, cached_result, ShouldCallIfuncResolver::Yes); - VERIFY(result == RelocationResult::Success); - } - - if (m_dynamic_object->has_text_relocations()) { - // If we don't have textrels, .text has already been made executable by this point in load_stage_2. - for (auto& text_segment : m_text_segments) { - if (mprotect(text_segment.address().as_ptr(), text_segment.size(), PROT_READ | PROT_EXEC) < 0) { - return DlErrorMessage { ByteString::formatted("mprotect .text: PROT_READ | PROT_EXEC: {}", strerror(errno)) }; - } - } - } - - if (m_relro_segment_size) { - if (mprotect(m_relro_segment_address.as_ptr(), m_relro_segment_size, PROT_READ) < 0) { - return DlErrorMessage { ByteString::formatted("mprotect .relro: PROT_READ: {}", strerror(errno)) }; - } - -#ifdef AK_OS_SERENITY - if (set_mmap_name(m_relro_segment_address.as_ptr(), m_relro_segment_size, ByteString::formatted("{}: .relro", m_filepath).characters()) < 0) { - return DlErrorMessage { ByteString::formatted("set_mmap_name .relro: {}", strerror(errno)) }; - } -#endif - } - - m_fully_relocated = true; - - return NonnullRefPtr { *m_dynamic_object }; -} - -void DynamicLoader::load_stage_4() -{ - call_object_init_functions(); - - m_fully_initialized = true; -} - -void DynamicLoader::load_program_headers() -{ - FlatPtr ph_load_start = SIZE_MAX; - FlatPtr ph_load_end = 0; - - // We walk the program header list once to find the requested address ranges of the program. - // We don't fill in the list of regions yet to keep malloc memory blocks from interfering with our reservation. - image().for_each_program_header([&](Image::ProgramHeader const& program_header) { - if (program_header.type() != PT_LOAD) - return; - - FlatPtr section_start = program_header.vaddr().get(); - FlatPtr section_end = section_start + program_header.size_in_memory(); - - if (ph_load_start > section_start) - ph_load_start = section_start; - - if (ph_load_end < section_end) - ph_load_end = section_end; - }); - - void* requested_load_address = image().is_dynamic() ? nullptr : reinterpret_cast(ph_load_start); - - int reservation_mmap_flags = MAP_ANON | MAP_PRIVATE | MAP_NORESERVE; - if (image().is_dynamic()) - reservation_mmap_flags |= MAP_RANDOMIZED; -#ifdef MAP_FIXED_NOREPLACE - else - reservation_mmap_flags |= MAP_FIXED_NOREPLACE; -#endif - - // First, we make a dummy reservation mapping, in order to allocate enough VM - // to hold all regions contiguously in the address space. - - FlatPtr ph_load_base = ph_load_start & ~(FlatPtr)0xfffu; - ph_load_end = round_up_to_power_of_two(ph_load_end, PAGE_SIZE); - - size_t total_mapping_size = ph_load_end - ph_load_base; - - // Before we make our reservation, unmap our existing mapped ELF image that we used for reading header information. - // This leaves our pointers dangling momentarily, but it reduces the chance that we will conflict with ourselves. - if (munmap(m_file_data, m_file_size) < 0) { - perror("munmap old mapping"); - VERIFY_NOT_REACHED(); - } - m_elf_image = nullptr; - m_file_data = nullptr; - - auto* reservation = mmap(requested_load_address, total_mapping_size, PROT_NONE, reservation_mmap_flags, 0, 0); - if (reservation == MAP_FAILED) { - perror("mmap reservation"); - VERIFY_NOT_REACHED(); - } - - // Now that we can't accidentally block our requested space, re-map our ELF image. - ByteString file_mmap_name = ByteString::formatted("ELF_DYN: {}", m_filepath); - auto* data = mmap_with_name(nullptr, m_file_size, PROT_READ, MAP_SHARED, m_image_fd, 0, file_mmap_name.characters()); - if (data == MAP_FAILED) { - perror("mmap new mapping"); - VERIFY_NOT_REACHED(); - } - - m_file_data = data; - m_elf_image = adopt_own(*new ELF::Image((u8*)m_file_data, m_file_size)); - - VERIFY(requested_load_address == nullptr || reservation == requested_load_address); - - m_base_address = VirtualAddress { reservation }; - - // Most binaries have four loadable regions, three of which are mapped - // (symbol tables/relocation information, executable instructions, read-only data) - // and one of which is copied (modifiable data). - // These are allocated in-line to cut down on the malloc calls. - Vector map_regions; - Vector copy_regions; - Optional relro_region; - - VirtualAddress dynamic_region_desired_vaddr; - - image().for_each_program_header([&](Image::ProgramHeader const& program_header) { - ProgramHeaderRegion region {}; - region.set_program_header(program_header.raw_header()); - if (region.is_tls_template()) { - // Skip, this is handled in DynamicLoader::copy_initial_tls_data_into. - } else if (region.is_load()) { - if (region.size_in_memory() == 0) - return; - if (region.is_writable()) { - copy_regions.append(region); - } else { - map_regions.append(region); - } - } else if (region.is_dynamic()) { - dynamic_region_desired_vaddr = region.desired_load_address(); - } else if (region.is_relro()) { - VERIFY(!relro_region.has_value()); - relro_region = region; - } - }); - - VERIFY(!map_regions.is_empty() || !copy_regions.is_empty()); - - auto compare_load_address = [](ProgramHeaderRegion& a, ProgramHeaderRegion& b) { - return a.desired_load_address().as_ptr() < b.desired_load_address().as_ptr(); - }; - - quick_sort(map_regions, compare_load_address); - quick_sort(copy_regions, compare_load_address); - - // Pre-allocate any malloc memory needed before unmapping the reservation. - // We don't want any future malloc to accidentally mmap a reserved address! - ByteString text_segment_name = ByteString::formatted("{}: .text", m_filepath); - ByteString rodata_segment_name = ByteString::formatted("{}: .rodata", m_filepath); - ByteString data_segment_name = ByteString::formatted("{}: .data", m_filepath); - - m_text_segments.ensure_capacity(map_regions.size()); - - // Finally, we unmap the reservation. - if (munmap(reservation, total_mapping_size) < 0) { - perror("munmap reservation"); - VERIFY_NOT_REACHED(); - } - - // WARNING: Allocating after this point has the possibility of malloc stealing our reserved - // virtual memory addresses. Be careful not to malloc below! - - // Process regions in order: .text, .data, .tls - for (auto& region : map_regions) { - FlatPtr ph_desired_base = region.desired_load_address().get(); - FlatPtr ph_base = region.desired_load_address().page_base().get(); - FlatPtr ph_end = ph_base + round_up_to_power_of_two(region.size_in_memory() + region.desired_load_address().get() - ph_base, PAGE_SIZE); - - char const* const segment_name = region.is_executable() ? text_segment_name.characters() : rodata_segment_name.characters(); - - // Now we can map the text segment at the reserved address. - auto* segment_base = (u8*)mmap_with_name( - (u8*)reservation + ph_base - ph_load_base, - ph_desired_base - ph_base + region.size_in_image(), - PROT_READ, - MAP_SHARED | MAP_FIXED, - m_image_fd, - VirtualAddress { region.offset() }.page_base().get(), - segment_name); - - if (segment_base == MAP_FAILED) { - perror("mmap non-writable"); - VERIFY_NOT_REACHED(); - } - - // NOTE: Capacity ensured above the line of no malloc above - if (region.is_executable()) - m_text_segments.unchecked_append({ VirtualAddress { segment_base }, ph_end - ph_base }); - } - - VERIFY(requested_load_address == nullptr || requested_load_address == reservation); - - if (relro_region.has_value()) { - m_relro_segment_size = relro_region->size_in_memory(); - m_relro_segment_address = VirtualAddress { (u8*)reservation + relro_region->desired_load_address().get() - ph_load_base }; - } - - if (image().is_dynamic()) - m_dynamic_section_address = VirtualAddress { (u8*)reservation + dynamic_region_desired_vaddr.get() - ph_load_base }; - else - m_dynamic_section_address = dynamic_region_desired_vaddr; - - for (auto& region : copy_regions) { - FlatPtr ph_data_base = region.desired_load_address().page_base().get(); - FlatPtr ph_data_end = ph_data_base + round_up_to_power_of_two(region.size_in_memory() + region.desired_load_address().get() - ph_data_base, PAGE_SIZE); - - auto* data_segment_address = (u8*)reservation + ph_data_base - ph_load_base; - size_t data_segment_size = ph_data_end - ph_data_base; - - // Finally, we make an anonymous mapping for the data segment. Contents are then copied from the file. - auto* data_segment = (u8*)mmap_with_name( - data_segment_address, - data_segment_size, - PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, - 0, - 0, - data_segment_name.characters()); - - if (MAP_FAILED == data_segment) { - perror("mmap writable"); - VERIFY_NOT_REACHED(); - } - - VirtualAddress data_segment_start; - if (image().is_dynamic()) - data_segment_start = VirtualAddress { (u8*)reservation + region.desired_load_address().get() }; - else - data_segment_start = region.desired_load_address(); - - VERIFY(data_segment_start.as_ptr() + region.size_in_memory() <= data_segment + data_segment_size); - - memcpy(data_segment_start.as_ptr(), (u8*)m_file_data + region.offset(), region.size_in_image()); - } -} - -DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObject::Relocation const& relocation, - Optional& cached_result, - ShouldCallIfuncResolver should_call_ifunc_resolver) -{ - FlatPtr* patch_ptr = nullptr; - if (is_dynamic()) - patch_ptr = (FlatPtr*)(m_dynamic_object->base_address().as_ptr() + relocation.offset()); - else - patch_ptr = (FlatPtr*)(FlatPtr)relocation.offset(); - - auto call_ifunc_resolver = [](VirtualAddress address) { - return VirtualAddress { reinterpret_cast(address.get())() }; - }; - - auto lookup_symbol = [&](DynamicObject::Symbol const& symbol) { - // The static linker sorts relocations by the referenced symbol. Especially when vtables - // in large inheritance hierarchies are involved, there might be tens of references to - // the same symbol. We can avoid redundant lookups by keeping track of the previous result. - if (!cached_result.has_value() || !cached_result.value().symbol.definitely_equals(symbol)) - cached_result = DynamicLoader::CachedLookupResult { symbol, DynamicLoader::lookup_symbol(symbol) }; - return cached_result.value().result; - }; - - struct ResolvedTLSSymbol { - DynamicObject const& dynamic_object; - FlatPtr value; - }; - - auto resolve_tls_symbol = [&](DynamicObject::Relocation const& relocation) -> Optional { - if (relocation.symbol_index() == 0) - return ResolvedTLSSymbol { relocation.dynamic_object(), 0 }; - - auto res = lookup_symbol(relocation.symbol()); - if (!res.has_value()) - return {}; - VERIFY(relocation.symbol().type() != STT_GNU_IFUNC); - VERIFY(res.value().dynamic_object != nullptr); - return ResolvedTLSSymbol { *res.value().dynamic_object, res.value().value }; - }; - - using enum GenericDynamicRelocationType; - switch (static_cast(relocation.type())) { - - case NONE: - // Apparently most loaders will just skip these? - // Seems if the 'link editor' generates one something is funky with your code - break; - case ABSOLUTE: { - auto symbol = relocation.symbol(); - auto res = lookup_symbol(symbol); - VirtualAddress symbol_address; - if (!res.has_value()) { - if (symbol.bind() != STB_WEAK) { - dbgln("ERROR: symbol not found: {}.", symbol.name()); - return RelocationResult::Failed; - } - symbol_address = VirtualAddress { (FlatPtr)0 }; - } else { - if (res.value().type == STT_GNU_IFUNC && should_call_ifunc_resolver == ShouldCallIfuncResolver::No) - return RelocationResult::CallIfuncResolver; - symbol_address = res.value().address; - } - if (relocation.addend_used()) - *patch_ptr = symbol_address.get() + relocation.addend(); - else - *patch_ptr += symbol_address.get(); - if (res.has_value() && res.value().type == STT_GNU_IFUNC) - *patch_ptr = call_ifunc_resolver(VirtualAddress { *patch_ptr }).get(); - break; - } -#if !ARCH(RISCV64) - case GLOB_DAT: { - auto symbol = relocation.symbol(); - auto res = lookup_symbol(symbol); - VirtualAddress symbol_location; - if (!res.has_value()) { - if (symbol.bind() != STB_WEAK) { - // Symbol not found - return RelocationResult::Failed; - } - - symbol_location = VirtualAddress { (FlatPtr)0 }; - } else { - symbol_location = res.value().address; - if (res.value().type == STT_GNU_IFUNC) { - if (should_call_ifunc_resolver == ShouldCallIfuncResolver::No) - return RelocationResult::CallIfuncResolver; - if (res.value().dynamic_object != nullptr && res.value().dynamic_object->has_text_relocations()) { - dbgln("\033[31mError:\033[0m Refusing to call IFUNC resolver defined in an object with text relocations."); - return RelocationResult::Failed; - } - symbol_location = call_ifunc_resolver(symbol_location); - } - } - VERIFY(symbol_location != m_dynamic_object->base_address()); - *patch_ptr = symbol_location.get(); - break; - } -#endif - case RELATIVE: { - if (!image().is_dynamic()) - break; - // FIXME: According to the spec, R_386_relative ones must be done first. - // We could explicitly do them first using m_number_of_relocations from DT_RELCOUNT - // However, our compiler is nice enough to put them at the front of the relocations for us :) - if (relocation.addend_used()) - *patch_ptr = m_dynamic_object->base_address().offset(relocation.addend()).get(); - else - *patch_ptr += m_dynamic_object->base_address().get(); - break; - } - case TLS_TPREL: { - auto maybe_resolution = resolve_tls_symbol(relocation); - if (!maybe_resolution.has_value()) - break; - auto [dynamic_object_of_symbol, symbol_value] = maybe_resolution.value(); - - size_t addend = relocation.addend_used() ? relocation.addend() : *patch_ptr; - *patch_ptr = addend + dynamic_object_of_symbol.tls_offset().value() + symbol_value + TLS_TP_STATIC_TLS_BLOCK_OFFSET; - - if constexpr (TLS_VARIANT == 1) { - // Until offset TLS_TP_STATIC_TLS_BLOCK_OFFSET there's the thread's ThreadControlBlock, we don't want to collide with it. - VERIFY(static_cast(*patch_ptr) >= static_cast(TLS_TP_STATIC_TLS_BLOCK_OFFSET)); - } else if constexpr (TLS_VARIANT == 2) { - // At offset 0 there's the thread's ThreadControlBlock, we don't want to collide with it. - VERIFY(static_cast(*patch_ptr) < 0); - } - - break; - } - case TLS_DTPMOD: { - auto maybe_resolution = resolve_tls_symbol(relocation); - if (!maybe_resolution.has_value()) - break; - - // We repurpose the module index to store the TLS block's TP offset. This is fine - // because we currently only support a single static TLS block. - *patch_ptr = maybe_resolution->dynamic_object.tls_offset().value(); - break; - } - case TLS_DTPREL: { - auto maybe_resolution = resolve_tls_symbol(relocation); - if (!maybe_resolution.has_value()) - break; - - size_t addend = relocation.addend_used() ? relocation.addend() : *patch_ptr; - *patch_ptr = addend + maybe_resolution->value - TLS_DTV_OFFSET + TLS_TP_STATIC_TLS_BLOCK_OFFSET; - break; - } -#ifdef HAS_TLSDESC_SUPPORT - case TLSDESC: { - auto maybe_resolution = resolve_tls_symbol(relocation); - if (!maybe_resolution.has_value()) - break; - auto [dynamic_object_of_symbol, symbol_value] = maybe_resolution.value(); - - size_t addend = relocation.addend_used() ? relocation.addend() : *patch_ptr; - - patch_ptr[0] = (FlatPtr)__tlsdesc_static; - patch_ptr[1] = addend + dynamic_object_of_symbol.tls_offset().value() + symbol_value; - break; - } -#endif - case IRELATIVE: { - if (should_call_ifunc_resolver == ShouldCallIfuncResolver::No) - return RelocationResult::CallIfuncResolver; - VirtualAddress resolver; - if (relocation.addend_used()) - resolver = m_dynamic_object->base_address().offset(relocation.addend()); - else - resolver = m_dynamic_object->base_address().offset(*patch_ptr); - - if (m_dynamic_object->has_text_relocations()) { - dbgln("\033[31mError:\033[0m Refusing to call IFUNC resolver defined in an object with text relocations."); - return RelocationResult::Failed; - } - - *patch_ptr = call_ifunc_resolver(resolver).get(); - break; - } - case JUMP_SLOT: - VERIFY_NOT_REACHED(); // PLT relocations are handled by do_plt_relocation. - default: - // Raise the alarm! Someone needs to implement this relocation type - dbgln("Found a new exciting relocation type {}", relocation.type()); - VERIFY_NOT_REACHED(); - } - return RelocationResult::Success; -} - -DynamicLoader::RelocationResult DynamicLoader::do_plt_relocation(DynamicObject::Relocation const& relocation, ShouldCallIfuncResolver should_call_ifunc_resolver) -{ - VERIFY(static_cast(relocation.type()) == GenericDynamicRelocationType::JUMP_SLOT); - auto symbol = relocation.symbol(); - auto* relocation_address = (FlatPtr*)relocation.address().as_ptr(); - - VirtualAddress symbol_location {}; - if (auto result = lookup_symbol(symbol); result.has_value()) { - auto address = result.value().address; - - if (result.value().type == STT_GNU_IFUNC) { - if (should_call_ifunc_resolver == ShouldCallIfuncResolver::No) - return RelocationResult::CallIfuncResolver; - symbol_location = VirtualAddress { reinterpret_cast(address.get())() }; - } else { - symbol_location = address; - } - } else if (symbol.bind() != STB_WEAK) { - return RelocationResult::Failed; - } - - dbgln_if(DYNAMIC_LOAD_DEBUG, "DynamicLoader: Jump slot relocation: putting {} ({}) into PLT at {}", symbol.name(), symbol_location, (void*)relocation_address); - *relocation_address = symbol_location.get(); - - return RelocationResult::Success; -} - -void DynamicLoader::do_relr_relocations() -{ - auto base_address = m_dynamic_object->base_address().get(); - m_dynamic_object->for_each_relr_relocation([base_address](FlatPtr address) { - *(FlatPtr*)address += base_address; - }); -} - -void DynamicLoader::copy_initial_tls_data_into(Bytes buffer) const -{ - image().for_each_program_header([this, &buffer](ELF::Image::ProgramHeader program_header) { - if (program_header.type() != PT_TLS) - return IterationDecision::Continue; - - // Note: The "size in image" is only concerned with initialized data. Uninitialized data (.tbss) is - // only included in the "size in memory" metric, and is expected to not be touched or read from, as - // it is not present in the image and zeroed out in-memory. We will still check that the buffer has - // space for both the initialized and the uninitialized data. - // TODO: Is the initialized data always in the beginning of the TLS segment, or should we walk the - // sections to figure that out? - - VERIFY(program_header.size_in_image() <= program_header.size_in_memory()); - VERIFY(program_header.size_in_memory() <= m_tls_size_of_current_object); - - if constexpr (TLS_VARIANT == 1) { - size_t tls_start_in_buffer = m_tls_offset; - VERIFY(tls_start_in_buffer + program_header.size_in_memory() <= buffer.size()); - memcpy(buffer.data() + tls_start_in_buffer, static_cast(m_file_data) + program_header.offset(), program_header.size_in_image()); - } else if constexpr (TLS_VARIANT == 2) { - size_t tls_start_in_buffer = buffer.size() + m_tls_offset; - VERIFY(tls_start_in_buffer + program_header.size_in_memory() <= buffer.size()); - memcpy(buffer.data() + tls_start_in_buffer, static_cast(m_file_data) + program_header.offset(), program_header.size_in_image()); - } - - return IterationDecision::Break; - }); -} - -// Defined in /plt_trampoline.S -extern "C" void _plt_trampoline(void) __attribute__((visibility("hidden"))); - -void DynamicLoader::setup_plt_trampoline() -{ - VERIFY(m_dynamic_object); - VERIFY(m_dynamic_object->has_plt()); - VirtualAddress got_address = m_dynamic_object->plt_got_base_address(); - - auto* got_ptr = (FlatPtr*)got_address.as_ptr(); - -#if ARCH(AARCH64) || ARCH(X86_64) - got_ptr[1] = (FlatPtr)m_dynamic_object.ptr(); - got_ptr[2] = (FlatPtr)&_plt_trampoline; -#elif ARCH(RISCV64) - got_ptr[0] = (FlatPtr)&_plt_trampoline; - got_ptr[1] = (FlatPtr)m_dynamic_object.ptr(); -#else -# error Unknown architecture -#endif -} - -// Called from our ASM routine _plt_trampoline. -extern "C" FlatPtr _fixup_plt_entry(DynamicObject* object, u32 relocation_offset) -{ - auto const& relocation = object->plt_relocation_section().relocation_at_offset(relocation_offset); - auto result = DynamicLoader::do_plt_relocation(relocation, ShouldCallIfuncResolver::Yes); - if (result != DynamicLoader::RelocationResult::Success) { - dbgln("Loader.so: {} unresolved symbol '{}'", object->filepath(), relocation.symbol().name()); - VERIFY_NOT_REACHED(); - } - return *reinterpret_cast(relocation.address().as_ptr()); -} - -void DynamicLoader::call_object_init_functions() -{ - typedef void (*InitFunc)(); - - if (m_dynamic_object->has_init_section()) { - auto init_function = m_dynamic_object->init_section_function(); - (init_function)(); - } - - if (m_dynamic_object->has_init_array_section()) { - auto init_array_section = m_dynamic_object->init_array_section(); - - InitFunc* init_begin = (InitFunc*)(init_array_section.address().as_ptr()); - InitFunc* init_end = init_begin + init_array_section.entry_count(); - while (init_begin != init_end) { - // Android sources claim that these can be -1, to be ignored. - // 0 definitely shows up. Apparently 0/-1 are valid? Confusing. - if (!*init_begin || ((FlatPtr)*init_begin == (FlatPtr)-1)) - continue; - (*init_begin)(); - ++init_begin; - } - } -} - -Optional DynamicLoader::lookup_symbol(const ELF::DynamicObject::Symbol& symbol) -{ - if (symbol.is_undefined() || symbol.bind() == STB_WEAK) - return DynamicLinker::lookup_global_symbol(symbol.name()); - - return DynamicObject::SymbolLookupResult { symbol.value(), symbol.size(), symbol.address(), symbol.bind(), symbol.type(), &symbol.object() }; -} - -void DynamicLoader::compute_topological_order(Vector>& topological_order) -{ - VERIFY(m_topological_ordering_state == TopologicalOrderingState::NotVisited); - m_topological_ordering_state = TopologicalOrderingState::Visiting; - - Vector> actual_dependencies; - for (auto const& dependency : m_true_dependencies) { - auto state = dependency->m_topological_ordering_state; - if (state == TopologicalOrderingState::NotVisited) - dependency->compute_topological_order(topological_order); - if (state == TopologicalOrderingState::Visited) - actual_dependencies.append(dependency); - } - m_true_dependencies = actual_dependencies; - - m_topological_ordering_state = TopologicalOrderingState::Visited; - topological_order.append(*this); -} - -} diff --git a/Userland/Libraries/LibELF/DynamicLoader.h b/Userland/Libraries/LibELF/DynamicLoader.h deleted file mode 100644 index 27dbb92236d..00000000000 --- a/Userland/Libraries/LibELF/DynamicLoader.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2019-2020, Andrew Kaster - * Copyright (c) 2020, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ELF { - -class LoadedSegment { -public: - LoadedSegment(VirtualAddress address, size_t size) - : m_address(address) - , m_size(size) - { - } - - VirtualAddress address() const { return m_address; } - size_t size() const { return m_size; } - -private: - VirtualAddress m_address; - size_t m_size; -}; - -enum class ShouldCallIfuncResolver { - Yes, - No -}; - -extern "C" FlatPtr _fixup_plt_entry(DynamicObject* object, u32 relocation_offset); - -class DynamicLoader : public RefCounted { -public: - static Result, DlErrorMessage> try_create(int fd, ByteString filepath); - ~DynamicLoader(); - - ByteString const& filepath() const { return m_filepath; } - - bool is_valid() const { return m_valid; } - - // Load a full ELF image from file into the current process and create an DynamicObject - // from the SHT_DYNAMIC in the file. - // Note that the DynamicObject will not be linked yet. Callers are responsible for calling link() to finish it. - RefPtr map(); - - bool link(unsigned flags); - - // Stage 2 of loading: dynamic object loading and primary relocations - bool load_stage_2(unsigned flags); - - // Stage 3 of loading: lazy relocations - Result, DlErrorMessage> load_stage_3(unsigned flags); - - // Stage 4 of loading: initializers - void load_stage_4(); - - void set_tls_offset(size_t offset) { m_tls_offset = offset; } - size_t tls_size_of_current_object() const { return m_tls_size_of_current_object; } - size_t tls_alignment_of_current_object() const { return m_tls_alignment_of_current_object; } - size_t tls_offset() const { return m_tls_offset; } - const ELF::Image& image() const { return *m_elf_image; } - - template - void for_each_needed_library(F) const; - - VirtualAddress base_address() const { return m_base_address; } - Vector const text_segments() const { return m_text_segments; } - bool is_dynamic() const { return image().is_dynamic(); } - - static Optional lookup_symbol(const ELF::DynamicObject::Symbol&); - void copy_initial_tls_data_into(Bytes buffer) const; - - DynamicObject& dynamic_object() { return *m_dynamic_object; } - DynamicObject const& dynamic_object() const { return *m_dynamic_object; } - - bool is_fully_relocated() const { return m_fully_relocated; } - bool is_fully_initialized() const { return m_fully_initialized; } - - void add_dependency(NonnullRefPtr dependency) - { - // Dependencies that aren't actually true will be removed in compute_topological_order. - m_true_dependencies.append(move(dependency)); - } - - void compute_topological_order(Vector>& topological_order); - -private: - DynamicLoader(int fd, ByteString filepath, void* file_data, size_t file_size); - - class ProgramHeaderRegion { - public: - void set_program_header(Elf_Phdr const& header) { m_program_header = header; } - - // Information from ELF Program header - u32 type() const { return m_program_header.p_type; } - u32 flags() const { return m_program_header.p_flags; } - u32 offset() const { return m_program_header.p_offset; } - VirtualAddress desired_load_address() const { return VirtualAddress(m_program_header.p_vaddr); } - u32 size_in_memory() const { return m_program_header.p_memsz; } - u32 size_in_image() const { return m_program_header.p_filesz; } - u32 alignment() const { return m_program_header.p_align; } - bool is_readable() const { return flags() & PF_R; } - bool is_writable() const { return flags() & PF_W; } - bool is_executable() const { return flags() & PF_X; } - bool is_tls_template() const { return type() == PT_TLS; } - bool is_load() const { return type() == PT_LOAD; } - bool is_dynamic() const { return type() == PT_DYNAMIC; } - bool is_relro() const { return type() == PT_GNU_RELRO; } - - private: - Elf_Phdr m_program_header; // Explicitly a copy of the PHDR in the image - }; - - // Stage 1 - void load_program_headers(); - - // Stage 2 - void do_main_relocations(); - - // Stage 3 - void setup_plt_trampoline(); - - // Stage 4 - void call_object_init_functions(); - - bool validate(); - - friend FlatPtr _fixup_plt_entry(DynamicObject*, u32); - - enum class RelocationResult : uint8_t { - Failed, - Success, - CallIfuncResolver, - }; - struct CachedLookupResult { - DynamicObject::Symbol symbol; - Optional result; - }; - RelocationResult do_direct_relocation(DynamicObject::Relocation const&, Optional&, ShouldCallIfuncResolver); - // Will be called from _fixup_plt_entry, as part of the PLT trampoline - static RelocationResult do_plt_relocation(DynamicObject::Relocation const&, ShouldCallIfuncResolver); - void do_relr_relocations(); - void find_tls_size_and_alignment(); - - ByteString m_filepath; - size_t m_file_size { 0 }; - int m_image_fd { -1 }; - void* m_file_data { nullptr }; - OwnPtr m_elf_image; - bool m_valid { true }; - - RefPtr m_dynamic_object; - - VirtualAddress m_base_address; - Vector m_text_segments; - - VirtualAddress m_relro_segment_address; - size_t m_relro_segment_size { 0 }; - - VirtualAddress m_dynamic_section_address; - - ssize_t m_tls_offset { 0 }; - size_t m_tls_size_of_current_object { 0 }; - size_t m_tls_alignment_of_current_object { 0 }; - - Vector m_direct_ifunc_relocations; - Vector m_plt_ifunc_relocations; - - bool m_fully_relocated { false }; - bool m_fully_initialized { false }; - - enum class TopologicalOrderingState { - NotVisited, - Visiting, - Visited, - } m_topological_ordering_state { TopologicalOrderingState::NotVisited }; - - Vector> m_true_dependencies; -}; - -template -void DynamicLoader::for_each_needed_library(F func) const -{ - dynamic_object().for_each_needed_library(move(func)); -} - -} // end namespace ELF diff --git a/Userland/Libraries/LibELF/DynamicObject.cpp b/Userland/Libraries/LibELF/DynamicObject.cpp deleted file mode 100644 index 849507fe6d7..00000000000 --- a/Userland/Libraries/LibELF/DynamicObject.cpp +++ /dev/null @@ -1,574 +0,0 @@ -/* - * Copyright (c) 2019-2020, Andrew Kaster - * Copyright (c) 2020, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ELF { - -DynamicObject::DynamicObject(ByteString const& filepath, VirtualAddress base_address, VirtualAddress dynamic_section_address) - : m_filepath(filepath) - , m_base_address(base_address) - , m_dynamic_address(dynamic_section_address) -{ - auto* header = (Elf_Ehdr*)base_address.as_ptr(); - auto* const phdrs = program_headers(); - - // Calculate the base address using the PT_LOAD element with the lowest `p_vaddr` (which is the first element) - for (size_t i = 0; i < program_header_count(); ++i) { - auto pheader = phdrs[i]; - if (pheader.p_type == PT_LOAD) { - m_elf_base_address = VirtualAddress { pheader.p_vaddr - pheader.p_offset }; - break; - } - - if (i == program_header_count() - 1) { - VERIFY_NOT_REACHED(); - } - } - - if (header->e_type == ET_DYN) - m_is_elf_dynamic = true; - else - m_is_elf_dynamic = false; - - parse(); -} - -DynamicObject::~DynamicObject() -{ - // TODO: unmap the object -} - -void DynamicObject::dump() const -{ - if constexpr (DYNAMIC_LOAD_DEBUG) { - StringBuilder builder; - builder.append("\nd_tag tag_name value\n"sv); - size_t num_dynamic_sections = 0; - - for_each_dynamic_entry([&](DynamicObject::DynamicEntry const& entry) { - ByteString name_field = ByteString::formatted("({})", name_for_dtag(entry.tag())); - builder.appendff("{:#08x} {:17} {:#08x}\n", entry.tag(), name_field, entry.val()); - num_dynamic_sections++; - }); - - if (m_has_soname) - builder.appendff("DT_SONAME: {}\n", soname()); // FIXME: Validate that this string is null terminated? - if (m_has_rpath) - builder.appendff("DT_RPATH: {}\n", rpath()); - if (m_has_runpath) - builder.appendff("DT_RUNPATH: {}\n", runpath()); - - dbgln("Dynamic section at address {} contains {} entries:", m_dynamic_address.as_ptr(), num_dynamic_sections); - dbgln("{}", builder.string_view()); - } -} - -void DynamicObject::parse() -{ - for_each_dynamic_entry([&](DynamicEntry const& entry) { - switch (entry.tag()) { - case DT_INIT: - m_init_offset = entry.ptr() - m_elf_base_address.get(); - break; - case DT_FINI: - m_fini_offset = entry.ptr() - m_elf_base_address.get(); - break; - case DT_INIT_ARRAY: - m_init_array_offset = entry.ptr() - m_elf_base_address.get(); - break; - case DT_INIT_ARRAYSZ: - m_init_array_size = entry.val(); - break; - case DT_FINI_ARRAY: - m_fini_array_offset = entry.ptr() - m_elf_base_address.get(); - break; - case DT_FINI_ARRAYSZ: - m_fini_array_size = entry.val(); - break; - case DT_HASH: - // Use SYSV hash only if GNU hash is not available - if (m_hash_type == HashType::SYSV) { - m_hash_table_offset = entry.ptr() - m_elf_base_address.get(); - } - break; - case DT_GNU_HASH: - m_hash_type = HashType::GNU; - m_hash_table_offset = entry.ptr() - m_elf_base_address.get(); - break; - case DT_SYMTAB: - m_symbol_table_offset = entry.ptr() - m_elf_base_address.get(); - break; - case DT_STRTAB: - m_string_table_offset = entry.ptr() - m_elf_base_address.get(); - break; - case DT_STRSZ: - m_size_of_string_table = entry.val(); - break; - case DT_SYMENT: - m_size_of_symbol_table_entry = entry.val(); - break; - case DT_PLTGOT: - m_procedure_linkage_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_PLTRELSZ: - m_size_of_plt_relocation_entry_list = entry.val(); - break; - case DT_PLTREL: - m_procedure_linkage_table_relocation_type = entry.val(); - VERIFY(m_procedure_linkage_table_relocation_type & (DT_REL | DT_RELA)); - break; - case DT_JMPREL: - m_plt_relocation_offset_location = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_RELA: - m_addend_used = true; - [[fallthrough]]; - case DT_REL: - m_relocation_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_RELASZ: - case DT_RELSZ: - m_size_of_relocation_table = entry.val(); - break; - case DT_RELAENT: - case DT_RELENT: - m_size_of_relocation_entry = entry.val(); - break; - case DT_RELACOUNT: - case DT_RELCOUNT: - m_number_of_relocations = entry.val(); - break; - case DT_RELR: - m_relr_relocation_table_offset = entry.ptr() - m_elf_base_address.get(); - break; - case DT_RELRSZ: - m_size_of_relr_relocation_table = entry.val(); - break; - case DT_RELRENT: - m_size_of_relr_relocations_entry = entry.val(); - break; - case DT_FLAGS: - m_dt_flags = entry.val(); - break; - case DT_TEXTREL: - m_dt_flags |= DF_TEXTREL; // This tag seems to exist for legacy reasons only? - break; - case DT_SONAME: - m_soname_index = entry.val(); - m_has_soname = true; - break; - case DT_BIND_NOW: - m_dt_flags |= DF_BIND_NOW; - break; - case DT_RPATH: - m_rpath_index = entry.val(); - m_has_rpath = true; - break; - case DT_RUNPATH: - m_runpath_index = entry.val(); - m_has_runpath = true; - break; - case DT_DEBUG: - break; - case DT_FLAGS_1: - m_is_pie = true; - break; - case DT_NEEDED: - // We handle these in for_each_needed_library - break; - case DT_SYMBOLIC: - break; - default: - dbgln("DynamicObject: DYNAMIC tag handling not implemented for DT_{} ({}) in {}", name_for_dtag(entry.tag()), entry.tag(), m_filepath); - break; - } - }); - - if (!m_size_of_relocation_entry) { - // TODO: FIXME, this shouldn't be hardcoded - // The reason we need this here is that for some reason, when there only PLT relocations, the compiler - // doesn't insert a 'PLTRELSZ' entry to the dynamic section - m_size_of_relocation_entry = sizeof(Elf_Rel); - } - - // Whether or not RELASZ (stored in m_size_of_relocation_table) only refers to non-PLT entries is not clearly specified. - // So check if [JMPREL, JMPREL+PLTRELSZ) is in [RELA, RELA+RELASZ). - // If so, change the size of the non-PLT relocation table. - if (m_plt_relocation_offset_location >= m_relocation_table_offset // JMPREL >= RELA - && m_plt_relocation_offset_location < (m_relocation_table_offset + m_size_of_relocation_table)) { // JMPREL < (RELA + RELASZ) - // [JMPREL, JMPREL+PLTRELSZ) is in [RELA, RELA+RELASZ) - - // Verify that the ends of the tables match up - VERIFY(m_plt_relocation_offset_location + m_size_of_plt_relocation_entry_list == m_relocation_table_offset + m_size_of_relocation_table); - - m_size_of_relocation_table -= m_size_of_plt_relocation_entry_list; - } - - u32 const* hash_table_begin = reinterpret_cast(hash_section().address().as_ptr()); - - if (m_hash_type == HashType::SYSV) { - u32 n_chain = hash_table_begin[1]; - m_symbol_count = n_chain; - return; - } - - // Determine amount of symbols by finding the chain with the highest - // starting index and walking this chain until the end to find the - // maximum index = amount of symbols. - using BloomWord = FlatPtr; - size_t const num_buckets = hash_table_begin[0]; - size_t const num_omitted_symbols = hash_table_begin[1]; - u32 const num_maskwords = hash_table_begin[2]; - BloomWord const* bloom_words = reinterpret_cast(&hash_table_begin[4]); - u32 const* const buckets = reinterpret_cast(&bloom_words[num_maskwords]); - u32 const* const chains = &buckets[num_buckets]; - - size_t highest_chain_idx = 0; - for (size_t i = 0; i < num_buckets; i++) { - if (buckets[i] > highest_chain_idx) { - highest_chain_idx = buckets[i]; - } - } - - if (highest_chain_idx < num_omitted_symbols) { - m_symbol_count = 0; - return; - } - - size_t amount_symbols = highest_chain_idx; - u32 const* last_chain = &chains[highest_chain_idx - num_omitted_symbols]; - while ((*(last_chain++) & 1) == 0) { - amount_symbols++; - } - - m_symbol_count = amount_symbols + 1; -} - -DynamicObject::Relocation DynamicObject::RelocationSection::relocation(unsigned index) const -{ - VERIFY(index < entry_count()); - unsigned offset_in_section = index * entry_size(); - auto relocation_address = (Elf_Rela*)address().offset(offset_in_section).as_ptr(); - return Relocation(m_dynamic, *relocation_address, offset_in_section, m_addend_used); -} - -DynamicObject::Relocation DynamicObject::RelocationSection::relocation_at_offset(unsigned offset) const -{ - VERIFY(offset <= (m_section_size_bytes - m_entry_size)); - auto relocation_address = (Elf_Rela*)address().offset(offset).as_ptr(); - return Relocation(m_dynamic, *relocation_address, offset, m_addend_used); -} - -DynamicObject::Symbol DynamicObject::symbol(unsigned index) const -{ - auto symbol_section = Section(*this, m_symbol_table_offset, (m_symbol_count * m_size_of_symbol_table_entry), m_size_of_symbol_table_entry, "DT_SYMTAB"sv); - auto symbol_entry = (Elf_Sym*)symbol_section.address().offset(index * symbol_section.entry_size()).as_ptr(); - return Symbol(*this, index, *symbol_entry); -} - -DynamicObject::Section DynamicObject::init_section() const -{ - return Section(*this, m_init_offset, sizeof(void (*)()), sizeof(void (*)()), "DT_INIT"sv); -} - -DynamicObject::Section DynamicObject::fini_section() const -{ - return Section(*this, m_fini_offset, sizeof(void (*)()), sizeof(void (*)()), "DT_FINI"sv); -} - -DynamicObject::Section DynamicObject::init_array_section() const -{ - return Section(*this, m_init_array_offset, m_init_array_size, sizeof(void (*)()), "DT_INIT_ARRAY"sv); -} - -DynamicObject::Section DynamicObject::fini_array_section() const -{ - return Section(*this, m_fini_array_offset, m_fini_array_size, sizeof(void (*)()), "DT_FINI_ARRAY"sv); -} - -DynamicObject::RelocationSection DynamicObject::relocation_section() const -{ - return RelocationSection(Section(*this, m_relocation_table_offset, m_size_of_relocation_table, m_size_of_relocation_entry, "DT_REL"sv), m_addend_used); -} - -DynamicObject::RelocationSection DynamicObject::plt_relocation_section() const -{ - return RelocationSection(Section(*this, m_plt_relocation_offset_location, m_size_of_plt_relocation_entry_list, m_size_of_relocation_entry, "DT_JMPREL"sv), m_procedure_linkage_table_relocation_type & DT_RELA); -} - -DynamicObject::Section DynamicObject::relr_relocation_section() const -{ - return Section(*this, m_relr_relocation_table_offset, m_size_of_relr_relocation_table, m_size_of_relr_relocations_entry, "DT_RELR"sv); -} - -Elf_Half DynamicObject::program_header_count() const -{ - auto* header = (Elf_Ehdr const*)m_base_address.as_ptr(); - return header->e_phnum; -} - -Elf_Phdr const* DynamicObject::program_headers() const -{ - auto* header = (Elf_Ehdr const*)m_base_address.as_ptr(); - return (Elf_Phdr const*)(m_base_address.as_ptr() + header->e_phoff); -} - -auto DynamicObject::HashSection::lookup_sysv_symbol(StringView name, u32 hash_value) const -> Optional -{ - u32* hash_table_begin = (u32*)address().as_ptr(); - size_t num_buckets = hash_table_begin[0]; - - // This is here for completeness, but, since we're using the fact that every chain - // will end at chain 0 (which means 'not found'), we don't need to check num_chains. - // Interestingly, num_chains is required to be num_symbols - - // size_t num_chains = hash_table_begin[1]; - - u32* buckets = &hash_table_begin[2]; - u32* chains = &buckets[num_buckets]; - - for (u32 i = buckets[hash_value % num_buckets]; i; i = chains[i]) { - auto symbol = m_dynamic.symbol(i); - if (name == symbol.raw_name()) { - dbgln_if(DYNAMIC_LOAD_DEBUG, "Returning SYSV dynamic symbol with index {} for {}: {}", i, symbol.name(), symbol.address().as_ptr()); - return symbol; - } - } - return {}; -} - -auto DynamicObject::HashSection::lookup_gnu_symbol(StringView name, u32 hash_value) const -> Optional -{ - // Algorithm reference: https://ent-voy.blogspot.com/2011/02/ - using BloomWord = FlatPtr; - constexpr size_t bloom_word_size = sizeof(BloomWord) * 8; - - u32 const* hash_table_begin = (u32*)address().as_ptr(); - - size_t const num_buckets = hash_table_begin[0]; - size_t const num_omitted_symbols = hash_table_begin[1]; - u32 const num_maskwords = hash_table_begin[2]; - // This works because num_maskwords is required to be a power of 2 - u32 const num_maskwords_bitmask = num_maskwords - 1; - u32 const shift2 = hash_table_begin[3]; - - BloomWord const* bloom_words = (BloomWord const*)&hash_table_begin[4]; - u32 const* const buckets = (u32 const*)&bloom_words[num_maskwords]; - u32 const* const chains = &buckets[num_buckets]; - - BloomWord hash1 = hash_value; - BloomWord hash2 = hash1 >> shift2; - BloomWord const bitmask = ((BloomWord)1 << (hash1 % bloom_word_size)) | ((BloomWord)1 << (hash2 % bloom_word_size)); - - if ((bloom_words[(hash1 / bloom_word_size) & num_maskwords_bitmask] & bitmask) != bitmask) - return {}; - - size_t current_sym = buckets[hash1 % num_buckets]; - if (current_sym == 0) - return {}; - u32 const* current_chain = &chains[current_sym - num_omitted_symbols]; - - for (hash1 &= ~1;; ++current_sym) { - hash2 = *(current_chain++); - if (hash1 == (hash2 & ~1)) { - auto symbol = m_dynamic.symbol(current_sym); - if (name == symbol.raw_name()) - return symbol; - } - - if (hash2 & 1) - break; - } - - return {}; -} - -StringView DynamicObject::symbol_string_table_string(Elf_Word index) const -{ - auto const* symbol_string_table_ptr = reinterpret_cast(base_address().offset(m_string_table_offset + index).as_ptr()); - return StringView { symbol_string_table_ptr, strlen(symbol_string_table_ptr) }; -} - -char const* DynamicObject::raw_symbol_string_table_string(Elf_Word index) const -{ - return (char const*)base_address().offset(m_string_table_offset + index).as_ptr(); -} - -DynamicObject::InitializationFunction DynamicObject::init_section_function() const -{ - VERIFY(has_init_section()); - return (InitializationFunction)init_section().address().as_ptr(); -} - -DynamicObject::FinalizationFunction DynamicObject::fini_section_function() const -{ - VERIFY(has_fini_section()); - return (FinalizationFunction)fini_section().address().as_ptr(); -} - -char const* DynamicObject::name_for_dtag(Elf_Sword d_tag) -{ - switch (d_tag) { - case DT_NULL: - return "NULL"; /* marks end of _DYNAMIC array */ - case DT_NEEDED: - return "NEEDED"; /* string table offset of needed lib */ - case DT_PLTRELSZ: - return "PLTRELSZ"; /* size of relocation entries in PLT */ - case DT_PLTGOT: - return "PLTGOT"; /* address PLT/GOT */ - case DT_HASH: - return "HASH"; /* address of symbol hash table */ - case DT_STRTAB: - return "STRTAB"; /* address of string table */ - case DT_SYMTAB: - return "SYMTAB"; /* address of symbol table */ - case DT_RELA: - return "RELA"; /* address of relocation table */ - case DT_RELASZ: - return "RELASZ"; /* size of relocation table */ - case DT_RELAENT: - return "RELAENT"; /* size of relocation entry */ - case DT_STRSZ: - return "STRSZ"; /* size of string table */ - case DT_SYMENT: - return "SYMENT"; /* size of symbol table entry */ - case DT_INIT: - return "INIT"; /* address of initialization func. */ - case DT_FINI: - return "FINI"; /* address of termination function */ - case DT_SONAME: - return "SONAME"; /* string table offset of shared obj */ - case DT_RPATH: - return "RPATH"; /* string table offset of library search path */ - case DT_SYMBOLIC: - return "SYMBOLIC"; /* start sym search in shared obj. */ - case DT_REL: - return "REL"; /* address of rel. tbl. w addends */ - case DT_RELSZ: - return "RELSZ"; /* size of DT_REL relocation table */ - case DT_RELENT: - return "RELENT"; /* size of DT_REL relocation entry */ - case DT_PLTREL: - return "PLTREL"; /* PLT referenced relocation entry */ - case DT_DEBUG: - return "DEBUG"; /* bugger */ - case DT_TEXTREL: - return "TEXTREL"; /* Allow rel. mod. to unwritable seg */ - case DT_JMPREL: - return "JMPREL"; /* add. of PLT's relocation entries */ - case DT_BIND_NOW: - return "BIND_NOW"; /* Bind now regardless of env setting */ - case DT_INIT_ARRAY: - return "INIT_ARRAY"; /* address of array of init func */ - case DT_FINI_ARRAY: - return "FINI_ARRAY"; /* address of array of term func */ - case DT_INIT_ARRAYSZ: - return "INIT_ARRAYSZ"; /* size of array of init func */ - case DT_FINI_ARRAYSZ: - return "FINI_ARRAYSZ"; /* size of array of term func */ - case DT_RUNPATH: - return "RUNPATH"; /* strtab offset of lib search path */ - case DT_FLAGS: - return "FLAGS"; /* Set of DF_* flags */ - case DT_ENCODING: - return "ENCODING"; /* further DT_* follow encoding rules */ - case DT_PREINIT_ARRAY: - return "PREINIT_ARRAY"; /* address of array of preinit func */ - case DT_PREINIT_ARRAYSZ: - return "PREINIT_ARRAYSZ"; /* size of array of preinit func */ - case DT_LOOS: - return "LOOS"; /* reserved range for OS */ - case DT_HIOS: - return "HIOS"; /* specific dynamic array tags */ - case DT_LOPROC: - return "LOPROC"; /* reserved range for processor */ - case DT_HIPROC: - return "HIPROC"; /* specific dynamic array tags */ - case DT_GNU_HASH: - return "GNU_HASH"; /* address of GNU hash table */ - case DT_RELACOUNT: - return "RELACOUNT"; /* if present, number of RELATIVE */ - case DT_RELCOUNT: - return "RELCOUNT"; /* relocs, which must come first */ - case DT_FLAGS_1: - return "FLAGS_1"; - case DT_VERDEF: - return "VERDEF"; - case DT_VERDEFNUM: - return "VERDEFNUM"; - case DT_VERSYM: - return "VERSYM"; - case DT_VERNEEDED: - return "VERNEEDED"; - case DT_VERNEEDEDNUM: - return "VERNEEDEDNUM"; - case DT_RELR: - return "DT_RELR"; - case DT_RELRSZ: - return "DT_RELRSZ"; - case DT_RELRENT: - return "DT_RELRENT"; - default: - return "??"; - } -} - -auto DynamicObject::lookup_symbol(StringView name) const -> Optional -{ - return lookup_symbol(HashSymbol { name }); -} - -auto DynamicObject::lookup_symbol(HashSymbol const& symbol) const -> Optional -{ - auto result = hash_section().lookup_symbol(symbol); - if (!result.has_value()) - return {}; - auto symbol_result = result.value(); - if (symbol_result.is_undefined()) - return {}; - return SymbolLookupResult { symbol_result.value(), symbol_result.size(), symbol_result.address(), symbol_result.bind(), symbol_result.type(), this }; -} - -NonnullRefPtr DynamicObject::create(ByteString const& filepath, VirtualAddress base_address, VirtualAddress dynamic_section_address) -{ - return adopt_ref(*new DynamicObject(filepath, base_address, dynamic_section_address)); -} - -u32 DynamicObject::HashSymbol::gnu_hash() const -{ - if (!m_gnu_hash.has_value()) - m_gnu_hash = compute_gnu_hash(m_name); - return m_gnu_hash.value(); -} - -u32 DynamicObject::HashSymbol::sysv_hash() const -{ - if (!m_sysv_hash.has_value()) - m_sysv_hash = compute_sysv_hash(m_name); - return m_sysv_hash.value(); -} - -void* DynamicObject::symbol_for_name(StringView name) -{ - auto result = hash_section().lookup_symbol(name); - if (!result.has_value()) - return nullptr; - auto symbol = result.value(); - if (symbol.is_undefined()) - return nullptr; - return base_address().offset(symbol.value()).as_ptr(); -} -} // end namespace ELF diff --git a/Userland/Libraries/LibELF/DynamicObject.h b/Userland/Libraries/LibELF/DynamicObject.h deleted file mode 100644 index 4e89b919348..00000000000 --- a/Userland/Libraries/LibELF/DynamicObject.h +++ /dev/null @@ -1,504 +0,0 @@ -/* - * Copyright (c) 2019-2020, Andrew Kaster - * Copyright (c) 2020, Itamar S. - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ELF { - -class DynamicObject : public RefCounted { -public: - static NonnullRefPtr create(ByteString const& filepath, VirtualAddress base_address, VirtualAddress dynamic_section_address); - static char const* name_for_dtag(Elf_Sword d_tag); - - ~DynamicObject(); - void dump() const; - - class DynamicEntry; - class Section; - class RelocationSection; - class Symbol; - class Relocation; - class HashSection; - - class DynamicEntry { - public: - explicit DynamicEntry(Elf_Dyn const& dyn) - : m_dyn(dyn) - { - } - - ~DynamicEntry() = default; - - Elf_Sword tag() const { return m_dyn.d_tag; } - Elf_Addr ptr() const { return m_dyn.d_un.d_ptr; } - Elf_Word val() const { return m_dyn.d_un.d_val; } - - private: - Elf_Dyn const& m_dyn; - }; - - class Symbol { - public: - Symbol(DynamicObject const& dynamic, unsigned index, Elf_Sym const& sym) - : m_dynamic(dynamic) - , m_sym(sym) - , m_index(index) - { - } - - StringView name() const { return m_dynamic.symbol_string_table_string(m_sym.st_name); } - char const* raw_name() const { return m_dynamic.raw_symbol_string_table_string(m_sym.st_name); } - unsigned section_index() const { return m_sym.st_shndx; } - FlatPtr value() const { return m_sym.st_value; } - size_t size() const { return m_sym.st_size; } - unsigned index() const { return m_index; } - unsigned type() const - { - return ELF64_ST_TYPE(m_sym.st_info); - } - unsigned bind() const { return ELF64_ST_BIND(m_sym.st_info); } - - bool is_undefined() const - { - return section_index() == 0; - } - - VirtualAddress address() const - { - if (m_dynamic.elf_is_dynamic()) - return m_dynamic.base_address().offset(value()); - return VirtualAddress { value() }; - } - DynamicObject const& object() const { return m_dynamic; } - - // This might return false even if the two Symbol objects resolve to the same thing. - bool definitely_equals(Symbol const& other) const - { - return &m_dynamic == &other.m_dynamic && &m_sym == &other.m_sym && m_index == other.m_index; - } - - private: - DynamicObject const& m_dynamic; - Elf_Sym const& m_sym; - unsigned const m_index; - }; - - class Section { - public: - Section(DynamicObject const& dynamic, unsigned section_offset, unsigned section_size_bytes, unsigned entry_size, StringView name) - : m_dynamic(dynamic) - , m_section_offset(section_offset) - , m_section_size_bytes(section_size_bytes) - , m_entry_size(entry_size) - , m_name(name) - { - } - ~Section() = default; - - StringView name() const { return m_name; } - unsigned offset() const { return m_section_offset; } - unsigned size() const { return m_section_size_bytes; } - unsigned entry_size() const { return m_entry_size; } - unsigned entry_count() const - { - return !entry_size() ? 0 : size() / entry_size(); - } - VirtualAddress address() const - { - return m_dynamic.base_address().offset(m_section_offset); - } - - protected: - friend class RelocationSection; - friend class HashSection; - DynamicObject const& m_dynamic; - unsigned m_section_offset; - unsigned m_section_size_bytes; - unsigned m_entry_size; - StringView m_name; - }; - - class RelocationSection : public Section { - public: - explicit RelocationSection(Section const& section, bool addend_used) - : Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name) - , m_addend_used(addend_used) - { - } - unsigned relocation_count() const { return entry_count(); } - Relocation relocation(unsigned index) const; - Relocation relocation_at_offset(unsigned offset) const; - - template F> - void for_each_relocation(F) const; - template F> - void for_each_relocation(F func) const; - - private: - bool const m_addend_used; - }; - - class Relocation { - public: - Relocation(DynamicObject const& dynamic, Elf_Rela const& rel, unsigned offset_in_section, bool addend_used) - : m_dynamic(dynamic) - , m_rel(rel) - , m_offset_in_section(offset_in_section) - , m_addend_used(addend_used) - { - } - - ~Relocation() = default; - - unsigned offset_in_section() const { return m_offset_in_section; } - unsigned offset() const { return m_rel.r_offset; } - unsigned type() const - { - return ELF64_R_TYPE(m_rel.r_info); - } - unsigned symbol_index() const { return ELF64_R_SYM(m_rel.r_info); } - unsigned addend() const - { - VERIFY(m_addend_used); - return m_rel.r_addend; - } - bool addend_used() const { return m_addend_used; } - - Symbol symbol() const - { - return m_dynamic.symbol(symbol_index()); - } - VirtualAddress address() const - { - if (m_dynamic.elf_is_dynamic()) - return m_dynamic.base_address().offset(offset()); - return VirtualAddress { offset() }; - } - [[nodiscard]] DynamicObject const& dynamic_object() const { return m_dynamic; } - - private: - DynamicObject const& m_dynamic; - Elf_Rela const& m_rel; - unsigned const m_offset_in_section; - bool const m_addend_used; - }; - - enum class HashType { - SYSV, - GNU - }; - - class HashSymbol { - public: - HashSymbol(StringView name) - : m_name(name) - { - } - - StringView name() const { return m_name; } - u32 gnu_hash() const; - u32 sysv_hash() const; - - private: - StringView m_name; - mutable Optional m_gnu_hash; - mutable Optional m_sysv_hash; - }; - - class HashSection : public Section { - public: - HashSection(Section const& section, HashType hash_type) - : Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name) - , m_hash_type(hash_type) - { - } - - Optional lookup_symbol(HashSymbol const& symbol) const - { - if (m_hash_type == HashType::SYSV) - return lookup_sysv_symbol(symbol.name(), symbol.sysv_hash()); - return lookup_gnu_symbol(symbol.name(), symbol.gnu_hash()); - } - - private: - Optional lookup_sysv_symbol(StringView name, u32 hash_value) const; - Optional lookup_gnu_symbol(StringView name, u32 hash) const; - - HashType m_hash_type {}; - }; - - unsigned symbol_count() const { return m_symbol_count; } - - Symbol symbol(unsigned) const; - - typedef void (*InitializationFunction)(); - typedef void (*FinalizationFunction)(); - typedef Elf_Addr (*IfuncResolver)(); - - bool has_init_section() const { return m_init_offset != 0; } - bool has_init_array_section() const { return m_init_array_offset != 0; } - Section init_section() const; - InitializationFunction init_section_function() const; - Section init_array_section() const; - - bool is_pie() const { return m_is_pie; } - - bool has_fini_section() const { return m_fini_offset != 0; } - bool has_fini_array_section() const { return m_fini_array_offset != 0; } - Section fini_section() const; - FinalizationFunction fini_section_function() const; - Section fini_array_section() const; - - HashSection hash_section() const - { - auto section_name = m_hash_type == HashType::SYSV ? "DT_HASH"sv : "DT_GNU_HASH"sv; - - return HashSection(Section(*this, m_hash_table_offset, 0, 0, section_name), m_hash_type); - } - - RelocationSection relocation_section() const; - RelocationSection plt_relocation_section() const; - Section relr_relocation_section() const; - - bool should_process_origin() const { return m_dt_flags & DF_ORIGIN; } - bool requires_symbolic_symbol_resolution() const { return m_dt_flags & DF_SYMBOLIC; } - // Text relocations meaning: we need to edit the .text section which is normally mapped PROT_READ - bool has_text_relocations() const { return m_dt_flags & DF_TEXTREL; } - bool must_bind_now() const { return m_dt_flags & DF_BIND_NOW; } - bool has_static_thread_local_storage() const { return m_dt_flags & DF_STATIC_TLS; } - - bool has_plt() const { return m_procedure_linkage_table_offset.has_value(); } - VirtualAddress plt_got_base_address() const { return m_base_address.offset(m_procedure_linkage_table_offset.value()); } - VirtualAddress base_address() const { return m_base_address; } - - ByteString const& filepath() const { return m_filepath; } - - StringView rpath() const { return m_has_rpath ? symbol_string_table_string(m_rpath_index) : StringView {}; } - StringView runpath() const { return m_has_runpath ? symbol_string_table_string(m_runpath_index) : StringView {}; } - StringView soname() const { return m_has_soname ? symbol_string_table_string(m_soname_index) : StringView {}; } - - Optional tls_offset() const { return m_tls_offset; } - Optional tls_size() const { return m_tls_size; } - void set_tls_offset(FlatPtr offset) { m_tls_offset = offset; } - void set_tls_size(FlatPtr size) { m_tls_size = size; } - - Elf_Half program_header_count() const; - Elf_Phdr const* program_headers() const; - - template F> - void for_each_needed_library(F) const; - - template F> - void for_each_initialization_array_function(F f) const; - - template F> - void for_each_dynamic_entry(F) const; - template F> - void for_each_dynamic_entry(F func) const; - - template F> - void for_each_symbol(F) const; - - template - void for_each_relr_relocation(F) const; - - struct SymbolLookupResult { - FlatPtr value { 0 }; - size_t size { 0 }; - VirtualAddress address; - unsigned bind { STB_LOCAL }; - unsigned type { STT_FUNC }; - const ELF::DynamicObject* dynamic_object { nullptr }; // The object in which the symbol is defined - }; - - Optional lookup_symbol(StringView name) const; - Optional lookup_symbol(HashSymbol const& symbol) const; - - bool elf_is_dynamic() const { return m_is_elf_dynamic; } - - void* symbol_for_name(StringView name); - -private: - explicit DynamicObject(ByteString const& filepath, VirtualAddress base_address, VirtualAddress dynamic_section_address); - - StringView symbol_string_table_string(Elf_Word) const; - char const* raw_symbol_string_table_string(Elf_Word) const; - void parse(); - - ByteString m_filepath; - - VirtualAddress m_base_address; - VirtualAddress m_dynamic_address; - VirtualAddress m_elf_base_address; - - unsigned m_symbol_count { 0 }; - - // Begin Section information collected from DT_* entries - FlatPtr m_init_offset { 0 }; - FlatPtr m_fini_offset { 0 }; - - FlatPtr m_init_array_offset { 0 }; - size_t m_init_array_size { 0 }; - FlatPtr m_fini_array_offset { 0 }; - size_t m_fini_array_size { 0 }; - - FlatPtr m_hash_table_offset { 0 }; - HashType m_hash_type { HashType::SYSV }; - - FlatPtr m_string_table_offset { 0 }; - size_t m_size_of_string_table { 0 }; - FlatPtr m_symbol_table_offset { 0 }; - size_t m_size_of_symbol_table_entry { 0 }; - - Elf_Sword m_procedure_linkage_table_relocation_type { -1 }; - FlatPtr m_plt_relocation_offset_location { 0 }; // offset of PLT relocations, at end of relocations - size_t m_size_of_plt_relocation_entry_list { 0 }; - Optional m_procedure_linkage_table_offset; - - // NOTE: We'll only ever either RELA or REL entries, not both (thank god) - // NOTE: The x86 ABI will only ever genrerate REL entries. - size_t m_number_of_relocations { 0 }; - size_t m_size_of_relocation_entry { 0 }; - size_t m_size_of_relocation_table { 0 }; - bool m_addend_used { false }; - FlatPtr m_relocation_table_offset { 0 }; - size_t m_size_of_relr_relocations_entry { 0 }; - size_t m_size_of_relr_relocation_table { 0 }; - FlatPtr m_relr_relocation_table_offset { 0 }; - bool m_is_elf_dynamic { false }; - - bool m_is_pie { false }; - - // DT_FLAGS - Elf_Word m_dt_flags { 0 }; - - bool m_has_soname { false }; - Elf_Word m_soname_index { 0 }; // Index into dynstr table for SONAME - bool m_has_rpath { false }; - Elf_Word m_rpath_index { 0 }; // Index into dynstr table for RPATH - bool m_has_runpath { false }; - Elf_Word m_runpath_index { 0 }; // Index into dynstr table for RUNPATH - - Optional m_tls_offset; - Optional m_tls_size; - // End Section information from DT_* entries -}; - -template F> -inline void DynamicObject::RelocationSection::for_each_relocation(F func) const -{ - for (unsigned i = 0; i < relocation_count(); ++i) { - auto const reloc = relocation(i); - if (static_cast(reloc.type()) == GenericDynamicRelocationType::NONE) - continue; - if (func(reloc) == IterationDecision::Break) - break; - } -} - -template F> -inline void DynamicObject::RelocationSection::for_each_relocation(F func) const -{ - for_each_relocation([&](auto& reloc) { - func(reloc); - return IterationDecision::Continue; - }); -} - -template -inline void DynamicObject::for_each_relr_relocation(F f) const -{ - auto section = relr_relocation_section(); - if (section.entry_count() == 0) - return; - - VERIFY(section.entry_size() == sizeof(FlatPtr)); - VERIFY(section.size() >= section.entry_size() * section.entry_count()); - - auto* entries = reinterpret_cast(section.address().get()); - auto base = base_address().get(); - FlatPtr patch_addr = 0; - for (unsigned i = 0; i < section.entry_count(); ++i) { - if ((entries[i] & 1u) == 0) { - patch_addr = base + entries[i]; - f(patch_addr); - patch_addr += sizeof(FlatPtr); - } else { - unsigned j = 0; - for (auto bitmap = entries[i]; (bitmap >>= 1u) != 0; ++j) - if (bitmap & 1u) - f(patch_addr + j * sizeof(FlatPtr)); - - patch_addr += (8 * sizeof(FlatPtr) - 1) * sizeof(FlatPtr); - } - } -} - -template F> -inline void DynamicObject::for_each_symbol(F func) const -{ - for (unsigned i = 0; i < symbol_count(); ++i) { - func(symbol(i)); - } -} - -template F> -inline void DynamicObject::for_each_dynamic_entry(F func) const -{ - auto* dyns = reinterpret_cast(m_dynamic_address.as_ptr()); - for (unsigned i = 0;; ++i) { - auto&& dyn = DynamicEntry(dyns[i]); - if (dyn.tag() == DT_NULL) - break; - if (func(dyn) == IterationDecision::Break) - break; - } -} - -template F> -inline void DynamicObject::for_each_dynamic_entry(F func) const -{ - for_each_dynamic_entry([&](auto& dyn) { - func(dyn); - return IterationDecision::Continue; - }); -} - -template F> -inline void DynamicObject::for_each_needed_library(F func) const -{ - for_each_dynamic_entry([func, this](auto entry) { - if (entry.tag() != DT_NEEDED) - return; - Elf_Word offset = entry.val(); - func(symbol_string_table_string(offset)); - }); -} - -template F> -void DynamicObject::for_each_initialization_array_function(F f) const -{ - if (!has_init_array_section()) - return; - FlatPtr init_array = (FlatPtr)init_array_section().address().as_ptr(); - for (size_t i = 0; i < (m_init_array_size / sizeof(void*)); ++i) { - InitializationFunction current = ((InitializationFunction*)(init_array))[i]; - f(current); - } -} - -} // end namespace ELF diff --git a/Userland/Libraries/LibELF/ELFABI.h b/Userland/Libraries/LibELF/ELFABI.h deleted file mode 100644 index fa6a8a91dee..00000000000 --- a/Userland/Libraries/LibELF/ELFABI.h +++ /dev/null @@ -1,908 +0,0 @@ -/* $OpenBSD: exec_elf.h,v 1.83 2019/01/22 23:23:18 jsg Exp $ */ -/* - * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This is the ELF ABI header file - * formerly known as "elf_abi.h". - */ - -#pragma once - -#ifndef KERNEL -# include -# include -#else -# include -#endif - -#define ElfW(type) Elf64_##type - -#define ELFSIZE 64 - -typedef uint8_t Elf_Byte; - -typedef uint32_t Elf32_Addr; /* Unsigned program address */ -typedef uint32_t Elf32_Off; /* Unsigned file offset */ -typedef int32_t Elf32_Sword; /* Signed large integer */ -typedef uint32_t Elf32_Word; /* Unsigned large integer */ -typedef uint16_t Elf32_Half; /* Unsigned medium integer */ -typedef uint64_t Elf32_Lword; - -typedef uint64_t Elf64_Addr; -typedef uint64_t Elf64_Off; -typedef int32_t Elf64_Shalf; - -#ifdef __alpha__ -typedef int64_t Elf64_Sword; -typedef uint64_t Elf64_Word; -#else -typedef int32_t Elf64_Sword; -typedef uint32_t Elf64_Word; -#endif - -typedef int64_t Elf64_Sxword; -typedef uint64_t Elf64_Xword; -typedef uint64_t Elf64_Lword; - -typedef uint32_t Elf64_Half; -typedef uint16_t Elf64_Quarter; - -/* - * e_ident[] identification indices - * See http://www.sco.com/developers/gabi/latest/ch4.eheader.html - */ -#define EI_MAG0 0 /* file ID */ -#define EI_MAG1 1 /* file ID */ -#define EI_MAG2 2 /* file ID */ -#define EI_MAG3 3 /* file ID */ -#define EI_CLASS 4 /* file class */ -#define EI_DATA 5 /* data encoding */ -#define EI_VERSION 6 /* ELF header version */ -#define EI_OSABI 7 /* OS/ABI ID */ -#define EI_ABIVERSION 8 /* ABI version */ -#define EI_PAD 9 /* start of pad bytes */ -#define EI_NIDENT 16 /* Gfx::Size of e_ident[] */ - -/* e_ident[] magic number */ -#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ -#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ -#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ -#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ -#define ELFMAG "\177ELF" /* magic */ -#define SELFMAG 4 /* size of magic */ - -/* e_ident[] file class */ -#define ELFCLASSNONE 0 /* invalid */ -#define ELFCLASS32 1 /* 32-bit objs */ -#define ELFCLASS64 2 /* 64-bit objs */ -#define ELFCLASSNUM 3 /* number of classes */ - -/* e_ident[] data encoding */ -#define ELFDATANONE 0 /* invalid */ -#define ELFDATA2LSB 1 /* Little-Endian */ -#define ELFDATA2MSB 2 /* Big-Endian */ -#define ELFDATANUM 3 /* number of data encode defines */ - -/* e_ident[] Operating System/ABI */ -#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ -#define ELFOSABI_HPUX 1 /* HP-UX operating system */ -#define ELFOSABI_NETBSD 2 /* NetBSD */ -#define ELFOSABI_LINUX 3 /* GNU/Linux */ -#define ELFOSABI_GNU ELFOSABI_LINUX -#define ELFOSABI_HURD 4 /* GNU/Hurd */ -#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ -#define ELFOSABI_SOLARIS 6 /* Solaris */ -#define ELFOSABI_MONTEREY 7 /* Monterey */ -#define ELFOSABI_AIX ELFOSABI_MONTEREY -#define ELFOSABI_IRIX 8 /* IRIX */ -#define ELFOSABI_FREEBSD 9 /* FreeBSD */ -#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ -#define ELFOSABI_MODESTO 11 /* Novell Modesto */ -#define ELFOSABI_OPENBSD 12 /* OpenBSD */ -#define ELFOSABI_ARM 97 /* ARM */ -#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ - -/* e_ident */ -#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && (ehdr).e_ident[EI_MAG1] == ELFMAG1 && (ehdr).e_ident[EI_MAG2] == ELFMAG2 && (ehdr).e_ident[EI_MAG3] == ELFMAG3) - -/* ELF Header */ -typedef struct elfhdr { - unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ - Elf32_Half e_type; /* object file type */ - Elf32_Half e_machine; /* machine */ - Elf32_Word e_version; /* object file version */ - Elf32_Addr e_entry; /* virtual entry point */ - Elf32_Off e_phoff; /* program header table offset */ - Elf32_Off e_shoff; /* section header table offset */ - Elf32_Word e_flags; /* processor-specific flags */ - Elf32_Half e_ehsize; /* ELF header size */ - Elf32_Half e_phentsize; /* program header entry size */ - Elf32_Half e_phnum; /* number of program header entries */ - Elf32_Half e_shentsize; /* section header entry size */ - Elf32_Half e_shnum; /* number of section header entries */ - Elf32_Half e_shstrndx; /* section header table's "section - header string table" entry offset */ -} Elf32_Ehdr; - -typedef struct { - unsigned char e_ident[EI_NIDENT]; /* Id bytes */ - Elf64_Quarter e_type; /* file type */ - Elf64_Quarter e_machine; /* machine type */ - Elf64_Half e_version; /* version number */ - Elf64_Addr e_entry; /* entry point */ - Elf64_Off e_phoff; /* Program hdr offset */ - Elf64_Off e_shoff; /* Section hdr offset */ - Elf64_Half e_flags; /* Processor flags */ - Elf64_Quarter e_ehsize; /* sizeof ehdr */ - Elf64_Quarter e_phentsize; /* Program header entry size */ - Elf64_Quarter e_phnum; /* Number of program headers */ - Elf64_Quarter e_shentsize; /* Section header entry size */ - Elf64_Quarter e_shnum; /* Number of section headers */ - Elf64_Quarter e_shstrndx; /* String table index */ -} Elf64_Ehdr; - -/* e_type */ -#define ET_NONE 0 /* No file type */ -#define ET_REL 1 /* relocatable file */ -#define ET_EXEC 2 /* executable file */ -#define ET_DYN 3 /* shared object file */ -#define ET_CORE 4 /* core file */ -#define ET_NUM 5 /* number of types */ -#define ET_LOPROC 0xff00 /* reserved range for processor */ -#define ET_HIPROC 0xffff /* specific e_type */ - -/* e_machine */ -#define EM_NONE 0 /* No Machine */ -#define EM_M32 1 /* AT&T WE 32100 */ -#define EM_SPARC 2 /* SPARC */ -#define EM_386 3 /* Intel 80386 */ -#define EM_68K 4 /* Motorola 68000 */ -#define EM_88K 5 /* Motorola 88000 */ -#define EM_486 6 /* Intel 80486 - unused? */ -#define EM_860 7 /* Intel 80860 */ -#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ -/* - * Don't know if EM_MIPS_RS4_BE, - * EM_SPARC64, EM_PARISC, - * or EM_PPC are ABI compliant - */ -#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ -#define EM_SPARC64 11 /* SPARC v9 64-bit unofficial */ -#define EM_PARISC 15 /* HPPA */ -#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ -#define EM_PPC 20 /* PowerPC */ -#define EM_PPC64 21 /* PowerPC 64 */ -#define EM_S390 22 /* IBM S390 */ -#define EM_ARM 40 /* Advanced RISC Machines ARM */ -#define EM_ALPHA 41 /* DEC ALPHA */ -#define EM_SH 42 /* Hitachi/Renesas Super-H */ -#define EM_SPARCV9 43 /* SPARC version 9 */ -#define EM_IA_64 50 /* Intel IA-64 Processor */ -#define EM_AMD64 62 /* AMD64 architecture */ -#define EM_X86_64 EM_AMD64 -#define EM_VAX 75 /* DEC VAX */ -#define EM_AARCH64 183 /* ARM 64-bit architecture (AArch64) */ -#define EM_RISCV 243 /* RISC-V */ - -/* Non-standard */ -#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */ -#define EM__LAST__ (EM_ALPHA_EXP + 1) - -#define EM_NUM 22 /* number of machine types */ - -/* Version */ -#define EV_NONE 0 /* Invalid */ -#define EV_CURRENT 1 /* Current */ -#define EV_NUM 2 /* number of versions */ - -/* Magic for e_phnum: get real value from sh_info of first section header */ -#define PN_XNUM 0xffff - -/* RISC-V specific e_flags */ -/* See: RISC-V ABI Specification 1.0, Section 8.1: File Header */ -#define EF_RISCV_RVC 0x0001 /* Binary targets the Compressed ABI */ -#define EF_RISCV_FLOAT_ABI_SOFT 0x0000 /* No hardware float ABI in use */ -#define EF_RISCV_FLOAT_ABI_SINGLE 0x0002 /* 32-bit hardware float ABI */ -#define EF_RISCV_FLOAT_ABI_DOUBLE 0x0004 /* 64-bit hardware float ABI */ -#define EF_RISCV_FLOAT_ABI_QUAD 0x0006 /* 128-bit hardware float ABI */ -#define EF_RISCV_FLOAT_ABI 0x0006 /* Test mask for float ABIs */ -#define EF_RISCV_RVE 0x0008 /* Binary targets the Embedded ABI */ -#define EF_RISCV_TSO 0x0010 /* Binary requires Ztso extension */ - -/* Section Header */ -typedef struct { - Elf32_Word sh_name; /* name - index into section header - string table section */ - Elf32_Word sh_type; /* type */ - Elf32_Word sh_flags; /* flags */ - Elf32_Addr sh_addr; /* address */ - Elf32_Off sh_offset; /* file offset */ - Elf32_Word sh_size; /* section size */ - Elf32_Word sh_link; /* section header table index link */ - Elf32_Word sh_info; /* extra information */ - Elf32_Word sh_addralign; /* address alignment */ - Elf32_Word sh_entsize; /* section entry size */ -} Elf32_Shdr; - -typedef struct { - Elf64_Half sh_name; /* section name */ - Elf64_Half sh_type; /* section type */ - Elf64_Xword sh_flags; /* section flags */ - Elf64_Addr sh_addr; /* virtual address */ - Elf64_Off sh_offset; /* file offset */ - Elf64_Xword sh_size; /* section size */ - Elf64_Half sh_link; /* link to another */ - Elf64_Half sh_info; /* misc info */ - Elf64_Xword sh_addralign; /* memory alignment */ - Elf64_Xword sh_entsize; /* table entry size */ -} Elf64_Shdr; - -/* Special Section Indices */ -#define SHN_UNDEF 0 /* undefined */ -#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indices */ -#define SHN_LOPROC 0xff00 /* reserved range for processor */ -#define SHN_HIPROC 0xff1f /* specific section indices */ -#define SHN_ABS 0xfff1 /* absolute value */ -#define SHN_COMMON 0xfff2 /* common symbol */ -#define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere. */ -#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indices */ - -/* sh_type */ -#define SHT_NULL 0 /* inactive */ -#define SHT_PROGBITS 1 /* program defined information */ -#define SHT_SYMTAB 2 /* symbol table section */ -#define SHT_STRTAB 3 /* string table section */ -#define SHT_RELA 4 /* relocation section with addends*/ -#define SHT_HASH 5 /* symbol hash table section */ -#define SHT_DYNAMIC 6 /* dynamic section */ -#define SHT_NOTE 7 /* note section */ -#define SHT_NOBITS 8 /* no space section */ -#define SHT_REL 9 /* relation section without addends */ -#define SHT_SHLIB 10 /* reserved - purpose unknown */ -#define SHT_DYNSYM 11 /* dynamic symbol table section */ -#define SHT_NUM 12 /* number of section types */ -#define SHT_INIT_ARRAY 14 /* pointers to init functions */ -#define SHT_FINI_ARRAY 15 /* pointers to termination functions */ -#define SHT_PREINIT_ARRAY 16 /* ptrs to funcs called before init */ -#define SHT_GROUP 17 /* defines a section group */ -#define SHT_SYMTAB_SHNDX 18 /* Section indices (see SHN_XINDEX). */ -#define SHT_RELR 19 /* relative-only relocation section */ -#define SHT_LOOS 0x60000000 /* reserved range for OS specific */ -#define SHT_SUNW_dof 0x6ffffff4 /* used by dtrace */ -#define SHT_GNU_LIBLIST 0x6ffffff7 /* libraries to be prelinked */ -#define SHT_SUNW_move 0x6ffffffa /* inf for partially init'ed symbols */ -#define SHT_SUNW_syminfo 0x6ffffffc /* ad symbol information */ -#define SHT_SUNW_verdef 0x6ffffffd /* symbol versioning inf */ -#define SHT_SUNW_verneed 0x6ffffffe /* symbol versioning req */ -#define SHT_SUNW_versym 0x6fffffff /* symbol versioning table */ -#define SHT_HIOS 0x6fffffff /* section header types */ -#define SHT_LOPROC 0x70000000 /* reserved range for processor */ -#define SHT_HIPROC 0x7fffffff /* specific section header types */ -#define SHT_LOUSER 0x80000000 /* reserved range for application */ -#define SHT_HIUSER 0xffffffff /* specific indices */ - -#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table section */ - -/* Section names */ -#define ELF_BSS ".bss" /* uninitialized data */ -#define ELF_DATA ".data" /* initialized data */ -#define ELF_CTF ".SUNW_ctf" /* CTF data */ -#define ELF_DEBUG ".debug" /* debug */ -#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ -#define ELF_DYNSTR ".dynstr" /* dynamic string table */ -#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ -#define ELF_FINI ".fini" /* termination code */ -#define ELF_GOT ".got" /* global offset table */ -#define ELF_HASH ".hash" /* symbol hash table */ -#define ELF_INIT ".init" /* initialization code */ -#define ELF_REL_DATA ".rel.data" /* relocation data */ -#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ -#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ -#define ELF_REL_DYN ".rel.dyn" /* relocation dynamic link info */ -#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ -#define ELF_REL_TEXT ".rel.text" /* relocation code */ -#define ELF_RODATA ".rodata" /* read-only data */ -#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ -#define ELF_STRTAB ".strtab" /* string table */ -#define ELF_SYMTAB ".symtab" /* symbol table */ -#define ELF_TEXT ".text" /* code */ -#define ELF_OPENBSDRANDOMDATA ".openbsd.randomdata" /* constant randomdata */ - -/* Section Attribute Flags - sh_flags */ -#define SHF_WRITE 0x1 /* Writable */ -#define SHF_ALLOC 0x2 /* occupies memory */ -#define SHF_EXECINSTR 0x4 /* executable */ -#define SHF_MERGE 0x10 /* may be merged */ -#define SHF_STRINGS 0x20 /* contains strings */ -#define SHF_INFO_LINK 0x40 /* sh_info holds section index */ -#define SHF_LINK_ORDER 0x80 /* ordering requirements */ -#define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required */ -#define SHF_GROUP 0x200 /* member of section group */ -#define SHF_TLS 0x400 /* thread local storage */ -#define SHF_COMPRESSED 0x800 /* contains compressed data */ -#define SHF_MASKOS 0x0ff00000 /* OS-specific semantics */ -#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */ - /* specific section attributes */ - -/* Symbol Table Entry */ -typedef struct elf32_sym { - Elf32_Word st_name; /* name - index into string table */ - Elf32_Addr st_value; /* symbol value */ - Elf32_Word st_size; /* symbol size */ - unsigned char st_info; /* type and binding */ - unsigned char st_other; /* 0 - no defined meaning */ - Elf32_Half st_shndx; /* section header index */ -} Elf32_Sym; - -typedef struct { - Elf64_Half st_name; /* Symbol name index in str table */ - Elf_Byte st_info; /* type / binding attrs */ - Elf_Byte st_other; /* unused */ - Elf64_Quarter st_shndx; /* section index of symbol */ - Elf64_Xword st_value; /* value of symbol */ - Elf64_Xword st_size; /* size of symbol */ -} Elf64_Sym; - -/* Symbol table index */ -#define STN_UNDEF 0 /* undefined */ - -/* Extract symbol info - st_info */ -#define ELF32_ST_BIND(x) ((x) >> 4) -#define ELF32_ST_TYPE(x) (((unsigned int)x) & 0xf) -#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t) & 0xf)) - -#define ELF64_ST_BIND(x) ((x) >> 4) -#define ELF64_ST_TYPE(x) (((unsigned int)x) & 0xf) -#define ELF64_ST_INFO(b, t) (((b) << 4) + ((t) & 0xf)) - -/* Symbol Binding - ELF32_ST_BIND - st_info */ -#define STB_LOCAL 0 /* Local symbol */ -#define STB_GLOBAL 1 /* Global symbol */ -#define STB_WEAK 2 /* like global - lower precedence */ -#define STB_NUM 3 /* number of symbol bindings */ -#define STB_LOPROC 13 /* reserved range for processor */ -#define STB_HIPROC 15 /* specific symbol bindings */ - -/* Symbol type - ELF32_ST_TYPE - st_info */ -#define STT_NOTYPE 0 /* not specified */ -#define STT_OBJECT 1 /* data object */ -#define STT_FUNC 2 /* function */ -#define STT_SECTION 3 /* section */ -#define STT_FILE 4 /* file */ -#define STT_TLS 6 /* thread local storage */ -#define STT_GNU_IFUNC 10 -#define STT_LOPROC 13 /* reserved range for processor */ -#define STT_HIPROC 15 /* specific symbol types */ - -/* Extract symbol visibility - st_other */ -#define ELF_ST_VISIBILITY(v) ((v) & 0x3) -#define ELF32_ST_VISIBILITY ELF_ST_VISIBILITY -#define ELF64_ST_VISIBILITY ELF_ST_VISIBILITY - -#define STV_DEFAULT 0 /* Visibility set by binding type */ -#define STV_INTERNAL 1 /* OS specific version of STV_HIDDEN */ -#define STV_HIDDEN 2 /* can only be seen inside own .so */ -#define STV_PROTECTED 3 /* HIDDEN inside, DEFAULT outside */ - -/* Relocation entry with implicit addend */ -typedef struct { - Elf32_Addr r_offset; /* offset of relocation */ - Elf32_Word r_info; /* symbol table index and type */ -} Elf32_Rel; - -/* Relocation entry with explicit addend */ -typedef struct { - Elf32_Addr r_offset; /* offset of relocation */ - Elf32_Word r_info; /* symbol table index and type */ - Elf32_Sword r_addend; -} Elf32_Rela; - -/* Extract relocation info - r_info */ -#define ELF32_R_SYM(i) ((i) >> 8) -#define ELF32_R_TYPE(i) ((unsigned char)(i)) -#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) - -typedef struct { - Elf64_Xword r_offset; /* where to do it */ - Elf64_Xword r_info; /* index & type of relocation */ -} Elf64_Rel; - -typedef struct { - Elf64_Xword r_offset; /* where to do it */ - Elf64_Xword r_info; /* index & type of relocation */ - Elf64_Sxword r_addend; /* adjustment value */ -} Elf64_Rela; - -#define ELF64_R_SYM(info) ((info) >> 32) -#define ELF64_R_TYPE(info) ((info) & 0xFFFFFFFF) -#define ELF64_R_INFO(s, t) (((s) << 32) + (uint32_t)(t)) - -#if defined(__mips64__) && defined(__MIPSEL__) -/* - * The 64-bit MIPS ELF ABI uses a slightly different relocation format - * than the regular ELF ABI: the r_info field is split into several - * pieces (see gnu/usr.bin/binutils-2.17/include/elf/mips.h for details). - */ -# undef ELF64_R_SYM -# undef ELF64_R_TYPE -# undef ELF64_R_INFO -# define ELF64_R_TYPE(info) ((uint64_t)swap32((info) >> 32)) -# define ELF64_R_SYM(info) ((info) & 0xFFFFFFFF) -# define ELF64_R_INFO(s, t) (((uint64_t)swap32(t) << 32) + (uint32_t)(s)) -#endif /* __mips64__ && __MIPSEL__ */ - -typedef Elf32_Word Elf32_Relr; -typedef Elf64_Xword Elf64_Relr; - -/* Program Header */ -typedef struct { - Elf32_Word p_type; /* segment type */ - Elf32_Off p_offset; /* segment offset */ - Elf32_Addr p_vaddr; /* virtual address of segment */ - Elf32_Addr p_paddr; /* physical address - ignored? */ - Elf32_Word p_filesz; /* number of bytes in file for seg. */ - Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ - Elf32_Word p_flags; /* flags */ - Elf32_Word p_align; /* memory alignment */ -} Elf32_Phdr; - -typedef struct { - Elf64_Half p_type; /* entry type */ - Elf64_Half p_flags; /* flags */ - Elf64_Off p_offset; /* offset */ - Elf64_Addr p_vaddr; /* virtual address */ - Elf64_Addr p_paddr; /* physical address */ - Elf64_Xword p_filesz; /* file size */ - Elf64_Xword p_memsz; /* memory size */ - Elf64_Xword p_align; /* memory & file alignment */ -} Elf64_Phdr; - -/* Segment types - p_type */ -#define PT_NULL 0 /* unused */ -#define PT_LOAD 1 /* loadable segment */ -#define PT_DYNAMIC 2 /* dynamic linking section */ -#define PT_INTERP 3 /* the RTLD */ -#define PT_NOTE 4 /* auxiliary information */ -#define PT_SHLIB 5 /* reserved - purpose undefined */ -#define PT_PHDR 6 /* program header */ -#define PT_TLS 7 /* thread local storage */ -#define PT_LOOS 0x60000000 /* reserved range for OS */ -#define PT_HIOS 0x6fffffff /* specific segment types */ - -#define PT_LOPROC 0x70000000 /* start of reserved range for processor specific segment types */ -#define PT_RISCV_ATTRIBUTES 0x70000003 /* RISC-V ELF attribute section */ -#define PT_HIPROC 0x7fffffff /* end of reserved range for processor specific segment types */ - -#define PT_GNU_EH_FRAME 0x6474e550 /* Exception handling info */ -#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ -#define PT_GNU_STACK 0x6474e551 /* Stack permissions & size info */ - -#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */ -#define PT_OPENBSD_WXNEEDED 0x65a3dbe7 /* program performs W^X violations */ -#define PT_OPENBSD_BOOTDATA 0x65a41be6 /* section for boot arguments */ - -/* Segment flags - p_flags */ -#define PF_X 0x1 /* Executable */ -#define PF_W 0x2 /* Writable */ -#define PF_R 0x4 /* Readable */ -#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ - /* specific segment flags */ - -/* Dynamic structure */ -typedef struct { - Elf32_Sword d_tag; /* controls meaning of d_val */ - union { - Elf32_Word d_val; /* Multiple meanings - see d_tag */ - Elf32_Addr d_ptr; /* program virtual address */ - } d_un; -} Elf32_Dyn; - -typedef struct { - Elf64_Xword d_tag; /* controls meaning of d_val */ - union { - Elf64_Addr d_ptr; - Elf64_Xword d_val; - } d_un; -} Elf64_Dyn; - -/* Dynamic Array Tags - d_tag */ -#define DT_NULL 0 /* marks end of _DYNAMIC array */ -#define DT_NEEDED 1 /* string table offset of needed lib */ -#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ -#define DT_PLTGOT 3 /* address PLT/GOT */ -#define DT_HASH 4 /* address of symbol hash table */ -#define DT_STRTAB 5 /* address of string table */ -#define DT_SYMTAB 6 /* address of symbol table */ -#define DT_RELA 7 /* address of relocation table */ -#define DT_RELASZ 8 /* size of relocation table */ -#define DT_RELAENT 9 /* size of relocation entry */ -#define DT_STRSZ 10 /* size of string table */ -#define DT_SYMENT 11 /* size of symbol table entry */ -#define DT_INIT 12 /* address of initialization func. */ -#define DT_FINI 13 /* address of termination function */ -#define DT_SONAME 14 /* string table offset of shared obj */ -#define DT_RPATH 15 /* string table offset of library \ - search path */ -#define DT_SYMBOLIC 16 /* start sym search in shared obj. */ -#define DT_REL 17 /* address of rel. tbl. w addends */ -#define DT_RELSZ 18 /* size of DT_REL relocation table */ -#define DT_RELENT 19 /* size of DT_REL relocation entry */ -#define DT_PLTREL 20 /* PLT referenced relocation entry */ -#define DT_DEBUG 21 /* bugger */ -#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ -#define DT_JMPREL 23 /* add. of PLT's relocation entries */ -#define DT_BIND_NOW 24 /* Bind now regardless of env setting */ -#define DT_INIT_ARRAY 25 /* address of array of init func */ -#define DT_FINI_ARRAY 26 /* address of array of term func */ -#define DT_INIT_ARRAYSZ 27 /* size of array of init func */ -#define DT_FINI_ARRAYSZ 28 /* size of array of term func */ -#define DT_RUNPATH 29 /* strtab offset of lib search path */ -#define DT_FLAGS 30 /* Set of DF_* flags */ -#define DT_ENCODING 31 /* further DT_* follow encoding rules */ -#define DT_PREINIT_ARRAY 32 /* address of array of preinit func */ -#define DT_PREINIT_ARRAYSZ 33 /* size of array of preinit func */ -#define DT_RELRSZ 35 /* size of DT_RELR relocation table */ -#define DT_RELR 36 /* addr of DT_RELR relocation table */ -#define DT_RELRENT 37 /* size of DT_RELR relocation entry */ -#define DT_LOOS 0x6000000d /* reserved range for OS */ -#define DT_HIOS 0x6ffff000 /* specific dynamic array tags */ -#define DT_LOPROC 0x70000000 /* reserved range for processor */ -#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ - -/* some other useful tags */ -#define DT_GNU_HASH 0x6ffffef5 /* address of GNU hash table */ -#define DT_VERSYM 0x6ffffff0 /* address of table provided by .gnu.version */ -#define DT_RELACOUNT 0x6ffffff9 /* if present, number of RELATIVE */ -#define DT_RELCOUNT 0x6ffffffa /* relocs, which must come first */ -#define DT_FLAGS_1 0x6ffffffb -#define DT_VERDEF 0x6ffffffc /* address of version definition table */ -#define DT_VERDEFNUM 0x6ffffffd /* number of version definitions */ -#define DT_VERNEEDED 0x6ffffffe /* address of the dependency table */ -#define DT_VERNEEDEDNUM 0x6fffffff /* number of entries in VERNEEDED */ - -/* Dynamic Flags - DT_FLAGS .dynamic entry */ -#define DF_ORIGIN 0x00000001 -#define DF_SYMBOLIC 0x00000002 -#define DF_TEXTREL 0x00000004 -#define DF_BIND_NOW 0x00000008 -#define DF_STATIC_TLS 0x00000010 - -/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */ -#define DF_1_NOW 0x00000001 -#define DF_1_GLOBAL 0x00000002 -#define DF_1_GROUP 0x00000004 -#define DF_1_NODELETE 0x00000008 -#define DF_1_LOADFLTR 0x00000010 -#define DF_1_INITFIRST 0x00000020 -#define DF_1_NOOPEN 0x00000040 -#define DF_1_ORIGIN 0x00000080 -#define DF_1_DIRECT 0x00000100 -#define DF_1_TRANS 0x00000200 -#define DF_1_INTERPOSE 0x00000400 -#define DF_1_NODEFLIB 0x00000800 -#define DF_1_NODUMP 0x00001000 -#define DF_1_CONLFAT 0x00002000 - -/* - * Note header - */ -typedef struct { - Elf32_Word n_namesz; - Elf32_Word n_descsz; - Elf32_Word n_type; -} Elf32_Nhdr; - -typedef struct { - Elf64_Half n_namesz; - Elf64_Half n_descsz; - Elf64_Half n_type; -} Elf64_Nhdr; - -/* - * Note Definitions - */ -typedef struct { - Elf32_Word namesz; - Elf32_Word descsz; - Elf32_Word type; -} Elf32_Note; - -typedef struct { - Elf64_Half namesz; - Elf64_Half descsz; - Elf64_Half type; -} Elf64_Note; - -/* Values for n_type. */ -#define NT_PRSTATUS 1 /* Process status. */ -#define NT_FPREGSET 2 /* Floating point registers. */ -#define NT_PRPSINFO 3 /* Process state info. */ - -/* - * OpenBSD-specific core file information. - * - * OpenBSD ELF core files use notes to provide information about - * the process's state. The note name is "OpenBSD" for information - * that is global to the process, and "OpenBSD@nn", where "nn" is the - * thread ID of the thread that the information belongs to (such as - * register state). - * - * We use the following note identifiers: - * - * NT_OPENBSD_PROCINFO - * Note is a "elfcore_procinfo" structure. - * NT_OPENBSD_AUXV - * Note is a a bunch of Auxiliary Vectors, terminated by - * an AT_NULL entry. - * NT_OPENBSD_REGS - * Note is a "reg" structure. - * NT_OPENBSD_FPREGS - * Note is a "fpreg" structure. - * - * Please try to keep the members of the "elfcore_procinfo" structure - * nicely aligned, and if you add elements, add them to the end and - * bump the version. - */ - -#define NT_OPENBSD_PROCINFO 10 -#define NT_OPENBSD_AUXV 11 - -#define NT_OPENBSD_REGS 20 -#define NT_OPENBSD_FPREGS 21 -#define NT_OPENBSD_XFPREGS 22 -#define NT_OPENBSD_WCOOKIE 23 - -struct elfcore_procinfo { - /* Version 1 fields start here. */ - uint32_t cpi_version; /* netbsd_elfcore_procinfo version */ -#define ELFCORE_PROCINFO_VERSION 1 - uint32_t cpi_cpisize; /* sizeof(netbsd_elfcore_procinfo) */ - uint32_t cpi_signo; /* killing signal */ - uint32_t cpi_sigcode; /* signal code */ - uint32_t cpi_sigpend; /* pending signals */ - uint32_t cpi_sigmask; /* blocked signals */ - uint32_t cpi_sigignore; /* ignored signals */ - uint32_t cpi_sigcatch; /* signals being caught by user */ - int32_t cpi_pid; /* process ID */ - int32_t cpi_ppid; /* parent process ID */ - int32_t cpi_pgrp; /* process group ID */ - int32_t cpi_sid; /* session ID */ - uint32_t cpi_ruid; /* real user ID */ - uint32_t cpi_euid; /* effective user ID */ - uint32_t cpi_svuid; /* saved user ID */ - uint32_t cpi_rgid; /* real group ID */ - uint32_t cpi_egid; /* effective group ID */ - uint32_t cpi_svgid; /* saved group ID */ - int8_t cpi_name[32]; /* copy of pr->ps_comm */ -}; - -/* - * FIXME - these _KERNEL items aren't part of the ABI! - */ -#if defined(_KERNEL) || defined(_DYN_LOADER) - -# define ELF32_NO_ADDR ((uint32_t)~0) /* Indicates addr. not yet filled in */ - -typedef struct { - Elf32_Sword au_id; /* 32-bit id */ - Elf32_Word au_v; /* 32-bit value */ -} Aux32Info; - -# define ELF64_NO_ADDR ((uint64_t)~0) /* Indicates addr. not yet filled in */ - -typedef struct { - Elf64_Shalf au_id; /* 32-bit id */ - Elf64_Xword au_v; /* 64-bit value */ -} Aux64Info; - -enum AuxID { - AUX_null = 0, - AUX_ignore = 1, - AUX_execfd = 2, - AUX_phdr = 3, /* &phdr[0] */ - AUX_phent = 4, /* sizeof(phdr[0]) */ - AUX_phnum = 5, /* # phdr entries */ - AUX_pagesz = 6, /* PAGESIZE */ - AUX_base = 7, /* ld.so base addr */ - AUX_flags = 8, /* processor flags */ - AUX_entry = 9, /* a.out entry */ - AUX_sun_uid = 2000, /* euid */ - AUX_sun_ruid = 2001, /* ruid */ - AUX_sun_gid = 2002, /* egid */ - AUX_sun_rgid = 2003 /* rgid */ -}; - -struct elf_args { - u_long arg_entry; /* program entry point */ - u_long arg_interp; /* Interpreter load address */ - u_long arg_phaddr; /* program header address */ - u_long arg_phentsize; /* Gfx::Size of program header */ - u_long arg_phnum; /* Number of program headers */ -}; - -#endif - -#if !defined(ELFSIZE) && defined(ARCH_ELFSIZE) -# define ELFSIZE ARCH_ELFSIZE -#endif - -#if defined(ELFSIZE) -# define CONCAT(x, y) __CONCAT(x, y) -# define ELFNAME(x) CONCAT(elf, CONCAT(ELFSIZE, CONCAT(_, x))) -# define ELFDEFNNAME(x) CONCAT(ELF, CONCAT(ELFSIZE, CONCAT(_, x))) -#endif - -#if defined(ELFSIZE) && (ELFSIZE == 32) -# define Elf_Ehdr Elf32_Ehdr -# define Elf_Phdr Elf32_Phdr -# define Elf_Shdr Elf32_Shdr -# define Elf_Sym Elf32_Sym -# define Elf_Rel Elf32_Rel -# define Elf_RelA Elf32_Rela -# define Elf_Rela Elf32_Rela -# define Elf_Relr Elf32_Relr -# define Elf_Dyn Elf32_Dyn -# define Elf_Half Elf32_Half -# define Elf_Word Elf32_Word -# define Elf_Sword Elf32_Sword -# define Elf_Addr Elf32_Addr -# define Elf_Off Elf32_Off -# define Elf_Nhdr Elf32_Nhdr -# define Elf_Note Elf32_Note - -# define ELF_R_SYM ELF32_R_SYM -# define ELF_R_TYPE ELF32_R_TYPE -# define ELF_R_INFO ELF32_R_INFO -# define ELFCLASS ELFCLASS32 - -# define ELF_ST_BIND ELF32_ST_BIND -# define ELF_ST_TYPE ELF32_ST_TYPE -# define ELF_ST_INFO ELF32_ST_INFO - -# define ELF_NO_ADDR ELF32_NO_ADDR -# define AuxInfo Aux32Info -#elif defined(ELFSIZE) && (ELFSIZE == 64) -# define Elf_Ehdr Elf64_Ehdr -# define Elf_Phdr Elf64_Phdr -# define Elf_Shdr Elf64_Shdr -# define Elf_Sym Elf64_Sym -# define Elf_Rel Elf64_Rel -# define Elf_RelA Elf64_Rela -# define Elf_Rela Elf64_Rela -# define Elf_Relr Elf64_Relr -# define Elf_Dyn Elf64_Dyn -# define Elf_Half Elf64_Half -# define Elf_Word Elf64_Word -# define Elf_Sword Elf64_Sword -# define Elf_Addr Elf64_Addr -# define Elf_Off Elf64_Off -# define Elf_Nhdr Elf64_Nhdr -# define Elf_Note Elf64_Note - -# define ELF_R_SYM ELF64_R_SYM -# define ELF_R_TYPE ELF64_R_TYPE -# define ELF_R_INFO ELF64_R_INFO -# define ELFCLASS ELFCLASS64 - -# define ELF_ST_BIND ELF64_ST_BIND -# define ELF_ST_TYPE ELF64_ST_TYPE -# define ELF_ST_INFO ELF64_ST_INFO - -# define ELF_NO_ADDR ELF64_NO_ADDR -# define AuxInfo Aux64Info -#endif - -#define ELF_TARG_VER 1 /* The ver for which this code is intended */ - -/* Relocation types */ -#define R_386_NONE 0 -#define R_386_32 1 /* Symbol + Addend */ -#define R_386_PC32 2 /* Symbol + Addend - Section offset */ -#define R_386_GOT32 3 /* Used by build-time linker to create GOT entry */ -#define R_386_PLT32 4 /* Used by build-time linker to create PLT entry */ -#define R_386_COPY 5 /* https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter4-10454.html#chapter4-84604 */ -#define R_386_GLOB_DAT 6 /* Relation b/w GOT entry and symbol */ -#define R_386_JMP_SLOT 7 /* Fixed up by dynamic loader */ -#define R_386_RELATIVE 8 /* Base address + Addned */ -#define R_386_TLS_TPOFF 14 /* Negative offset into the static TLS storage */ -#define R_386_TLS_TPOFF32 37 -#define R_386_IRELATIVE 42 /* PLT entry resolved indirectly at runtime */ - -#define R_X86_64_NONE 0 -#define R_X86_64_64 1 -#define R_X86_64_COPY 5 -#define R_X86_64_GLOB_DAT 6 -#define R_X86_64_JUMP_SLOT 7 -#define R_X86_64_RELATIVE 8 -#define R_X86_64_DTPMOD64 16 -#define R_X86_64_DTPOFF64 17 -#define R_X86_64_TPOFF64 18 -#define R_X86_64_TLSDESC 36 -#define R_X86_64_IRELATIVE 37 - -#define __ENUMERATE_X86_64_DYNAMIC_RELOCS(R) \ - R(R_X86_64_NONE) \ - R(R_X86_64_64) \ - R(R_X86_64_COPY) \ - R(R_X86_64_GLOB_DAT) \ - R(R_X86_64_JUMP_SLOT) \ - R(R_X86_64_RELATIVE) \ - R(R_X86_64_DTPMOD64) \ - R(R_X86_64_DTPOFF64) \ - R(R_X86_64_TPOFF64) \ - R(R_X86_64_TLSDESC) \ - R(R_X86_64_IRELATIVE) - -/* 5.7.12 Dynamic relocations https://github.com/ARM-software/abi-aa/blob/2023q1-release/aaelf64/aaelf64.rst#dynamic-relocations */ -#define R_AARCH64_NONE 0 -#define R_AARCH64_ABS64 257 -#define R_AARCH64_COPY 1024 -#define R_AARCH64_GLOB_DAT 1025 -#define R_AARCH64_JUMP_SLOT 1026 -#define R_AARCH64_RELATIVE 1027 -#define R_AARCH64_TLS_DTPMOD 1028 -#define R_AARCH64_TLS_DTPREL 1029 -#define R_AARCH64_TLS_TPREL 1030 -#define R_AARCH64_TLSDESC 1031 -#define R_AARCH64_IRELATIVE 1032 - -#define __ENUMERATE_AARCH64_DYNAMIC_RELOCS(R) \ - R(R_AARCH64_NONE) \ - R(R_AARCH64_ABS64) \ - R(R_AARCH64_COPY) \ - R(R_AARCH64_GLOB_DAT) \ - R(R_AARCH64_JUMP_SLOT) \ - R(R_AARCH64_RELATIVE) \ - R(R_AARCH64_TLS_DTPMOD) \ - R(R_AARCH64_TLS_DTPREL) \ - R(R_AARCH64_TLS_TPREL) \ - R(R_AARCH64_TLSDESC) \ - R(R_AARCH64_IRELATIVE) - -/* https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/v1.0/riscv-elf.adoc#relocations */ -#define R_RISCV_NONE 0 -#define R_RISCV_64 2 -#define R_RISCV_RELATIVE 3 -#define R_RISCV_COPY 4 -#define R_RISCV_JUMP_SLOT 5 -#define R_RISCV_TLS_DTPMOD64 7 -#define R_RISCV_TLS_DTPREL64 9 -#define R_RISCV_TLS_TPREL64 11 -#define R_RISCV_TLSDESC 12 -#define R_RISCV_IRELATIVE 58 - -#define __ENUMERATE_RISCV_DYNAMIC_RELOCS(R) \ - R(R_RISCV_NONE) \ - R(R_RISCV_64) \ - R(R_RISCV_RELATIVE) \ - R(R_RISCV_COPY) \ - R(R_RISCV_JUMP_SLOT) \ - R(R_RISCV_TLS_DTPMOD64) \ - R(R_RISCV_TLS_DTPREL64) \ - R(R_RISCV_TLS_TPREL64) \ - R(R_RISCV_TLSDESC) \ - R(R_RISCV_IRELATIVE) diff --git a/Userland/Libraries/LibELF/ELFBuild.cpp b/Userland/Libraries/LibELF/ELFBuild.cpp deleted file mode 100644 index 04724e8f52a..00000000000 --- a/Userland/Libraries/LibELF/ELFBuild.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2023, Jesús Lapastora - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -namespace ELF { - -SectionTable::Index StringTable::emit_into_builder(u32 name_index, SectionTable& builder) const noexcept -{ - return builder.append(emit_section(name_index)); -} - -Section StringTable::emit_section(u32 name_index) const noexcept -{ - Elf64_Shdr header {}; - header.sh_name = name_index; - header.sh_type = SHT_STRTAB; - header.sh_flags = 0; - header.sh_addr = 0; - header.sh_link = 0; - header.sh_info = 0; - header.sh_entsize = 0; - header.sh_addralign = 0; - return Section(m_data.span(), header); -} - -u32 StringTable::insert(StringView str) noexcept -{ - // The offsets for sh_name and st_name are 32-bit unsigned integers, so it - // won't make sense to address a string table bigger than what u32 can - // provide. - VERIFY(m_data.size() < NumericLimits::max()); - auto const offset = static_cast(m_data.size()); - - auto const final_size = m_data.size() + str.length() + 1; - VERIFY(final_size < NumericLimits::max()); - - m_data.ensure_capacity(m_data.size() + str.length() + 1); - - for (auto ch : str) { - VERIFY(ch != 0); - m_data.unchecked_append(ch); - } - m_data.append(0); - return offset; -} - -FixedArray build_elf_image(u64 shstrndx, Elf64_Quarter image_type, ReadonlySpan
    sections) -{ - Checked final_image_size = sizeof(Elf64_Ehdr); - Vector section_offsets; - section_offsets.ensure_capacity(sections.size()); - - auto const sections_begin = final_image_size.value_unchecked(); - final_image_size += sizeof(Elf64_Shdr) * sections.size(); - - for (auto const& section : sections) { - auto const offset = final_image_size.value(); - section_offsets.unchecked_append(offset); - if (section.data.has_value()) { - final_image_size += section.data.value().size(); - } - } - - auto image = MUST(FixedArray::create(final_image_size.value())); - - { - auto section_headers = Span { - reinterpret_cast(image.span().offset_pointer(sections_begin)), - sections.size(), - }; - for (size_t i = 0; i < sections.size(); ++i) { - section_headers[i] = sections[i].header; - section_headers[i].sh_offset = section_offsets[i]; - if (sections[i].data.has_value()) { - auto const data = sections[i].data.value(); - auto const data_in_elf = image.span().slice(section_offsets[i], data.size()); - data.copy_to(data_in_elf); - section_headers[i].sh_size = data.size(); - } - } - } - - { - auto* const final_elf_hdr = reinterpret_cast(image.data()); - final_elf_hdr->e_ident[EI_MAG0] = 0x7f; - final_elf_hdr->e_ident[EI_MAG1] = 'E'; - final_elf_hdr->e_ident[EI_MAG2] = 'L'; - final_elf_hdr->e_ident[EI_MAG3] = 'F'; - final_elf_hdr->e_ident[EI_CLASS] = ELFCLASS64; - // FIXME: This is platform-dependent. Any big-endian host will write the - // data in MSB format, so the EI_DATA field should be set to - // ELFDATA2MSB. - final_elf_hdr->e_ident[EI_DATA] = ELFDATA2LSB; - final_elf_hdr->e_ident[EI_VERSION] = EV_CURRENT; - // FIXME: This is platform-dependent. The host must set the OSABI to the - // one of the image target. - final_elf_hdr->e_ident[EI_OSABI] = ELFOSABI_SYSV; - final_elf_hdr->e_ident[EI_ABIVERSION] = 0; - auto padding = Bytes { - &final_elf_hdr->e_ident[EI_PAD], - EI_NIDENT - EI_PAD, - }; - padding.fill(0); - - final_elf_hdr->e_type = image_type; - // FIXME: This is platform-dependent. This must be set to the host - // architecture. - final_elf_hdr->e_machine = EM_AMD64; - final_elf_hdr->e_version = EV_CURRENT; - - // Currently segments aren't supported, hence no program headers. - // FIXME: Update program header info on ELF header when adding segment - // information. - final_elf_hdr->e_phoff = 0; - final_elf_hdr->e_phnum = 0; - final_elf_hdr->e_phentsize = 0; - - final_elf_hdr->e_shoff = sections_begin; - final_elf_hdr->e_shnum = sections.size(); - final_elf_hdr->e_shentsize = sizeof(Section::header); - - // FIXME: This is platform-dependent. The flags field should be in sync - // with the architecture flags assumed in the code sections, otherwise - // instructions may be misinterpreted. - final_elf_hdr->e_flags = 0; - - final_elf_hdr->e_ehsize = sizeof(*final_elf_hdr); - final_elf_hdr->e_shstrndx = shstrndx; - } - - return image; -} -}; diff --git a/Userland/Libraries/LibELF/ELFBuild.h b/Userland/Libraries/LibELF/ELFBuild.h deleted file mode 100644 index b5f16c6b0ac..00000000000 --- a/Userland/Libraries/LibELF/ELFBuild.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2023, Jesús Lapastora - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -// Collection of utilities to produce an in-memory ELF file in the same format -// as the host. - -#include -#include -#include -#include - -namespace ELF { - -// Represents an ELF Section that is optionally bound to some data. -struct Section { - Elf64_Shdr header; - Optional data {}; - - explicit Section(Elf64_Shdr header) - : header(header) - { - } - Section(ReadonlyBytes data, Elf64_Shdr header) - : header(header) - , data(data) - { - } -}; - -// Receives a list of sections, and writes the following layout: -//
    -// -// Both the section headers & the data for those sections will be written in the -// exact order as they appear in the list. -// If a `Section` contains data, then its `sh_offset` is set to the offset in -// the final image, and `sh_size` to the size of the specified data. `Section`s -// that do not contain data will have their `sh_offset` set to the end offset of -// the section that comes right before them. -// -// Notes on the ELF Header: -// The elf header is mostly filled by this function. It needs help in a couple -// of fields: `e_shstrndx` and `e_type`. -// -// - `shstrndx` is the index of the `Section` that contains the section name -// string table. -// - `image_type` is the image file type: ET_CORE, ET_REL, ET_EXEC, etc. -FixedArray build_elf_image(u64 shstrndx, Elf64_Quarter image_type, ReadonlySpan
    sections); - -// Takes care of tracking section header indices and their order -struct SectionTable { - - struct Index { - u64 index; - - constexpr explicit Index(u64 index) - : index(index) - { - } - - constexpr u64 raw_index() const noexcept { return index; } - }; - - ReadonlySpan
    span() const noexcept { return m_sections.span(); } - - // Appends a default-intialized header with no data. The client is - // responsible for initializing the header before producing the final image. - Index reserve() noexcept - { - return append(Section(Elf64_Shdr())); - } - - // Appends a Section and returns the index to refer to it. - Index append(Section section) noexcept - { - auto const index = m_sections.size(); - m_sections.append(move(section)); - return Index(index); - } - template - Index empend(Args&&... args) noexcept - { - auto const index = m_sections.size(); - m_sections.empend(forward(args)...); - return Index(index); - } - - // Calls `header_builder` with a reference to the Section header, so that - // the builder can initialize it. - // Returns the index for the section. - template - Index build_nobits(Builder header_builder) - { - auto index = reserve(); - build_nobits_at(index, move(header_builder)); - return index; - } - - // Creates a null section header. Useful for avoiding index 0 for the text - // section, since if we use 0 for its index then symbols that relate to - // .text will be misinterpreted as related to an 'undefined' section. - Index build_null() - { - Elf64_Shdr header {}; - header.sh_type = SHT_NULL; - header.sh_name = 0; - return empend(header); - } - - // Same as `build_nobits`, but writes an already reserved header instead of - // creating a new one. - template - void build_nobits_at(Index at, Builder header_builder) - { - Elf64_Shdr header {}; - header.sh_type = SHT_NOBITS; - header_builder(header); - new (&m_sections[at.raw_index()]) Section(header); - } - - // Reinterprets `typed_data` as a byte slice, and calls `header_builder` - // with a reference to the Section header to be initialized. - // Sets the header's `sh_entsize` to `sizeof(T)` before calling the builder, - // so it can be overridden if required. - // Returns the index for the section. - template - Index build(ReadonlySpan typed_data, Builder header_builder) - { - auto index = reserve(); - build_at(index, move(typed_data), move(header_builder)); - return index; - } - - // Same as `build`, but writes an already reserved header instead of - // creating a new one. - template - void build_at(Index at, ReadonlySpan typed_data, Builder header_builder) - { - Elf64_Shdr header {}; - header.sh_entsize = sizeof(T); - header_builder(static_cast(header)); - ReadonlyBytes data = ReadonlyBytes { - reinterpret_cast(typed_data.offset(0)), - typed_data.size() * sizeof(T), - }; - new (&m_sections[at.raw_index()]) Section(data, header); - } - - // Makes header editing available after construction. The reference is valid - // until another header is added. - Elf64_Shdr& header_at(Index index) noexcept { return m_sections[index.raw_index()].header; } - -private: - Vector
    m_sections; -}; - -struct StringTable { - // Inserts the given string into the table, giving back the offset it begins - // at. The string must not contain any zeroes. - u32 insert(StringView str) noexcept; - - // Emits the section information for the current state, so that it can be - // merged into an ELF image. - Section emit_section(u32 name_index) const noexcept; - - // Like `emit_section`, but writes the section directly into the builder. - // Returns the index for the section. - SectionTable::Index emit_into_builder(u32 name_index, SectionTable& builder) const noexcept; - -private: - Vector m_data; -}; - -}; diff --git a/Userland/Libraries/LibELF/Hashes.h b/Userland/Libraries/LibELF/Hashes.h deleted file mode 100644 index 0fbbfea7eda..00000000000 --- a/Userland/Libraries/LibELF/Hashes.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2019-2020, Andrew Kaster - * Copyright (c) 2020, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace ELF { - -constexpr u32 compute_sysv_hash(StringView name) -{ - // SYSV ELF hash algorithm - // Note that the GNU HASH algorithm has less collisions - - u32 hash = 0; - - for (auto ch : name) { - hash = hash << 4; - hash += ch; - - u32 const top_nibble_of_hash = hash & 0xf0000000u; - hash ^= top_nibble_of_hash >> 24; - hash &= ~top_nibble_of_hash; - } - - return hash; -} - -constexpr u32 compute_gnu_hash(StringView name) -{ - // GNU ELF hash algorithm - u32 hash = 5381; - - for (auto ch : name) - hash = hash * 33 + ch; - - return hash; -} - -} diff --git a/Userland/Libraries/LibELF/Image.cpp b/Userland/Libraries/LibELF/Image.cpp deleted file mode 100644 index fa71e01e12b..00000000000 --- a/Userland/Libraries/LibELF/Image.cpp +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright (c) 2018-2021, Andreas Kling - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef KERNEL -# include -#else -# include -#endif - -namespace ELF { - -Image::Image(ReadonlyBytes bytes, bool verbose_logging) - : m_buffer(bytes.data()) - , m_size(bytes.size()) - , m_verbose_logging(verbose_logging) -{ - parse(); -} - -Image::Image(u8 const* buffer, size_t size, bool verbose_logging) - : Image(ReadonlyBytes { buffer, size }, verbose_logging) -{ -} - -StringView Image::section_index_to_string(unsigned index) const -{ - VERIFY(m_valid); - if (index == SHN_UNDEF) - return "Undefined"sv; - if (index >= SHN_LORESERVE) - return "Reserved"sv; - return section(index).name(); -} - -unsigned Image::symbol_count() const -{ - VERIFY(m_valid); - if (!section_count()) - return 0; - return section(m_symbol_table_section_index).entry_count(); -} - -void Image::dump() const -{ -#if ELF_IMAGE_DEBUG - dbgln("ELF::Image({:p}) {{", this); - dbgln(" is_valid: {}", is_valid()); - - if (!is_valid()) { - dbgln("}}"); - return; - } - - dbgln(" type: {}", ELF::Image::object_file_type_to_string(header().e_type).value_or("(?)"sv)); - dbgln(" machine: {}", header().e_machine); - dbgln(" entry: {:x}", header().e_entry); - dbgln(" shoff: {}", header().e_shoff); - dbgln(" shnum: {}", header().e_shnum); - dbgln(" phoff: {}", header().e_phoff); - dbgln(" phnum: {}", header().e_phnum); - dbgln(" shstrndx: {}", header().e_shstrndx); - - for_each_program_header([&](ProgramHeader const& program_header) { - dbgln(" Program Header {}: {{", program_header.index()); - dbgln(" type: {:x}", program_header.type()); - dbgln(" offset: {:x}", program_header.offset()); - dbgln(" flags: {:x}", program_header.flags()); - dbgln(" }}"); - }); - - for (unsigned i = 0; i < header().e_shnum; ++i) { - auto const& section = this->section(i); - dbgln(" Section {}: {{", i); - dbgln(" name: {}", section.name()); - dbgln(" type: {:x}", section.type()); - dbgln(" offset: {:x}", section.offset()); - dbgln(" size: {}", section.size()); - dbgln(" "); - dbgln(" }}"); - } - - dbgln("Symbol count: {} (table is {})", symbol_count(), m_symbol_table_section_index); - for (unsigned i = 1; i < symbol_count(); ++i) { - auto const& sym = symbol(i); - dbgln("Symbol @{}:", i); - dbgln(" Name: {}", sym.name()); - dbgln(" In section: {}", section_index_to_string(sym.section_index())); - dbgln(" Value: {}", sym.value()); - dbgln(" Size: {}", sym.size()); - } - - dbgln("}}"); -#endif -} - -unsigned Image::section_count() const -{ - VERIFY(m_valid); - return header().e_shnum; -} - -unsigned Image::program_header_count() const -{ - VERIFY(m_valid); - return header().e_phnum; -} - -bool Image::parse() -{ - if (m_size < sizeof(Elf_Ehdr) || !validate_elf_header(header(), m_size, m_verbose_logging)) { - if (m_verbose_logging) - dbgln("ELF::Image::parse(): ELF Header not valid"); - m_valid = false; - return false; - } - - auto result_or_error = validate_program_headers(header(), m_size, { m_buffer, m_size }, nullptr, nullptr, m_verbose_logging); - if (result_or_error.is_error()) { - if (m_verbose_logging) - dbgln("ELF::Image::parse(): Failed validating ELF Program Headers"); - m_valid = false; - return false; - } - if (!result_or_error.value()) { - if (m_verbose_logging) - dbgln("ELF::Image::parse(): ELF Program Headers not valid"); - m_valid = false; - return false; - } - - m_valid = true; - - // First locate the string tables. - for (unsigned i = 0; i < section_count(); ++i) { - auto& sh = section_header(i); - if (sh.sh_type == SHT_SYMTAB) { - if (m_symbol_table_section_index && m_symbol_table_section_index != i) { - m_valid = false; - return false; - } - m_symbol_table_section_index = i; - } - if (sh.sh_type == SHT_STRTAB && i != header().e_shstrndx) { - if (section_header_table_string(sh.sh_name) == ELF_STRTAB) - m_string_table_section_index = i; - } - } - - return m_valid; -} - -StringView Image::table_string(unsigned table_index, unsigned offset) const -{ - VERIFY(m_valid); - auto& sh = section_header(table_index); - if (sh.sh_type != SHT_STRTAB) - return {}; - size_t computed_offset = sh.sh_offset + offset; - if (computed_offset >= m_size) { - if (m_verbose_logging) - dbgln("SHENANIGANS! Image::table_string() computed offset outside image."); - return {}; - } - size_t max_length = min(m_size - computed_offset, (size_t)PAGE_SIZE); - size_t length = strnlen(raw_data(sh.sh_offset + offset), max_length); - return { raw_data(sh.sh_offset + offset), length }; -} - -StringView Image::section_header_table_string(unsigned offset) const -{ - VERIFY(m_valid); - return table_string(header().e_shstrndx, offset); -} - -StringView Image::table_string(unsigned offset) const -{ - VERIFY(m_valid); - return table_string(m_string_table_section_index, offset); -} - -char const* Image::raw_data(unsigned offset) const -{ - VERIFY(offset < m_size); // Callers must check indices into raw_data()'s result are also in bounds. - return reinterpret_cast(m_buffer) + offset; -} - -Elf_Ehdr const& Image::header() const -{ - VERIFY(m_size >= sizeof(Elf_Ehdr)); - return *reinterpret_cast(raw_data(0)); -} - -Elf_Phdr const& Image::program_header_internal(unsigned index) const -{ - VERIFY(m_valid); - VERIFY(index < header().e_phnum); - return *reinterpret_cast(raw_data(header().e_phoff + (index * sizeof(Elf_Phdr)))); -} - -Elf_Shdr const& Image::section_header(unsigned index) const -{ - VERIFY(m_valid); - VERIFY(index < header().e_shnum); - return *reinterpret_cast(raw_data(header().e_shoff + (index * header().e_shentsize))); -} - -Image::Symbol Image::symbol(unsigned index) const -{ - VERIFY(m_valid); - VERIFY(index < symbol_count()); - auto* raw_syms = reinterpret_cast(raw_data(section(m_symbol_table_section_index).offset())); - return Symbol(*this, index, raw_syms[index]); -} - -Image::Section Image::section(unsigned index) const -{ - VERIFY(m_valid); - VERIFY(index < section_count()); - return Section(*this, index); -} - -Image::ProgramHeader Image::program_header(unsigned index) const -{ - VERIFY(m_valid); - VERIFY(index < program_header_count()); - return ProgramHeader(*this, index); -} - -Image::Relocation Image::RelocationSection::relocation(unsigned index) const -{ - VERIFY(index < relocation_count()); - auto* rels = reinterpret_cast(m_image.raw_data(offset())); - return Relocation(m_image, rels[index]); -} - -Optional Image::Section::relocations() const -{ - StringBuilder builder; - builder.append(".rel"sv); - builder.append(name()); - - auto relocation_section = m_image.lookup_section(builder.string_view()); - if (!relocation_section.has_value()) - return {}; - - dbgln_if(ELF_IMAGE_DEBUG, "Found relocations for {} in {}", name(), relocation_section.value().name()); - return static_cast(relocation_section.value()); -} - -Optional Image::lookup_section(StringView name) const -{ - VERIFY(m_valid); - for (unsigned i = 0; i < section_count(); ++i) { - auto section = this->section(i); - if (section.name() == name) - return section; - } - return {}; -} - -Optional Image::object_file_type_to_string(Elf_Half type) -{ - switch (type) { - case ET_NONE: - return "None"sv; - case ET_REL: - return "Relocatable"sv; - case ET_EXEC: - return "Executable"sv; - case ET_DYN: - return "Shared object"sv; - case ET_CORE: - return "Core"sv; - default: - return {}; - } -} - -Optional Image::object_machine_type_to_string(Elf_Half type) -{ - switch (type) { - case ET_NONE: - return "None"sv; - case EM_M32: - return "AT&T WE 32100"sv; - case EM_SPARC: - return "SPARC"sv; - case EM_386: - return "Intel 80386"sv; - case EM_68K: - return "Motorola 68000"sv; - case EM_88K: - return "Motorola 88000"sv; - case EM_486: - return "Intel 80486"sv; - case EM_860: - return "Intel 80860"sv; - case EM_MIPS: - return "MIPS R3000 Big-Endian only"sv; - case EM_X86_64: - return "x86_64"sv; - default: - return {}; - } -} - -Optional Image::object_abi_type_to_string(Elf_Byte type) -{ - switch (type) { - case ELFOSABI_SYSV: - return "SYSV"sv; - case ELFOSABI_HPUX: - return "HP-UX"sv; - case ELFOSABI_NETBSD: - return "NetBSD"sv; - case ELFOSABI_LINUX: - return "Linux"sv; - case ELFOSABI_HURD: - return "GNU Hurd"sv; - case ELFOSABI_86OPEN: - return "86Open"sv; - case ELFOSABI_SOLARIS: - return "Solaris"sv; - case ELFOSABI_MONTEREY: - return "AIX"sv; - case ELFOSABI_IRIX: - return "IRIX"sv; - case ELFOSABI_FREEBSD: - return "FreeBSD"sv; - case ELFOSABI_TRU64: - return "Tru64"sv; - case ELFOSABI_MODESTO: - return "Novell Modesto"sv; - case ELFOSABI_OPENBSD: - return "OpenBSD"sv; - case ELFOSABI_ARM: - return "ARM"sv; - case ELFOSABI_STANDALONE: - return "Standalone"sv; - default: - return {}; - } -} - -StringView Image::Symbol::raw_data() const -{ - auto section = this->section(); - return { section.raw_data() + (value() - section.address()), size() }; -} - -#ifndef KERNEL -Optional Image::find_demangled_function(StringView name) const -{ - Optional found; - for_each_symbol([&](Image::Symbol const& symbol) { - if (symbol.type() != STT_FUNC && symbol.type() != STT_GNU_IFUNC) - return IterationDecision::Continue; - if (symbol.is_undefined()) - return IterationDecision::Continue; - auto demangled = demangle(symbol.name()); - auto index_of_paren = demangled.find('('); - if (index_of_paren.has_value()) { - demangled = demangled.substring(0, index_of_paren.value()); - } - if (demangled != name) - return IterationDecision::Continue; - found = symbol; - return IterationDecision::Break; - }); - return found; -} - -Image::SortedSymbol* Image::find_sorted_symbol(FlatPtr address) const -{ - if (m_sorted_symbols.is_empty()) - sort_symbols(); - - size_t index = 0; - binary_search(m_sorted_symbols, nullptr, &index, [&address](auto, auto& candidate) { - if (address < candidate.address) - return -1; - else if (address > candidate.address) - return 1; - else - return 0; - }); - // FIXME: The error path here feels strange, index == 0 means error but what about symbol #0? - if (index == 0) - return nullptr; - return &m_sorted_symbols[index]; -} - -Optional Image::find_symbol(FlatPtr address, u32* out_offset) const -{ - auto symbol_count = this->symbol_count(); - if (!symbol_count) - return {}; - - auto* symbol = find_sorted_symbol(address); - if (!symbol) - return {}; - if (out_offset) - *out_offset = address - symbol->address; - return symbol->symbol; -} - -NEVER_INLINE void Image::sort_symbols() const -{ - m_sorted_symbols.ensure_capacity(symbol_count()); - bool const is_aarch64_or_riscv = header().e_machine == EM_AARCH64 || header().e_machine == EM_RISCV; - for_each_symbol([this, is_aarch64_or_riscv](auto const& symbol) { - // The AArch64 and RISC-V ABIs mark the boundaries of literal pools in a function with $x/$d. - // https://github.com/ARM-software/abi-aa/blob/2023q1-release/aaelf64/aaelf64.rst#mapping-symbols - // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#mapping-symbol - // Skip them so we don't accidentally print these instead of function names. - if (is_aarch64_or_riscv && (symbol.name().starts_with("$x"sv) || symbol.name().starts_with("$d"sv))) - return; - // STT_SECTION has the same address as the first function in the section, but shows up as the empty string. - if (symbol.type() == STT_SECTION) - return; - m_sorted_symbols.append({ symbol.value(), symbol.name(), {}, symbol }); - }); - quick_sort(m_sorted_symbols, [](auto& a, auto& b) { - return a.address < b.address; - }); -} - -ByteString Image::symbolicate(FlatPtr address, u32* out_offset) const -{ - auto symbol_count = this->symbol_count(); - if (!symbol_count) { - if (out_offset) - *out_offset = 0; - return "??"; - } - - auto* symbol = find_sorted_symbol(address); - if (!symbol) { - if (out_offset) - *out_offset = 0; - return "??"; - } - - auto& demangled_name = symbol->demangled_name; - if (demangled_name.is_empty()) - demangled_name = demangle(symbol->name); - - if (out_offset) { - *out_offset = address - symbol->address; - return demangled_name; - } - return ByteString::formatted("{} +{:#x}", demangled_name, address - symbol->address); -} -#endif - -} // end namespace ELF diff --git a/Userland/Libraries/LibELF/Image.h b/Userland/Libraries/LibELF/Image.h deleted file mode 100644 index fcd3c5248c4..00000000000 --- a/Userland/Libraries/LibELF/Image.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -#ifndef KERNEL -# include -#endif - -namespace ELF { - -class Image { -public: - explicit Image(ReadonlyBytes, bool verbose_logging = true); - explicit Image(u8 const*, size_t, bool verbose_logging = true); - - ~Image() = default; - void dump() const; - bool is_valid() const { return m_valid; } - bool parse(); - - bool is_within_image(void const* address, size_t size) const - { - if (address < m_buffer) - return false; - if (((u8 const*)address + size) > m_buffer + m_size) - return false; - return true; - } - - class Section; - class RelocationSection; - class Symbol; - class Relocation; - - class Symbol { - public: - Symbol(Image const& image, unsigned index, Elf_Sym const& sym) - : m_image(image) - , m_sym(sym) - , m_index(index) - { - } - - ~Symbol() = default; - - StringView name() const { return m_image.table_string(m_sym.st_name); } - unsigned section_index() const { return m_sym.st_shndx; } - FlatPtr value() const { return m_sym.st_value; } - size_t size() const { return m_sym.st_size; } - unsigned index() const { return m_index; } - unsigned type() const - { - return ELF64_ST_TYPE(m_sym.st_info); - } - unsigned bind() const { return ELF64_ST_BIND(m_sym.st_info); } - Section section() const - { - return m_image.section(section_index()); - } - bool is_undefined() const { return section_index() == 0; } - StringView raw_data() const; - - private: - Image const& m_image; - Elf_Sym const& m_sym; - unsigned const m_index; - }; - - class ProgramHeader { - public: - ProgramHeader(Image const& image, unsigned program_header_index) - : m_image(image) - , m_program_header(image.program_header_internal(program_header_index)) - , m_program_header_index(program_header_index) - { - } - ~ProgramHeader() = default; - - unsigned index() const { return m_program_header_index; } - u32 type() const { return m_program_header.p_type; } - u32 flags() const { return m_program_header.p_flags; } - size_t offset() const { return m_program_header.p_offset; } - VirtualAddress vaddr() const { return VirtualAddress(m_program_header.p_vaddr); } - size_t size_in_memory() const { return m_program_header.p_memsz; } - size_t size_in_image() const { return m_program_header.p_filesz; } - size_t alignment() const { return m_program_header.p_align; } - bool is_readable() const { return flags() & PF_R; } - bool is_writable() const { return flags() & PF_W; } - bool is_executable() const { return flags() & PF_X; } - char const* raw_data() const { return m_image.raw_data(m_program_header.p_offset); } - Elf_Phdr raw_header() const { return m_program_header; } - - private: - Image const& m_image; - Elf_Phdr const& m_program_header; - unsigned m_program_header_index { 0 }; - }; - - class Section { - public: - Section(Image const& image, unsigned sectionIndex) - : m_image(image) - , m_section_header(image.section_header(sectionIndex)) - , m_section_index(sectionIndex) - { - } - ~Section() = default; - - StringView name() const { return m_image.section_header_table_string(m_section_header.sh_name); } - u32 type() const { return m_section_header.sh_type; } - size_t offset() const { return m_section_header.sh_offset; } - size_t size() const { return m_section_header.sh_size; } - size_t entry_size() const { return m_section_header.sh_entsize; } - size_t entry_count() const { return !entry_size() ? 0 : size() / entry_size(); } - FlatPtr address() const { return m_section_header.sh_addr; } - char const* raw_data() const { return m_image.raw_data(m_section_header.sh_offset); } - ReadonlyBytes bytes() const { return { raw_data(), size() }; } - Optional relocations() const; - auto flags() const { return m_section_header.sh_flags; } - bool is_writable() const { return flags() & SHF_WRITE; } - bool is_executable() const { return flags() & PF_X; } - - protected: - friend class RelocationSection; - Image const& m_image; - Elf_Shdr const& m_section_header; - unsigned m_section_index; - }; - - class RelocationSection : public Section { - public: - explicit RelocationSection(Section const& section) - : Section(section.m_image, section.m_section_index) - { - } - size_t relocation_count() const { return entry_count(); } - Relocation relocation(unsigned index) const; - - template F> - void for_each_relocation(F) const; - }; - - class Relocation { - public: - Relocation(Image const& image, Elf_Rel const& rel) - : m_image(image) - , m_rel(rel) - { - } - - ~Relocation() = default; - - size_t offset() const { return m_rel.r_offset; } - unsigned type() const - { - return ELF64_R_TYPE(m_rel.r_info); - } - unsigned symbol_index() const { return ELF64_R_SYM(m_rel.r_info); } - Symbol symbol() const - { - return m_image.symbol(symbol_index()); - } - - private: - Image const& m_image; - Elf_Rel const& m_rel; - }; - - unsigned symbol_count() const; - unsigned section_count() const; - unsigned program_header_count() const; - - Symbol symbol(unsigned) const; - Section section(unsigned) const; - ProgramHeader program_header(unsigned) const; - - template F> - void for_each_section(F) const; - template F> - void for_each_section(F) const; - - template F> - void for_each_section_of_type(unsigned, F) const; - template F> - void for_each_section_of_type(unsigned, F) const; - - template F> - void for_each_symbol(F) const; - template F> - void for_each_symbol(F) const; - - template F> - void for_each_program_header(F func) const; - template F> - void for_each_program_header(F) const; - - Optional
    lookup_section(StringView name) const; - - bool is_executable() const { return header().e_type == ET_EXEC; } - bool is_relocatable() const { return header().e_type == ET_REL; } - bool is_dynamic() const { return header().e_type == ET_DYN; } - - VirtualAddress entry() const { return VirtualAddress(header().e_entry); } - FlatPtr base_address() const { return (FlatPtr)m_buffer; } - size_t size() const { return m_size; } - - static Optional object_file_type_to_string(Elf_Half type); - static Optional object_machine_type_to_string(Elf_Half type); - static Optional object_abi_type_to_string(Elf_Byte type); - - bool has_symbols() const { return symbol_count(); } -#ifndef KERNEL - Optional find_demangled_function(StringView name) const; - ByteString symbolicate(FlatPtr address, u32* offset = nullptr) const; -#endif - Optional find_symbol(FlatPtr address, u32* offset = nullptr) const; - -private: - char const* raw_data(unsigned offset) const; - Elf_Ehdr const& header() const; - Elf_Shdr const& section_header(unsigned) const; - Elf_Phdr const& program_header_internal(unsigned) const; - StringView table_string(unsigned offset) const; - StringView section_header_table_string(unsigned offset) const; - StringView section_index_to_string(unsigned index) const; - StringView table_string(unsigned table_index, unsigned offset) const; - - u8 const* m_buffer { nullptr }; - size_t m_size { 0 }; - bool m_verbose_logging { true }; - bool m_valid { false }; - unsigned m_symbol_table_section_index { 0 }; - unsigned m_string_table_section_index { 0 }; - -#ifndef KERNEL - struct SortedSymbol { - FlatPtr address; - StringView name; - ByteString demangled_name; - Optional symbol; - }; - - void sort_symbols() const; - SortedSymbol* find_sorted_symbol(FlatPtr) const; - - mutable Vector m_sorted_symbols; -#endif -}; - -template F> -inline void Image::for_each_section(F func) const -{ - auto section_count = this->section_count(); - for (unsigned i = 0; i < section_count; ++i) { - if (func(section(i)) == IterationDecision::Break) - break; - } -} - -template F> -inline void Image::for_each_section(F func) const -{ - for_each_section([&](auto section) { - func(move(section)); - return IterationDecision::Continue; - }); -} - -template F> -inline void Image::for_each_section_of_type(unsigned type, F func) const -{ - auto section_count = this->section_count(); - for (unsigned i = 0; i < section_count; ++i) { - auto section = this->section(i); - if (section.type() == type) { - if (func(section) == IterationDecision::Break) - break; - } - } -} - -template F> -inline void Image::for_each_section_of_type(unsigned type, F func) const -{ - for_each_section_of_type(type, [&](auto& section) { - func(section); - return IterationDecision::Continue; - }); -} - -template F> -inline void Image::RelocationSection::for_each_relocation(F func) const -{ - auto relocation_count = this->relocation_count(); - for (unsigned i = 0; i < relocation_count; ++i) { - func(relocation(i)); - } -} - -template F> -inline void Image::for_each_symbol(F func) const -{ - auto symbol_count = this->symbol_count(); - for (unsigned i = 0; i < symbol_count; ++i) { - if (func(symbol(i)) == IterationDecision::Break) - break; - } -} - -template F> -inline void Image::for_each_symbol(F func) const -{ - for_each_symbol([&](auto symbol) { - func(move(symbol)); - return IterationDecision::Continue; - }); -} - -template F> -inline void Image::for_each_program_header(F func) const -{ - auto program_header_count = this->program_header_count(); - for (unsigned i = 0; i < program_header_count; ++i) { - if (func(program_header(i)) == IterationDecision::Break) - break; - } -} - -template F> -inline void Image::for_each_program_header(F func) const -{ - for_each_program_header([&](auto header) { - func(move(header)); - return IterationDecision::Continue; - }); -} - -} // end namespace ELF diff --git a/Userland/Libraries/LibELF/Relocation.cpp b/Userland/Libraries/LibELF/Relocation.cpp deleted file mode 100644 index b1a2380ccf8..00000000000 --- a/Userland/Libraries/LibELF/Relocation.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2021, Gunnar Beutner - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace ELF { - -[[gnu::no_stack_protector]] bool perform_relative_relocations(FlatPtr base_address) -{ - Elf_Ehdr* header = (Elf_Ehdr*)(base_address); - Elf_Phdr* pheader = (Elf_Phdr*)(base_address + header->e_phoff); - FlatPtr dynamic_section_addr = 0; - for (size_t i = 0; i < (size_t)header->e_phnum; ++i, ++pheader) { - if (pheader->p_type != PT_DYNAMIC) - continue; - dynamic_section_addr = pheader->p_vaddr + base_address; - } - if (!dynamic_section_addr) - return false; - - FlatPtr relocation_section_addr = 0; - size_t relocation_table_size = 0; - size_t relocation_count = 0; - size_t relocation_entry_size = 0; - FlatPtr relr_relocation_section_addr = 0; - size_t relr_relocation_table_size = 0; - bool use_addend = false; - auto* dyns = reinterpret_cast(dynamic_section_addr); - for (unsigned i = 0;; ++i) { - auto& dyn = dyns[i]; - if (dyn.d_tag == DT_NULL) - break; - if (dyn.d_tag == DT_RELA) - use_addend = true; - if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELA) - relocation_section_addr = base_address + dyn.d_un.d_ptr; - else if (dyn.d_tag == DT_RELCOUNT || dyn.d_tag == DT_RELACOUNT) - relocation_count = dyn.d_un.d_val; - else if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ) - relocation_table_size = dyn.d_un.d_val; - else if (dyn.d_tag == DT_RELENT || dyn.d_tag == DT_RELAENT) - relocation_entry_size = dyn.d_un.d_val; - else if (dyn.d_tag == DT_RELR) - relr_relocation_section_addr = base_address + dyn.d_un.d_ptr; - else if (dyn.d_tag == DT_RELRSZ) - relr_relocation_table_size = dyn.d_un.d_val; - else if (dyn.d_tag == DT_RELRENT) - VERIFY(dyn.d_un.d_val == sizeof(FlatPtr)); - } - - if ((!relocation_section_addr || !relocation_table_size || !relocation_count) && (!relr_relocation_section_addr || !relr_relocation_table_size)) - return false; - - for (unsigned i = 0; i < relocation_count; ++i) { - size_t offset_in_section = i * relocation_entry_size; - auto* relocation = (Elf_Rela*)(relocation_section_addr + offset_in_section); - VERIFY(static_cast(ELF64_R_TYPE(relocation->r_info)) == GenericDynamicRelocationType::RELATIVE); - auto* patch_address = (FlatPtr*)(base_address + relocation->r_offset); - FlatPtr relocated_address; - if (use_addend) { - relocated_address = base_address + relocation->r_addend; - } else { - __builtin_memcpy(&relocated_address, patch_address, sizeof(relocated_address)); - relocated_address += base_address; - } - __builtin_memcpy(patch_address, &relocated_address, sizeof(relocated_address)); - } - - auto patch_relr = [base_address](FlatPtr* patch_ptr) { - FlatPtr relocated_address; - __builtin_memcpy(&relocated_address, patch_ptr, sizeof(FlatPtr)); - relocated_address += base_address; - __builtin_memcpy(patch_ptr, &relocated_address, sizeof(FlatPtr)); - }; - - auto* entries = reinterpret_cast(relr_relocation_section_addr); - FlatPtr* patch_ptr = nullptr; - - for (unsigned i = 0; i < relr_relocation_table_size / sizeof(FlatPtr); ++i) { - if ((entries[i] & 1u) == 0) { - patch_ptr = reinterpret_cast(base_address + entries[i]); - patch_relr(patch_ptr); - ++patch_ptr; - } else { - unsigned j = 0; - for (auto bitmap = entries[i]; (bitmap >>= 1u) != 0; ++j) - if (bitmap & 1u) - patch_relr(patch_ptr + j); - - patch_ptr += 8 * sizeof(FlatPtr) - 1; - } - } - return true; -} -} diff --git a/Userland/Libraries/LibELF/Relocation.h b/Userland/Libraries/LibELF/Relocation.h deleted file mode 100644 index a00b1b7029c..00000000000 --- a/Userland/Libraries/LibELF/Relocation.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2021, Gunnar Beutner - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace ELF { - -bool perform_relative_relocations(FlatPtr base_address); - -} diff --git a/Userland/Libraries/LibELF/Validation.cpp b/Userland/Libraries/LibELF/Validation.cpp deleted file mode 100644 index b05678d83d5..00000000000 --- a/Userland/Libraries/LibELF/Validation.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (c) 2020, Andrew Kaster - * Copyright (c) 2021, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include - -#ifndef KERNEL -# include -# include -#endif - -namespace ELF { - -bool validate_elf_header(Elf_Ehdr const& elf_header, size_t file_size, bool verbose) -{ - if (!IS_ELF(elf_header)) { - if (verbose) - dbgln("File is not an ELF file."); - return false; - } - - auto expected_class = ELFCLASS64; - auto expected_bitness = 64; - if (expected_class != elf_header.e_ident[EI_CLASS]) { - if (verbose) - dbgln("File is not a {}-bit ELF file.", expected_bitness); - return false; - } - - if (ELFDATA2LSB != elf_header.e_ident[EI_DATA]) { - if (verbose) - dbgln("File is not a little endian ELF file."); - return false; - } - - if (EV_CURRENT != elf_header.e_ident[EI_VERSION]) { - if (verbose) - dbgln("File has unrecognized ELF version ({}), expected ({})!", elf_header.e_ident[EI_VERSION], EV_CURRENT); - return false; - } - - // NOTE: With Clang, -fprofile-instr-generate -fcoverage-mapping sets our ELF ABI Version to 3 b/c of SHF_GNU_RETAIN - if (ELFOSABI_SYSV != elf_header.e_ident[EI_OSABI] && ELFOSABI_LINUX != elf_header.e_ident[EI_OSABI]) { - if (verbose) - dbgln("File has unknown OS ABI ({}), expected SYSV(0) or GNU/Linux(3)!", elf_header.e_ident[EI_OSABI]); - return false; - } - - if (0 != elf_header.e_ident[EI_ABIVERSION]) { - if (verbose) - dbgln("File has unknown SYSV ABI version ({})!", elf_header.e_ident[EI_ABIVERSION]); - return false; - } - - auto expected_machines = Array { EM_X86_64, EM_AARCH64, EM_RISCV }; - auto expected_machine_names = Array { "x86-64"sv, "aarch64"sv, "riscv64"sv }; - - if (!expected_machines.span().contains_slow(elf_header.e_machine)) { - if (verbose) - dbgln("File has unknown machine ({}), expected {} ({})!", elf_header.e_machine, expected_machine_names.span(), expected_machines.span()); - return false; - } - - if (ET_EXEC != elf_header.e_type && ET_DYN != elf_header.e_type && ET_REL != elf_header.e_type && ET_CORE != elf_header.e_type) { - if (verbose) - dbgln("File has unloadable ELF type ({}), expected REL (1), EXEC (2), DYN (3) or CORE(4)!", elf_header.e_type); - return false; - } - - if (EV_CURRENT != elf_header.e_version) { - if (verbose) - dbgln("File has unrecognized ELF version ({}), expected ({})!", elf_header.e_version, EV_CURRENT); - return false; - } - - if (sizeof(Elf_Ehdr) != elf_header.e_ehsize) { - if (verbose) - dbgln("File has incorrect ELF header size..? ({}), expected ({})!", elf_header.e_ehsize, sizeof(Elf_Ehdr)); - return false; - } - - if ((elf_header.e_phnum != 0 && elf_header.e_phoff < elf_header.e_ehsize) || (elf_header.e_shnum != SHN_UNDEF && elf_header.e_shoff < elf_header.e_ehsize)) { - if (verbose) { - dbgln("SHENANIGANS! program header offset ({}) or section header offset ({}) overlap with ELF header!", - elf_header.e_phoff, elf_header.e_shoff); - } - return false; - } - - if (elf_header.e_phoff > file_size || elf_header.e_shoff > file_size) { - if (verbose) { - dbgln("SHENANIGANS! program header offset ({}) or section header offset ({}) are past the end of the file!", - elf_header.e_phoff, elf_header.e_shoff); - } - return false; - } - - if (elf_header.e_phnum == 0 && elf_header.e_phoff != 0) { - if (verbose) - dbgln("SHENANIGANS! File has no program headers, but it does have a program header offset ({})!", elf_header.e_phoff); - return false; - } - - if (elf_header.e_phnum != 0 && elf_header.e_phoff != elf_header.e_ehsize) { - if (verbose) { - dbgln("File does not have program headers directly after the ELF header? program header offset ({}), expected ({}).", - elf_header.e_phoff, elf_header.e_ehsize); - } - return false; - } - - if (0 != elf_header.e_flags) { - // TODO: Refuse to run C ABI binaries on system without the C extension. - // TODO: Refuse to run TSO ABI binaries on system without the Ztso extension. - if (elf_header.e_machine == EM_RISCV) { - auto float_abi = elf_header.e_flags & EF_RISCV_FLOAT_ABI; - // TODO: Support 32-bit hardware float ABI somehow? - if (float_abi != EF_RISCV_FLOAT_ABI_DOUBLE) { - if (verbose) - dbgln("File has unsupported float ABI ({}), only double ({}) is supported.", float_abi, EF_RISCV_FLOAT_ABI_DOUBLE); - return false; - } - } else { - if (verbose) - dbgln("File has incorrect ELF header flags...? ({}), expected ({}).", elf_header.e_flags, 0); - return false; - } - } - - if (0 != elf_header.e_phnum && sizeof(Elf_Phdr) != elf_header.e_phentsize) { - if (verbose) - dbgln("File has incorrect program header size..? ({}), expected ({}).", elf_header.e_phentsize, sizeof(Elf_Phdr)); - return false; - } - - if (sizeof(Elf_Shdr) != elf_header.e_shentsize) { - if (verbose) - dbgln("File has incorrect section header size..? ({}), expected ({}).", elf_header.e_shentsize, sizeof(Elf_Shdr)); - return false; - } - - Checked total_size_of_program_headers = elf_header.e_phnum; - total_size_of_program_headers *= elf_header.e_phentsize; - - Checked end_of_last_program_header = elf_header.e_phoff; - end_of_last_program_header += total_size_of_program_headers; - - if (end_of_last_program_header.has_overflow()) { - if (verbose) - dbgln("SHENANIGANS! Integer overflow in program header validation"); - return false; - } - - if (end_of_last_program_header > file_size) { - if (verbose) - dbgln("SHENANIGANS! End of last program header ({}) is past the end of the file!", end_of_last_program_header.value()); - return false; - } - - if (elf_header.e_shoff != SHN_UNDEF && elf_header.e_shoff < end_of_last_program_header.value()) { - if (verbose) { - dbgln("SHENANIGANS! Section header table begins at file offset {}, which is within program headers [ {} - {} ]!", - elf_header.e_shoff, elf_header.e_phoff, end_of_last_program_header.value()); - } - return false; - } - - Checked total_size_of_section_headers = elf_header.e_shnum; - total_size_of_section_headers *= elf_header.e_shentsize; - - Checked end_of_last_section_header = elf_header.e_shoff; - end_of_last_section_header += total_size_of_section_headers; - - if (end_of_last_section_header.has_overflow()) { - if (verbose) - dbgln("SHENANIGANS! Integer overflow in section header validation"); - return false; - } - - if (end_of_last_section_header > file_size) { - if (verbose) - dbgln("SHENANIGANS! End of last section header ({}) is past the end of the file!", end_of_last_section_header.value()); - return false; - } - - if (elf_header.e_shstrndx != SHN_UNDEF && elf_header.e_shstrndx >= elf_header.e_shnum) { - if (verbose) - dbgln("SHENANIGANS! Section header string table index ({}) is not a valid index given we have {} section headers!", elf_header.e_shstrndx, elf_header.e_shnum); - return false; - } - - return true; -} - -ErrorOr validate_program_headers(Elf_Ehdr const& elf_header, size_t file_size, ReadonlyBytes buffer, StringBuilder* interpreter_path_builder, Optional* requested_stack_size, bool verbose) -{ - Checked total_size_of_program_headers = elf_header.e_phnum; - total_size_of_program_headers *= elf_header.e_phentsize; - - Checked end_of_last_program_header = elf_header.e_phoff; - end_of_last_program_header += total_size_of_program_headers; - - if (end_of_last_program_header.has_overflow()) { - if (verbose) - dbgln("SHENANIGANS! Integer overflow in program header validation"); - return false; - } - - // Can we actually parse all the program headers in the given buffer? - if (end_of_last_program_header > buffer.size()) { - if (verbose) - dbgln("Unable to parse program headers from buffer, buffer too small! Buffer size: {}, End of program headers {}", buffer.size(), end_of_last_program_header.value()); - return false; - } - - if (file_size < buffer.size()) { - dbgln("We somehow read more from a file than was in the file in the first place!"); - VERIFY_NOT_REACHED(); - } - - size_t num_program_headers = elf_header.e_phnum; - auto program_header_begin = (Elf_Phdr const*)buffer.offset(elf_header.e_phoff); - - for (size_t header_index = 0; header_index < num_program_headers; ++header_index) { - auto& program_header = program_header_begin[header_index]; - - if (elf_header.e_machine == EM_RISCV && program_header.p_type == PT_RISCV_ATTRIBUTES) { - // TODO: Handle RISC-V attribute section. - // We have to continue here, as `p_memsz` is 0 when using the GNU toolchain - continue; - } - - if (program_header.p_filesz > program_header.p_memsz) { - if (verbose) - dbgln("Program header ({}) has p_filesz ({}) larger than p_memsz ({})", header_index, program_header.p_filesz, program_header.p_memsz); - return false; - } - - if (elf_header.e_type != ET_CORE) { - if (program_header.p_type == PT_LOAD && program_header.p_align == 0) { - if (verbose) - dbgln("Program header ({}) with p_type PT_LOAD missing p_align (p_align == 0)", header_index); - return false; - } - - if (program_header.p_type == PT_LOAD && program_header.p_align % (size_t)PAGE_SIZE != 0) { - if (verbose) - dbgln("Program header ({}) with p_type PT_LOAD has p_align ({}) not divisible by page size ({})", header_index, program_header.p_align, PAGE_SIZE); - return false; - } - - if (program_header.p_type == PT_LOAD && program_header.p_vaddr % program_header.p_align != program_header.p_offset % program_header.p_align) { - if (verbose) - dbgln("Program header ({}) with p_type PT_LOAD has mis-aligned p_vaddr ({:x})", header_index, program_header.p_vaddr); - return false; - } - } - - switch (program_header.p_type) { - case PT_INTERP: - // We checked above that file_size was >= buffer size. We only care about buffer size anyway, we're trying to read this! - if (Checked::addition_would_overflow(program_header.p_offset, program_header.p_filesz)) { - if (verbose) - dbgln("Integer overflow while validating PT_INTERP header"); - return false; - } - if (program_header.p_offset + program_header.p_filesz > buffer.size()) { - if (verbose) - dbgln("Found PT_INTERP header ({}), but the .interp section was not within the buffer :(", header_index); - return false; - } - if (program_header.p_filesz <= 1) { - if (verbose) - dbgln("Found PT_INTERP header ({}), but p_filesz is invalid ({})", header_index, program_header.p_filesz); - return false; - } - if (interpreter_path_builder) - TRY(interpreter_path_builder->try_append({ buffer.offset(program_header.p_offset), static_cast(program_header.p_filesz) - 1 })); - break; - case PT_LOAD: - case PT_DYNAMIC: - case PT_GNU_EH_FRAME: - case PT_NOTE: - case PT_PHDR: - case PT_TLS: - if (Checked::addition_would_overflow(program_header.p_offset, program_header.p_filesz)) { - if (verbose) - dbgln("Integer overflow while validating a program header"); - return false; - } - if (program_header.p_offset + program_header.p_filesz > file_size) { - if (verbose) - dbgln("SHENANIGANS! Program header {} segment leaks beyond end of file!", header_index); - return false; - } - if ((program_header.p_flags & PF_X) && (program_header.p_flags & PF_W)) { - if (verbose) - dbgln("SHENANIGANS! Program header {} segment is marked write and execute", header_index); - return false; - } - break; - case PT_GNU_STACK: - if (program_header.p_flags & PF_X) { - if (verbose) - dbgln("Possible shenanigans! Validating an ELF with executable stack."); - } - - if (program_header.p_memsz != 0) { - if ( -#ifdef PTHREAD_STACK_MIN - program_header.p_memsz < static_cast(PTHREAD_STACK_MIN) || -#endif - program_header.p_memsz > static_cast(PTHREAD_STACK_MAX)) { - if (verbose) - dbgln("PT_GNU_STACK defines an unacceptable stack size."); - return false; - } - - if (program_header.p_memsz % PAGE_SIZE != 0) { - if (verbose) - dbgln("PT_GNU_STACK size is not page-aligned."); - return false; - } - - if (requested_stack_size) - *requested_stack_size = program_header.p_memsz; - } - - break; - case PT_GNU_RELRO: - if ((program_header.p_flags & PF_X) && (program_header.p_flags & PF_W)) { - if (verbose) - dbgln("SHENANIGANS! Program header {} segment is marked write and execute", header_index); - return false; - } - break; - default: - // Not handling other program header types in other code so... let's not surprise them - if (verbose) - dbgln("Found program header ({}) of unrecognized type {}!", header_index, program_header.p_type); - return false; - } - } - return true; -} - -} // end namespace ELF diff --git a/Userland/Libraries/LibELF/Validation.h b/Userland/Libraries/LibELF/Validation.h deleted file mode 100644 index 8cb520f3f22..00000000000 --- a/Userland/Libraries/LibELF/Validation.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2020, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace ELF { - -bool validate_elf_header(Elf_Ehdr const& elf_header, size_t file_size, bool verbose = true); -ErrorOr validate_program_headers(Elf_Ehdr const& elf_header, size_t file_size, ReadonlyBytes buffer, StringBuilder* interpreter_path_builder = nullptr, Optional* requested_stack_size = nullptr, bool verbose = true); - -} // end namespace ELF diff --git a/Userland/Libraries/LibGL/Blending.cpp b/Userland/Libraries/LibGL/Blending.cpp deleted file mode 100644 index 9053ce22aef..00000000000 --- a/Userland/Libraries/LibGL/Blending.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2024, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace GL { - -void GLContext::gl_blend_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_blend_color, red, green, blue, alpha); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - m_blend_color = { red, green, blue, alpha }; - m_blend_color.clamp(0.f, 1.f); - - auto options = m_rasterizer->options(); - options.blend_color = m_blend_color; - m_rasterizer->set_options(options); -} - -void GLContext::gl_blend_equation_separate(GLenum rgb_mode, GLenum alpha_mode) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_blend_equation_separate, rgb_mode, alpha_mode); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(!(rgb_mode == GL_FUNC_ADD - || rgb_mode == GL_FUNC_SUBTRACT - || rgb_mode == GL_FUNC_REVERSE_SUBTRACT - || rgb_mode == GL_MIN - || rgb_mode == GL_MAX), - GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(!(alpha_mode == GL_FUNC_ADD - || alpha_mode == GL_FUNC_SUBTRACT - || alpha_mode == GL_FUNC_REVERSE_SUBTRACT - || alpha_mode == GL_MIN - || alpha_mode == GL_MAX), - GL_INVALID_ENUM); - - m_blend_equation_rgb = rgb_mode; - m_blend_equation_alpha = alpha_mode; - - auto map_gl_blend_equation_to_device = [](GLenum equation) constexpr { - switch (equation) { - case GL_FUNC_ADD: - return GPU::BlendEquation::Add; - case GL_FUNC_SUBTRACT: - return GPU::BlendEquation::Subtract; - case GL_FUNC_REVERSE_SUBTRACT: - return GPU::BlendEquation::ReverseSubtract; - case GL_MIN: - return GPU::BlendEquation::Min; - case GL_MAX: - return GPU::BlendEquation::Max; - default: - VERIFY_NOT_REACHED(); - } - }; - - auto options = m_rasterizer->options(); - options.blend_equation_rgb = map_gl_blend_equation_to_device(m_blend_equation_rgb); - options.blend_equation_alpha = map_gl_blend_equation_to_device(m_blend_equation_alpha); - m_rasterizer->set_options(options); -} - -void GLContext::gl_blend_func(GLenum src_factor, GLenum dst_factor) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_blend_func, src_factor, dst_factor); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // FIXME: The list of allowed enums differs between API versions - // This was taken from the 2.0 spec on https://docs.gl/gl2/glBlendFunc - - RETURN_WITH_ERROR_IF(!(src_factor == GL_ZERO - || src_factor == GL_ONE - || src_factor == GL_SRC_COLOR - || src_factor == GL_ONE_MINUS_SRC_COLOR - || src_factor == GL_DST_COLOR - || src_factor == GL_ONE_MINUS_DST_COLOR - || src_factor == GL_SRC_ALPHA - || src_factor == GL_ONE_MINUS_SRC_ALPHA - || src_factor == GL_DST_ALPHA - || src_factor == GL_ONE_MINUS_DST_ALPHA - || src_factor == GL_CONSTANT_COLOR - || src_factor == GL_ONE_MINUS_CONSTANT_COLOR - || src_factor == GL_CONSTANT_ALPHA - || src_factor == GL_ONE_MINUS_CONSTANT_ALPHA - || src_factor == GL_SRC_ALPHA_SATURATE), - GL_INVALID_ENUM); - - RETURN_WITH_ERROR_IF(!(dst_factor == GL_ZERO - || dst_factor == GL_ONE - || dst_factor == GL_SRC_COLOR - || dst_factor == GL_ONE_MINUS_SRC_COLOR - || dst_factor == GL_DST_COLOR - || dst_factor == GL_ONE_MINUS_DST_COLOR - || dst_factor == GL_SRC_ALPHA - || dst_factor == GL_ONE_MINUS_SRC_ALPHA - || dst_factor == GL_DST_ALPHA - || dst_factor == GL_ONE_MINUS_DST_ALPHA - || dst_factor == GL_CONSTANT_COLOR - || dst_factor == GL_ONE_MINUS_CONSTANT_COLOR - || dst_factor == GL_CONSTANT_ALPHA - || dst_factor == GL_ONE_MINUS_CONSTANT_ALPHA), - GL_INVALID_ENUM); - - m_blend_source_factor = src_factor; - m_blend_destination_factor = dst_factor; - - auto map_gl_blend_factor_to_device = [](GLenum factor) constexpr { - switch (factor) { - case GL_ZERO: - return GPU::BlendFactor::Zero; - case GL_ONE: - return GPU::BlendFactor::One; - case GL_SRC_COLOR: - return GPU::BlendFactor::SrcColor; - case GL_ONE_MINUS_SRC_COLOR: - return GPU::BlendFactor::OneMinusSrcColor; - case GL_DST_COLOR: - return GPU::BlendFactor::DstColor; - case GL_ONE_MINUS_DST_COLOR: - return GPU::BlendFactor::OneMinusDstColor; - case GL_SRC_ALPHA: - return GPU::BlendFactor::SrcAlpha; - case GL_ONE_MINUS_SRC_ALPHA: - return GPU::BlendFactor::OneMinusSrcAlpha; - case GL_DST_ALPHA: - return GPU::BlendFactor::DstAlpha; - case GL_ONE_MINUS_DST_ALPHA: - return GPU::BlendFactor::OneMinusDstAlpha; - case GL_CONSTANT_COLOR: - return GPU::BlendFactor::ConstantColor; - case GL_ONE_MINUS_CONSTANT_COLOR: - return GPU::BlendFactor::OneMinusConstantColor; - case GL_CONSTANT_ALPHA: - return GPU::BlendFactor::ConstantAlpha; - case GL_ONE_MINUS_CONSTANT_ALPHA: - return GPU::BlendFactor::OneMinusConstantAlpha; - case GL_SRC_ALPHA_SATURATE: - return GPU::BlendFactor::SrcAlphaSaturate; - default: - VERIFY_NOT_REACHED(); - } - }; - - auto options = m_rasterizer->options(); - options.blend_source_factor = map_gl_blend_factor_to_device(m_blend_source_factor); - options.blend_destination_factor = map_gl_blend_factor_to_device(m_blend_destination_factor); - m_rasterizer->set_options(options); -} - -} diff --git a/Userland/Libraries/LibGL/Buffer.cpp b/Userland/Libraries/LibGL/Buffer.cpp deleted file mode 100644 index e44bff386cc..00000000000 --- a/Userland/Libraries/LibGL/Buffer.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2022, Jelle Raaijmakers - * Copyright (c) 2022, cflip - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace GL { - -void GLContext::gl_bind_buffer(GLenum target, GLuint buffer) -{ - RETURN_WITH_ERROR_IF(target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER, GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(!m_buffer_name_allocator.has_allocated_name(buffer), GL_INVALID_VALUE); - - auto& target_buffer = target == GL_ELEMENT_ARRAY_BUFFER ? m_element_array_buffer : m_array_buffer; - target_buffer = nullptr; - - if (buffer != 0) { - auto it = m_allocated_buffers.find(buffer); - if (it != m_allocated_buffers.end()) { - auto buffer_object = it->value; - if (!buffer_object.is_null()) { - target_buffer = buffer_object; - } - } - - if (!target_buffer) { - target_buffer = adopt_ref(*new Buffer()); - m_allocated_buffers.set(buffer, target_buffer); - } - } -} - -void GLContext::gl_buffer_data(GLenum target, GLsizeiptr size, void const* data, GLenum usage) -{ - RETURN_WITH_ERROR_IF(usage != GL_STREAM_DRAW - && usage != GL_STREAM_READ - && usage != GL_STREAM_COPY - && usage != GL_STATIC_DRAW - && usage != GL_STATIC_READ - && usage != GL_STATIC_COPY - && usage != GL_DYNAMIC_DRAW - && usage != GL_DYNAMIC_READ - && usage != GL_DYNAMIC_COPY, - GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER, GL_INVALID_ENUM); - - auto& target_buffer = target == GL_ELEMENT_ARRAY_BUFFER ? m_element_array_buffer : m_array_buffer; - RETURN_WITH_ERROR_IF(!target_buffer, GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(target_buffer->set_data(data, size).is_error(), GL_OUT_OF_MEMORY); -} - -void GLContext::gl_buffer_sub_data(GLenum target, GLintptr offset, GLsizeiptr size, void const* data) -{ - RETURN_WITH_ERROR_IF(target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER, GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(offset < 0, GL_INVALID_VALUE); - // FIXME: Support buffer storage mutability flags. - - auto& target_buffer = target == GL_ELEMENT_ARRAY_BUFFER ? m_element_array_buffer : m_array_buffer; - RETURN_WITH_ERROR_IF(!target_buffer, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(static_cast(offset + size) > target_buffer->size(), GL_INVALID_VALUE); - - target_buffer->replace_data(data, offset, size); -} - -void GLContext::gl_delete_buffers(GLsizei n, GLuint const* buffers) -{ - RETURN_WITH_ERROR_IF(n < 0, GL_INVALID_VALUE); - - for (auto i = 0; i < n; i++) { - GLuint name = buffers[i]; - if (name == 0) - continue; - - auto buffer_object = m_allocated_buffers.find(name); - if (buffer_object == m_allocated_buffers.end() || buffer_object->value.is_null()) - continue; - - Buffer* buffer = buffer_object->value; - - if (m_array_buffer == buffer) - m_array_buffer = nullptr; - - if (m_element_array_buffer == buffer) - m_element_array_buffer = nullptr; - - m_buffer_name_allocator.free(name); - m_allocated_buffers.remove(name); - } -} - -void GLContext::gl_gen_buffers(GLsizei n, GLuint* buffers) -{ - RETURN_WITH_ERROR_IF(n < 0, GL_INVALID_VALUE); - - m_buffer_name_allocator.allocate(n, buffers); - - // Initialize all buffer names with a nullptr - for (auto i = 0; i < n; ++i) { - GLuint name = buffers[i]; - m_allocated_buffers.set(name, nullptr); - } -} - -} diff --git a/Userland/Libraries/LibGL/Buffer/Buffer.cpp b/Userland/Libraries/LibGL/Buffer/Buffer.cpp deleted file mode 100644 index dbfa8444159..00000000000 --- a/Userland/Libraries/LibGL/Buffer/Buffer.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2022, cflip - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Buffer.h" - -namespace GL { - -ErrorOr Buffer::set_data(void const* data, size_t size) -{ - if (!data) { - m_data = TRY(ByteBuffer::create_uninitialized(size)); - return {}; - } - m_data = TRY(ByteBuffer::copy(data, size)); - return {}; -} - -void Buffer::replace_data(void const* data, size_t offset, size_t size) -{ - m_data.overwrite(offset, data, size); -} - -size_t Buffer::size() -{ - return m_data.size(); -} - -void* Buffer::data() -{ - return m_data.data(); -} - -void* Buffer::offset_data(size_t offset) -{ - return m_data.offset_pointer(offset); -} - -} diff --git a/Userland/Libraries/LibGL/Buffer/Buffer.h b/Userland/Libraries/LibGL/Buffer/Buffer.h deleted file mode 100644 index ba3d1af3346..00000000000 --- a/Userland/Libraries/LibGL/Buffer/Buffer.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2022, cflip - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace GL { - -// FIXME: For now, this is basically just a wrapper around ByteBuffer, but in -// the future buffer data should be stored in LibGPU. -class Buffer : public RefCounted { -public: - ErrorOr set_data(void const*, size_t); - void replace_data(void const*, size_t offset, size_t size); - - size_t size(); - void* data(); - void* offset_data(size_t); - -private: - ByteBuffer m_data; -}; - -} diff --git a/Userland/Libraries/LibGL/CMakeLists.txt b/Userland/Libraries/LibGL/CMakeLists.txt deleted file mode 100644 index 2cc74389c3b..00000000000 --- a/Userland/Libraries/LibGL/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -include(libgl_generators) - -set(SOURCES - Blending.cpp - Buffer/Buffer.cpp - Buffer.cpp - ClipPlane.cpp - ContextParameter.cpp - GLContext.cpp - Image.cpp - Lighting.cpp - List.cpp - Matrix.cpp - NameAllocator.cpp - Shader.cpp - Shaders/Program.cpp - Shaders/Shader.cpp - Stencil.cpp - Tex/Texture2D.cpp - Texture.cpp - Vertex.cpp -) - -generate_libgl_implementation() - -set(GENERATED_SOURCES - GLAPI.cpp) - -serenity_lib(LibGL gl) -target_link_libraries(LibGL PRIVATE LibGfx LibGLSL LibGPU) - -# Install symlinks at some common locations so ports can find LibGL without issue -if (SERENITYOS) - install(CODE " - file(CREATE_LINK LibGL/GL/ \${CMAKE_INSTALL_PREFIX}/usr/include/GL SYMBOLIC) - file(CREATE_LINK libgl.so.serenity \${CMAKE_INSTALL_PREFIX}/usr/lib/libGL.so SYMBOLIC) - file(CREATE_LINK libgl.so.serenity \${CMAKE_INSTALL_PREFIX}/usr/lib/libGL.so.1 SYMBOLIC) - ") -endif() diff --git a/Userland/Libraries/LibGL/ClipPlane.cpp b/Userland/Libraries/LibGL/ClipPlane.cpp deleted file mode 100644 index 9d7301240dd..00000000000 --- a/Userland/Libraries/LibGL/ClipPlane.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * Copyright (c) 2022, Ryan Bethke - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace GL { - -void GLContext::gl_clip_plane(GLenum plane, GLdouble const* equation) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clip_plane, plane, equation); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF((plane < GL_CLIP_PLANE0) || (plane > GL_CLIP_PLANE5), GL_INVALID_ENUM); - - auto plane_idx = static_cast(plane) - GL_CLIP_PLANE0; - - auto eqn = FloatVector4(equation[0], equation[1], equation[2], equation[3]); - m_clip_plane_attributes.eye_clip_plane[plane_idx] = model_view_matrix() * eqn; - m_clip_planes_dirty = true; -} - -void GLContext::gl_get_clip_plane(GLenum plane, GLdouble* equation) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF((plane < GL_CLIP_PLANE0) || (plane > GL_CLIP_PLANE5), GL_INVALID_ENUM); - - auto plane_idx = static_cast(plane) - GL_CLIP_PLANE0; - equation[0] = static_cast(m_clip_plane_attributes.eye_clip_plane[plane_idx][0]); - equation[1] = static_cast(m_clip_plane_attributes.eye_clip_plane[plane_idx][1]); - equation[2] = static_cast(m_clip_plane_attributes.eye_clip_plane[plane_idx][2]); - equation[3] = static_cast(m_clip_plane_attributes.eye_clip_plane[plane_idx][3]); -} - -void GLContext::sync_clip_planes() -{ - if (!m_clip_planes_dirty) - return; - m_clip_planes_dirty = false; - - // TODO: Replace magic number 6 with device-dependent constant - Vector user_clip_planes; - for (size_t plane_idx = 0; plane_idx < 6; ++plane_idx) { - if ((m_clip_plane_attributes.enabled & (1 << plane_idx)) != 0u) { - user_clip_planes.append(m_clip_plane_attributes.eye_clip_plane[plane_idx]); - } - } - m_rasterizer->set_clip_planes(user_clip_planes); -} - -} diff --git a/Userland/Libraries/LibGL/ContextParameter.cpp b/Userland/Libraries/LibGL/ContextParameter.cpp deleted file mode 100644 index 94dff5809a6..00000000000 --- a/Userland/Libraries/LibGL/ContextParameter.cpp +++ /dev/null @@ -1,653 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022-2024, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -namespace GL { - -Optional GLContext::get_context_parameter(GLenum name) -{ - switch (name) { - case GL_ACTIVE_TEXTURE: - return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast(GL_TEXTURE0 + m_active_texture_unit_index) } }; - case GL_ALPHA_BITS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(u8) * 8 } }; - case GL_ALPHA_TEST: - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_alpha_test_enabled } }; - case GL_BLEND: - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_blend_enabled } }; - case GL_BLEND_DST: - case GL_BLEND_DST_ALPHA: - return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast(m_blend_destination_factor) } }; - case GL_BLEND_EQUATION_ALPHA: - return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast(m_blend_equation_alpha) } }; - case GL_BLEND_EQUATION_RGB: - return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast(m_blend_equation_rgb) } }; - case GL_BLEND_SRC: - case GL_BLEND_SRC_ALPHA: - return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast(m_blend_source_factor) } }; - case GL_BLUE_BITS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(u8) * 8 } }; - case GL_CLIENT_ACTIVE_TEXTURE: - return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast(GL_TEXTURE0 + m_client_active_texture) } }; - case GL_COLOR_CLEAR_VALUE: - return ContextParameter { - .type = GL_DOUBLE, - .count = 4, - .value = { - .double_list = { - static_cast(m_clear_color.x()), - static_cast(m_clear_color.y()), - static_cast(m_clear_color.z()), - static_cast(m_clear_color.w()), - } } - }; - case GL_COLOR_MATERIAL: - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_color_material_enabled } }; - case GL_COLOR_MATERIAL_FACE: - return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast(m_color_material_face) } }; - case GL_COLOR_MATERIAL_MODE: - return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast(m_color_material_mode) } }; - case GL_CURRENT_COLOR: - return ContextParameter { - .type = GL_DOUBLE, - .count = 4, - .value = { - .double_list = { - static_cast(m_current_vertex_color.x()), - static_cast(m_current_vertex_color.y()), - static_cast(m_current_vertex_color.z()), - static_cast(m_current_vertex_color.w()), - } } - }; - case GL_CULL_FACE: - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_cull_faces } }; - case GL_DEPTH_BITS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } }; - case GL_DEPTH_CLEAR_VALUE: - return ContextParameter { .type = GL_DOUBLE, .value = { .double_value = static_cast(m_clear_depth) } }; - case GL_DEPTH_TEST: - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_depth_test_enabled } }; - case GL_DITHER: - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_dither_enabled } }; - case GL_DOUBLEBUFFER: - return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = true } }; - case GL_FOG: { - auto fog_enabled = m_rasterizer->options().fog_enabled; - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = fog_enabled } }; - } - case GL_GREEN_BITS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(u8) * 8 } }; - case GL_LIGHTING: - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_lighting_enabled } }; - case GL_LINE_SMOOTH: - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_line_smooth } }; - case GL_MAX_CLIP_PLANES: - return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast(m_device_info.max_clip_planes) } }; - case GL_MAX_LIGHTS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast(m_device_info.num_lights) } }; - case GL_MAX_MODELVIEW_STACK_DEPTH: - return ContextParameter { .type = GL_INT, .value = { .integer_value = MODELVIEW_MATRIX_STACK_LIMIT } }; - case GL_MAX_PROJECTION_STACK_DEPTH: - return ContextParameter { .type = GL_INT, .value = { .integer_value = PROJECTION_MATRIX_STACK_LIMIT } }; - case GL_MAX_TEXTURE_LOD_BIAS: - return ContextParameter { .type = GL_DOUBLE, .value = { .double_value = static_cast(m_device_info.max_texture_lod_bias) } }; - case GL_MAX_TEXTURE_SIZE: - return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast(m_device_info.max_texture_size) } }; - case GL_MAX_TEXTURE_STACK_DEPTH: - return ContextParameter { .type = GL_INT, .value = { .integer_value = TEXTURE_MATRIX_STACK_LIMIT } }; - case GL_MAX_TEXTURE_UNITS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast(m_texture_units.size()) } }; - case GL_NORMAL_ARRAY_TYPE: - return ContextParameter { .type = GL_INT, .value = { .integer_value = GL_FLOAT } }; - case GL_NORMALIZE: - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_normalize } }; - case GL_PACK_ALIGNMENT: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_packing_parameters.pack_alignment } }; - case GL_PACK_IMAGE_HEIGHT: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_packing_parameters.image_height } }; - case GL_PACK_LSB_FIRST: - return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_packing_parameters.least_significant_bit_first } }; - case GL_PACK_ROW_LENGTH: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_packing_parameters.row_length } }; - case GL_PACK_SKIP_IMAGES: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_packing_parameters.skip_images } }; - case GL_PACK_SKIP_PIXELS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_packing_parameters.skip_pixels } }; - case GL_PACK_SKIP_ROWS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_packing_parameters.skip_rows } }; - case GL_PACK_SWAP_BYTES: - return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_packing_parameters.swap_bytes } }; - case GL_POINT_SMOOTH: - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_point_smooth } }; - case GL_POINT_SIZE: - return ContextParameter { .type = GL_DOUBLE, .value = { .double_value = static_cast(m_point_size) } }; - case GL_POLYGON_OFFSET_FILL: - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_depth_offset_enabled } }; - case GL_RED_BITS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(u8) * 8 } }; - case GL_SAMPLE_BUFFERS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = 0 } }; - case GL_SAMPLES: - return ContextParameter { .type = GL_INT, .value = { .integer_value = 1 } }; - case GL_SCISSOR_BOX: { - auto scissor_box = m_rasterizer->options().scissor_box; - return ContextParameter { - .type = GL_INT, - .count = 4, - .value = { - .integer_list = { - scissor_box.x(), - scissor_box.y(), - scissor_box.width(), - scissor_box.height(), - } } - }; - } - case GL_SCISSOR_TEST: { - auto scissor_enabled = m_rasterizer->options().scissor_enabled; - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = scissor_enabled } }; - } - case GL_STENCIL_BITS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_device_info.stencil_bits } }; - case GL_STENCIL_CLEAR_VALUE: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_clear_stencil } }; - case GL_STENCIL_TEST: - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_stencil_test_enabled } }; - case GL_TEXTURE_1D: - return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_1d_enabled() } }; - case GL_TEXTURE_2D: - return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_2d_enabled() } }; - case GL_TEXTURE_3D: - return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_3d_enabled() } }; - case GL_TEXTURE_CUBE_MAP: - return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_cube_map_enabled() } }; - case GL_TEXTURE_GEN_Q: - case GL_TEXTURE_GEN_R: - case GL_TEXTURE_GEN_S: - case GL_TEXTURE_GEN_T: { - auto generation_enabled = texture_coordinate_generation(m_active_texture_unit_index, name).enabled; - return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = generation_enabled } }; - } - case GL_UNPACK_ALIGNMENT: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpacking_parameters.pack_alignment } }; - case GL_UNPACK_IMAGE_HEIGHT: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpacking_parameters.image_height } }; - case GL_UNPACK_LSB_FIRST: - return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_unpacking_parameters.least_significant_bit_first } }; - case GL_UNPACK_ROW_LENGTH: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpacking_parameters.row_length } }; - case GL_UNPACK_SKIP_IMAGES: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpacking_parameters.skip_images } }; - case GL_UNPACK_SKIP_PIXELS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpacking_parameters.skip_pixels } }; - case GL_UNPACK_SKIP_ROWS: - return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpacking_parameters.skip_rows } }; - case GL_UNPACK_SWAP_BYTES: - return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_unpacking_parameters.swap_bytes } }; - case GL_VIEWPORT: - return ContextParameter { - .type = GL_INT, - .count = 4, - .value = { - .integer_list = { - m_viewport.x(), - m_viewport.y(), - m_viewport.width(), - m_viewport.height(), - } } - }; - default: - dbgln_if(GL_DEBUG, "get_context_parameter({:#x}): unknown context parameter", name); - return {}; - } -} - -void GLContext::gl_disable(GLenum capability) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_disable, capability); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - auto rasterizer_options = m_rasterizer->options(); - bool update_rasterizer_options = false; - - switch (capability) { - case GL_CLIP_PLANE0: - case GL_CLIP_PLANE1: - case GL_CLIP_PLANE2: - case GL_CLIP_PLANE3: - case GL_CLIP_PLANE4: - case GL_CLIP_PLANE5: { - auto plane_idx = static_cast(capability) - GL_CLIP_PLANE0; - m_clip_plane_attributes.enabled &= ~(1 << plane_idx); - m_clip_planes_dirty = true; - break; - } - case GL_COLOR_MATERIAL: - m_color_material_enabled = false; - break; - case GL_CULL_FACE: - m_cull_faces = false; - rasterizer_options.enable_culling = false; - update_rasterizer_options = true; - break; - case GL_DEPTH_TEST: - m_depth_test_enabled = false; - rasterizer_options.enable_depth_test = false; - update_rasterizer_options = true; - break; - case GL_BLEND: - m_blend_enabled = false; - rasterizer_options.enable_blending = false; - update_rasterizer_options = true; - break; - case GL_ALPHA_TEST: - m_alpha_test_enabled = false; - rasterizer_options.enable_alpha_test = false; - update_rasterizer_options = true; - break; - case GL_DITHER: - m_dither_enabled = false; - break; - case GL_FOG: - rasterizer_options.fog_enabled = false; - update_rasterizer_options = true; - break; - case GL_LIGHTING: - m_lighting_enabled = false; - rasterizer_options.lighting_enabled = false; - update_rasterizer_options = true; - break; - case GL_LIGHT0: - case GL_LIGHT1: - case GL_LIGHT2: - case GL_LIGHT3: - case GL_LIGHT4: - case GL_LIGHT5: - case GL_LIGHT6: - case GL_LIGHT7: - m_light_states.at(capability - GL_LIGHT0).is_enabled = false; - m_light_state_is_dirty = true; - break; - case GL_LINE_SMOOTH: - m_line_smooth = false; - rasterizer_options.line_smooth = false; - update_rasterizer_options = true; - break; - case GL_NORMALIZE: - m_normalize = false; - rasterizer_options.normalization_enabled = false; - update_rasterizer_options = true; - break; - case GL_POINT_SMOOTH: - m_point_smooth = false; - rasterizer_options.point_smooth = false; - update_rasterizer_options = true; - break; - case GL_POLYGON_OFFSET_FILL: - m_depth_offset_enabled = false; - rasterizer_options.depth_offset_enabled = false; - update_rasterizer_options = true; - break; - case GL_SCISSOR_TEST: - rasterizer_options.scissor_enabled = false; - update_rasterizer_options = true; - break; - case GL_STENCIL_TEST: - m_stencil_test_enabled = false; - rasterizer_options.enable_stencil_test = false; - update_rasterizer_options = true; - break; - case GL_TEXTURE_1D: - m_active_texture_unit->set_texture_1d_enabled(false); - m_sampler_config_is_dirty = true; - m_texture_units_dirty = true; - break; - case GL_TEXTURE_2D: - m_active_texture_unit->set_texture_2d_enabled(false); - m_sampler_config_is_dirty = true; - m_texture_units_dirty = true; - break; - case GL_TEXTURE_3D: - m_active_texture_unit->set_texture_3d_enabled(false); - m_sampler_config_is_dirty = true; - m_texture_units_dirty = true; - break; - case GL_TEXTURE_CUBE_MAP: - m_active_texture_unit->set_texture_cube_map_enabled(false); - m_sampler_config_is_dirty = true; - m_texture_units_dirty = true; - break; - case GL_TEXTURE_GEN_Q: - case GL_TEXTURE_GEN_R: - case GL_TEXTURE_GEN_S: - case GL_TEXTURE_GEN_T: - texture_coordinate_generation(m_active_texture_unit_index, capability).enabled = false; - m_texture_units_dirty = true; - break; - default: - dbgln_if(GL_DEBUG, "gl_disable({:#x}): unknown parameter", capability); - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - - if (update_rasterizer_options) - m_rasterizer->set_options(rasterizer_options); -} - -void GLContext::gl_disable_client_state(GLenum cap) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - switch (cap) { - case GL_COLOR_ARRAY: - m_client_side_color_array_enabled = false; - break; - case GL_NORMAL_ARRAY: - m_client_side_normal_array_enabled = false; - break; - case GL_TEXTURE_COORD_ARRAY: - m_client_side_texture_coord_array_enabled[m_client_active_texture] = false; - break; - case GL_VERTEX_ARRAY: - m_client_side_vertex_array_enabled = false; - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } -} - -void GLContext::gl_enable(GLenum capability) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_enable, capability); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - auto rasterizer_options = m_rasterizer->options(); - bool update_rasterizer_options = false; - - switch (capability) { - case GL_CLIP_PLANE0: - case GL_CLIP_PLANE1: - case GL_CLIP_PLANE2: - case GL_CLIP_PLANE3: - case GL_CLIP_PLANE4: - case GL_CLIP_PLANE5: { - auto plane_idx = static_cast(capability) - GL_CLIP_PLANE0; - m_clip_plane_attributes.enabled |= (1 << plane_idx); - m_clip_planes_dirty = true; - break; - } - case GL_COLOR_MATERIAL: - m_color_material_enabled = true; - break; - case GL_CULL_FACE: - m_cull_faces = true; - rasterizer_options.enable_culling = true; - update_rasterizer_options = true; - break; - case GL_DEPTH_TEST: - m_depth_test_enabled = true; - rasterizer_options.enable_depth_test = true; - update_rasterizer_options = true; - break; - case GL_BLEND: - m_blend_enabled = true; - rasterizer_options.enable_blending = true; - update_rasterizer_options = true; - break; - case GL_ALPHA_TEST: - m_alpha_test_enabled = true; - rasterizer_options.enable_alpha_test = true; - update_rasterizer_options = true; - break; - case GL_DITHER: - m_dither_enabled = true; - break; - case GL_FOG: - rasterizer_options.fog_enabled = true; - update_rasterizer_options = true; - break; - case GL_LIGHTING: - m_lighting_enabled = true; - rasterizer_options.lighting_enabled = true; - update_rasterizer_options = true; - break; - case GL_LIGHT0: - case GL_LIGHT1: - case GL_LIGHT2: - case GL_LIGHT3: - case GL_LIGHT4: - case GL_LIGHT5: - case GL_LIGHT6: - case GL_LIGHT7: - m_light_states.at(capability - GL_LIGHT0).is_enabled = true; - m_light_state_is_dirty = true; - break; - case GL_LINE_SMOOTH: - m_line_smooth = true; - rasterizer_options.line_smooth = true; - update_rasterizer_options = true; - break; - case GL_NORMALIZE: - m_normalize = true; - rasterizer_options.normalization_enabled = true; - update_rasterizer_options = true; - break; - case GL_POINT_SMOOTH: - m_point_smooth = true; - rasterizer_options.point_smooth = true; - update_rasterizer_options = true; - break; - case GL_POLYGON_OFFSET_FILL: - m_depth_offset_enabled = true; - rasterizer_options.depth_offset_enabled = true; - update_rasterizer_options = true; - break; - case GL_SCISSOR_TEST: - rasterizer_options.scissor_enabled = true; - update_rasterizer_options = true; - break; - case GL_STENCIL_TEST: - m_stencil_test_enabled = true; - rasterizer_options.enable_stencil_test = true; - update_rasterizer_options = true; - break; - case GL_TEXTURE_1D: - m_active_texture_unit->set_texture_1d_enabled(true); - m_sampler_config_is_dirty = true; - m_texture_units_dirty = true; - break; - case GL_TEXTURE_2D: - m_active_texture_unit->set_texture_2d_enabled(true); - m_sampler_config_is_dirty = true; - m_texture_units_dirty = true; - break; - case GL_TEXTURE_3D: - m_active_texture_unit->set_texture_3d_enabled(true); - m_sampler_config_is_dirty = true; - m_texture_units_dirty = true; - break; - case GL_TEXTURE_CUBE_MAP: - m_active_texture_unit->set_texture_cube_map_enabled(true); - m_sampler_config_is_dirty = true; - m_texture_units_dirty = true; - break; - case GL_TEXTURE_GEN_Q: - case GL_TEXTURE_GEN_R: - case GL_TEXTURE_GEN_S: - case GL_TEXTURE_GEN_T: - texture_coordinate_generation(m_active_texture_unit_index, capability).enabled = true; - m_texture_units_dirty = true; - break; - default: - dbgln_if(GL_DEBUG, "gl_enable({:#x}): unknown parameter", capability); - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - - if (update_rasterizer_options) - m_rasterizer->set_options(rasterizer_options); -} - -void GLContext::gl_enable_client_state(GLenum cap) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - switch (cap) { - case GL_COLOR_ARRAY: - m_client_side_color_array_enabled = true; - break; - case GL_NORMAL_ARRAY: - m_client_side_normal_array_enabled = true; - break; - case GL_TEXTURE_COORD_ARRAY: - m_client_side_texture_coord_array_enabled[m_client_active_texture] = true; - break; - case GL_VERTEX_ARRAY: - m_client_side_vertex_array_enabled = true; - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } -} - -void GLContext::gl_get_booleanv(GLenum pname, GLboolean* data) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - auto optional_parameter = get_context_parameter(pname); - RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM); - auto parameter = optional_parameter.release_value(); - - switch (parameter.type) { - case GL_BOOL: - *data = parameter.value.boolean_value ? GL_TRUE : GL_FALSE; - break; - case GL_DOUBLE: - *data = (parameter.value.double_value == 0.0) ? GL_FALSE : GL_TRUE; - break; - case GL_INT: - *data = (parameter.value.integer_value == 0) ? GL_FALSE : GL_TRUE; - break; - default: - VERIFY_NOT_REACHED(); - } -} - -void GLContext::gl_get_doublev(GLenum pname, GLdouble* params) -{ - get_floating_point(pname, params); -} - -template -void GLContext::get_floating_point(GLenum pname, T* params) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // Handle matrix retrieval first - auto flatten_and_assign_matrix = [¶ms](FloatMatrix4x4 const& matrix) { - auto elements = matrix.elements(); - for (size_t i = 0; i < 4; ++i) { - for (size_t j = 0; j < 4; ++j) { - // Return transposed matrix since OpenGL defines them as column-major - params[i * 4 + j] = static_cast(elements[j][i]); - } - } - }; - switch (pname) { - case GL_MODELVIEW_MATRIX: - flatten_and_assign_matrix(model_view_matrix()); - return; - case GL_PROJECTION_MATRIX: - flatten_and_assign_matrix(projection_matrix()); - return; - } - - // Regular parameters - auto optional_parameter = get_context_parameter(pname); - RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM); - auto parameter = optional_parameter.release_value(); - - switch (parameter.type) { - case GL_BOOL: - *params = parameter.value.boolean_value ? GL_TRUE : GL_FALSE; - break; - case GL_DOUBLE: - for (size_t i = 0; i < parameter.count; ++i) - params[i] = parameter.value.double_list[i]; - break; - case GL_INT: - for (size_t i = 0; i < parameter.count; ++i) - params[i] = parameter.value.integer_list[i]; - break; - default: - VERIFY_NOT_REACHED(); - } -} - -void GLContext::gl_get_floatv(GLenum pname, GLfloat* params) -{ - get_floating_point(pname, params); -} - -void GLContext::gl_get_integerv(GLenum pname, GLint* data) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - auto optional_parameter = get_context_parameter(pname); - RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM); - auto parameter = optional_parameter.release_value(); - - switch (parameter.type) { - case GL_BOOL: - *data = parameter.value.boolean_value ? GL_TRUE : GL_FALSE; - break; - case GL_DOUBLE: { - double const int_range = static_cast(NumericLimits::max()) - NumericLimits::min(); - for (size_t i = 0; i < parameter.count; ++i) { - double const result_factor = (clamp(parameter.value.double_list[i], -1.0, 1.0) + 1.0) / 2.0; - data[i] = static_cast(NumericLimits::min() + result_factor * int_range); - } - break; - } - case GL_INT: - for (size_t i = 0; i < parameter.count; ++i) - data[i] = parameter.value.integer_list[i]; - break; - default: - VERIFY_NOT_REACHED(); - } -} - -GLboolean GLContext::gl_is_enabled(GLenum capability) -{ - RETURN_VALUE_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION, 0); - - auto optional_parameter = get_context_parameter(capability); - RETURN_VALUE_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM, 0); - - auto parameter = optional_parameter.release_value(); - RETURN_VALUE_WITH_ERROR_IF(!parameter.is_capability, GL_INVALID_ENUM, 0); - - return parameter.value.boolean_value ? GL_TRUE : GL_FALSE; -} - -GPU::PackingSpecification GLContext::get_packing_specification(PackingType packing_type) -{ - // FIXME: add support for .least_significant_bit_first, .skip_images, .skip_pixels and .skip_rows - auto const& pixel_parameters = (packing_type == PackingType::Pack) ? m_packing_parameters : m_unpacking_parameters; - return { - .depth_stride = static_cast(pixel_parameters.image_height), - .row_stride = static_cast(pixel_parameters.row_length), - .byte_alignment = pixel_parameters.pack_alignment, - .component_bytes_order = pixel_parameters.swap_bytes ? GPU::ComponentBytesOrder::Reversed : GPU::ComponentBytesOrder::Normal, - }; -} - -} diff --git a/Userland/Libraries/LibGL/GL/gl.h b/Userland/Libraries/LibGL/GL/gl.h deleted file mode 100644 index b2d119760ab..00000000000 --- a/Userland/Libraries/LibGL/GL/gl.h +++ /dev/null @@ -1,648 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2021-2024, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define GL_VERSION_1_0 1 -#define GL_VERSION_1_1 1 -#define GL_VERSION_1_2 1 -#define GL_VERSION_1_3 1 -#define GL_VERSION_1_4 1 -#define GL_VERSION_1_5 1 -#define GL_ES_VERSION_2_0 1 - -// OpenGL related `defines` -#define GL_TRUE 1 -#define GL_FALSE 0 -#define GL_NONE 0 - -// Matrix Modes -#define GL_MODELVIEW 0x1700 -#define GL_PROJECTION 0x1701 -#define GL_TEXTURE 0x1702 - -// glBegin/glEnd primitive types -#define GL_POINTS 0x0000 -#define GL_LINES 0x0001 -#define GL_LINE_LOOP 0x0002 -#define GL_LINE_STRIP 0x0003 -#define GL_TRIANGLES 0x0004 -#define GL_TRIANGLE_STRIP 0x0005 -#define GL_TRIANGLE_FAN 0x0006 -#define GL_QUADS 0x0007 -#define GL_QUAD_STRIP 0x0008 -#define GL_POLYGON 0x0009 - -// Depth buffer and alpha test compare functions -#define GL_NEVER 0x0200 -#define GL_LESS 0x0201 -#define GL_EQUAL 0x0202 -#define GL_LEQUAL 0x0203 -#define GL_GREATER 0x0204 -#define GL_NOTEQUAL 0x0205 -#define GL_GEQUAL 0x0206 -#define GL_ALWAYS 0x0207 - -// Buffer bits -#define GL_DEPTH_BUFFER_BIT 0x00000100 -#define GL_STENCIL_BUFFER_BIT 0x00000400 -#define GL_COLOR_BUFFER_BIT 0x00004000 - -// Enable capabilities -#define GL_LINE_SMOOTH 0x0B20 -#define GL_POLYGON_MODE 0x0B40 -#define GL_POLYGON_SMOOTH 0x0B41 -#define GL_POLYGON_STIPPLE 0x0B42 -#define GL_EDGE_FLAG 0x0B43 -#define GL_CULL_FACE 0x0B44 -#define GL_FOG 0x0B60 -#define GL_DEPTH_TEST 0x0B71 -#define GL_STENCIL_TEST 0x0B90 -#define GL_DITHER 0x0BD0 -#define GL_POLYGON_OFFSET_FILL 0x8037 - -// Alpha testing -#define GL_ALPHA_TEST 0x0BC0 -#define GL_ALPHA_TEST_REF 0x0BC2 -#define GL_ALPHA_TEST_FUNC 0x0BC1 - -// Alpha blending -#define GL_BLEND 0x0BE2 -#define GL_BLEND_SRC_ALPHA 0x80CB -#define GL_BLEND_SRC_ALPHA_EXT 0x80CB -#define GL_BLEND_DST_ALPHA 0x80CA -#define GL_BLEND_DST_ALPHA_EXT 0x80CA - -// Attribute bit flags -#define GL_CURRENT_BIT 0x00000001 -#define GL_POINT_BIT 0x00000002 -#define GL_LINE_BIT 0x00000004 -#define GL_POLYGON_BIT 0x00000008 -#define GL_POLYGON_STIPPLE_BIT 0x00000010 -#define GL_PIXEL_MODE_BIT 0x00000020 -#define GL_LIGHTING_BIT 0x00000040 -#define GL_FOG_BIT 0x00000080 -#define GL_DEPTH_BUFFER_BIT 0x00000100 -#define GL_ACCUM_BUFFER_BIT 0x00000200 -#define GL_STENCIL_BUFFER_BIT 0x00000400 -#define GL_VIEWPORT_BIT 0x00000800 -#define GL_TRANSFORM_BIT 0x00001000 -#define GL_ENABLE_BIT 0x00002000 -#define GL_COLOR_BUFFER_BIT 0x00004000 -#define GL_HINT_BIT 0x00008000 -#define GL_EVAL_BIT 0x00010000 -#define GL_LIST_BIT 0x00020000 -#define GL_TEXTURE_BIT 0x00020000 -#define GL_SCISSOR_BIT 0x00080000 -#define GL_MULTISAMPLE_BIT 0x20000000 -#define GL_ALL_ATTRIB_BITS 0xFFFFFFFF - -// Utility -#define GL_VENDOR 0x1F00 -#define GL_RENDERER 0x1F01 -#define GL_VERSION 0x1F02 -#define GL_EXTENSIONS 0x1F03 -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C - -// Get parameters -#define GL_CURRENT_COLOR 0x0B00 -#define GL_COLOR_MATERIAL_FACE 0x0B55 -#define GL_COLOR_MATERIAL_MODE 0x0B56 -#define GL_COLOR_MATERIAL 0x0B57 -#define GL_FOG_START 0x0B63 -#define GL_FOG_END 0x0B64 -#define GL_DEPTH_CLEAR_VALUE 0x0B73 -#define GL_STENCIL_CLEAR_VALUE 0x0B91 -#define GL_MATRIX_MODE 0x0BA0 -#define GL_NORMALIZE 0x0BA1 -#define GL_VIEWPORT 0x0BA2 -#define GL_BLEND_DST 0x0BE0 -#define GL_BLEND_SRC 0x0BE1 -#define GL_COLOR_CLEAR_VALUE 0x0C22 -#define GL_DOUBLEBUFFER 0x0C32 -#define GL_TEXTURE_GEN_S 0x0C60 -#define GL_TEXTURE_GEN_T 0x0C61 -#define GL_TEXTURE_GEN_R 0x0C62 -#define GL_TEXTURE_GEN_Q 0x0C63 -#define GL_MAX_TEXTURE_SIZE 0x0D33 -#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 -#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 -#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 -#define GL_RED_BITS 0x0D52 -#define GL_GREEN_BITS 0x0D53 -#define GL_BLUE_BITS 0x0D54 -#define GL_ALPHA_BITS 0x0D55 -#define GL_DEPTH_BITS 0x0D56 -#define GL_STENCIL_BITS 0x0D57 -#define GL_ACTIVE_TEXTURE 0x84E0 -#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 -#define GL_MAX_TEXTURE_UNITS 0x84E2 -#define GL_MAX_LIGHTS 0x0D31 -#define GL_AUTO_NORMAL 0x0D80 -#define GL_MAP1_COLOR_4 0x0D90 -#define GL_MAP1_INDEX 0x0D91 -#define GL_MAP1_NORMAL 0x0D92 -#define GL_MAP1_TEXTURE_COORD_1 0x0D93 -#define GL_MAP1_TEXTURE_COORD_2 0x0D94 -#define GL_MAP1_TEXTURE_COORD_3 0x0D95 -#define GL_MAP1_TEXTURE_COORD_4 0x0D96 -#define GL_MAP1_VERTEX_3 0x0D97 -#define GL_MAP1_VERTEX_4 0x0D98 -#define GL_MAP2_COLOR_4 0x0DB0 -#define GL_MAP2_INDEX 0x0DB1 -#define GL_MAP2_NORMAL 0x0DB2 -#define GL_MAP2_TEXTURE_COORD_1 0x0DB3 -#define GL_MAP2_TEXTURE_COORD_2 0x0DB4 -#define GL_MAP2_TEXTURE_COORD_3 0x0DB5 -#define GL_MAP2_TEXTURE_COORD_4 0x0DB6 -#define GL_MAP2_VERTEX_3 0x0DB7 -#define GL_MAP2_VERTEX_4 0x0DB8 -#define GL_NORMAL_ARRAY 0x8075 -#define GL_NORMAL_ARRAY_TYPE 0x807E -#define GL_SAMPLE_BUFFERS 0x80A8 -#define GL_SAMPLES 0x80A9 -#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD - -// Blend factors -#define GL_ZERO 0 -#define GL_ONE 1 -#define GL_SRC_COLOR 0x0300 -#define GL_ONE_MINUS_SRC_COLOR 0x0301 -#define GL_SRC_ALPHA 0x0302 -#define GL_ONE_MINUS_SRC_ALPHA 0x0303 -#define GL_DST_ALPHA 0x0304 -#define GL_ONE_MINUS_DST_ALPHA 0x0305 -#define GL_DST_COLOR 0x0306 -#define GL_ONE_MINUS_DST_COLOR 0x0307 -#define GL_SRC_ALPHA_SATURATE 0x0308 - -// Sides -#define GL_FRONT_LEFT 0x0400 -#define GL_FRONT_RIGHT 0x0401 -#define GL_BACK_LEFT 0x0402 -#define GL_BACK_RIGHT 0x0403 -#define GL_FRONT 0x0404 -#define GL_BACK 0x0405 -#define GL_LEFT 0x0406 -#define GL_RIGHT 0x0407 -#define GL_FRONT_AND_BACK 0x0408 - -// Error codes -#define GL_NO_ERROR 0 -#define GL_INVALID_ENUM 0x0500 -#define GL_INVALID_VALUE 0x0501 -#define GL_INVALID_OPERATION 0x0502 -#define GL_STACK_OVERFLOW 0x0503 -#define GL_STACK_UNDERFLOW 0x0504 -#define GL_OUT_OF_MEMORY 0x0505 -#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 - -// Triangle winding order -#define GL_CW 0x0900 -#define GL_CCW 0x0901 - -// Hint enums -#define GL_DONT_CARE 0x1100 -#define GL_FASTEST 0x1101 -#define GL_NICEST 0x1102 - -#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 -#define GL_POINT_SMOOTH_HINT 0x0C51 -#define GL_LINE_SMOOTH_HINT 0x0C52 -#define GL_POLYGON_SMOOTH_HINT 0x0C53 -#define GL_FOG_HINT 0x0C54 -#define GL_GENERATE_MIPMAP_HINT 0x8192 -#define GL_TEXTURE_COMPRESSION_HINT 0x84EF - -// Reading pixels & unpacking texture patterns -#define GL_UNPACK_SWAP_BYTES 0x0CF0 -#define GL_UNPACK_LSB_FIRST 0x0CF1 -#define GL_UNPACK_ROW_LENGTH 0x0CF2 -#define GL_UNPACK_SKIP_ROWS 0x0CF3 -#define GL_UNPACK_SKIP_PIXELS 0x0CF4 -#define GL_UNPACK_ALIGNMENT 0x0CF5 -#define GL_UNPACK_SKIP_IMAGES 0x806D -#define GL_UNPACK_IMAGE_HEIGHT 0x806E - -#define GL_PACK_SWAP_BYTES 0x0D00 -#define GL_PACK_LSB_FIRST 0x0D01 -#define GL_PACK_ROW_LENGTH 0x0D02 -#define GL_PACK_SKIP_ROWS 0x0D03 -#define GL_PACK_SKIP_PIXELS 0x0D04 -#define GL_PACK_ALIGNMENT 0x0D05 -#define GL_PACK_SKIP_IMAGES 0x806B -#define GL_PACK_IMAGE_HEIGHT 0x806C - -// Listing enums -#define GL_COMPILE 0x1300 -#define GL_COMPILE_AND_EXECUTE 0x1301 - -// Type enums -#define GL_BITMAP 0x1A00 -#define GL_BYTE 0x1400 -#define GL_UNSIGNED_BYTE 0x1401 -#define GL_SHORT 0x1402 -#define GL_UNSIGNED_SHORT 0x1403 -#define GL_INT 0x1404 -#define GL_UNSIGNED_INT 0x1405 -#define GL_FLOAT 0x1406 -#define GL_2_BYTES 0x1407 -#define GL_3_BYTES 0x1408 -#define GL_4_BYTES 0x1409 -#define GL_DOUBLE 0x140A -#define GL_HALF_FLOAT 0x140B -#define GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define GL_UNSIGNED_INT_8_8_8_8 0x8035 -#define GL_UNSIGNED_INT_10_10_10_2 0x8036 -#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 -#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 -#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#define GL_BOOL 0x8B56 - -// Format enums -#define GL_COLOR_INDEX 0x1900 -#define GL_STENCIL_INDEX 0x1901 -#define GL_DEPTH_COMPONENT 0x1902 -#define GL_RED 0x1903 -#define GL_GREEN 0x1904 -#define GL_BLUE 0x1905 -#define GL_ALPHA 0x1906 -#define GL_RGB 0x1907 -#define GL_RGBA 0x1908 -#define GL_LUMINANCE 0x1909 -#define GL_LUMINANCE8 0x8040 -#define GL_LUMINANCE_ALPHA 0x190A -#define GL_R3_G3_B2 0x2A10 -#define GL_BGR 0x80E0 -#define GL_BGRA 0x80E1 -#define GL_ALPHA4 0x803B -#define GL_ALPHA8 0x803C -#define GL_ALPHA12 0x803D -#define GL_ALPHA16 0x803E -#define GL_LUMINANCE4 0x803F -#define GL_LUMINANCE8 0x8040 -#define GL_LUMINANCE12 0x8041 -#define GL_LUMINANCE16 0x8042 -#define GL_LUMINANCE4_ALPHA4 0x8043 -#define GL_LUMINANCE6_ALPHA2 0x8044 -#define GL_LUMINANCE8_ALPHA8 0x8045 -#define GL_LUMINANCE12_ALPHA4 0x8046 -#define GL_LUMINANCE12_ALPHA12 0x8047 -#define GL_LUMINANCE16_ALPHA16 0x8048 -#define GL_INTENSITY 0x8049 -#define GL_INTENSITY4 0x804A -#define GL_INTENSITY8 0x804B -#define GL_INTENSITY12 0x804C -#define GL_INTENSITY16 0x804D -#define GL_RGB4 0x804F -#define GL_RGB5 0x8050 -#define GL_RGB8 0x8051 -#define GL_RGB10 0x8052 -#define GL_RGB12 0x8053 -#define GL_RGB16 0x8054 -#define GL_RGBA2 0x8055 -#define GL_RGBA4 0x8056 -#define GL_RGB5_A1 0x8057 -#define GL_RGBA8 0x8058 -#define GL_RGB10_A2 0x8059 -#define GL_RGBA12 0x805A -#define GL_RGBA16 0x805B -#define GL_COLOR_INDEX8_EXT 0x80E5 -#define GL_DEPTH_COMPONENT16 0x81A5 -#define GL_DEPTH_COMPONENT16_SGIX 0x81A5 -#define GL_DEPTH_COMPONENT24 0x81A6 -#define GL_DEPTH_COMPONENT24_SGIX 0x81A6 -#define GL_DEPTH_COMPONENT32 0x81A7 -#define GL_DEPTH_COMPONENT32_SGIX 0x81A7 -#define GL_RG 0x8227 -#define GL_COMPRESSED_ALPHA 0x84E9 -#define GL_COMPRESSED_ALPHA_ARB 0x84E9 -#define GL_COMPRESSED_LUMINANCE 0x84EA -#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA -#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB -#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB -#define GL_COMPRESSED_INTENSITY 0x84EC -#define GL_COMPRESSED_INTENSITY_ARB 0x84EC -#define GL_COMPRESSED_RGB 0x84ED -#define GL_COMPRESSED_RGB_ARB 0x84ED -#define GL_COMPRESSED_RGBA 0x84EE -#define GL_COMPRESSED_RGBA_ARB 0x84EE -#define GL_DEPTH_STENCIL 0x84F9 -#define GL_DEPTH_STENCIL_EXT 0x84F9 -#define GL_DEPTH_STENCIL_NV 0x84F9 -#define GL_SRGB 0x8C40 -#define GL_SRGB_EXT 0x8C40 -#define GL_SRGB8 0x8C41 -#define GL_SRGB8_EXT 0x8C41 -#define GL_SRGB_ALPHA 0x8C42 -#define GL_SRGB_ALPHA_EXT 0x8C42 -#define GL_SRGB8_ALPHA8 0x8C43 -#define GL_SRGB8_ALPHA8_EXT 0x8C43 -#define GL_SLUMINANCE_ALPHA 0x8C44 -#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 -#define GL_SLUMINANCE8_ALPHA8 0x8C45 -#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 -#define GL_SLUMINANCE 0x8C46 -#define GL_SLUMINANCE_EXT 0x8C46 -#define GL_SLUMINANCE8 0x8C47 -#define GL_SLUMINANCE8_EXT 0x8C47 - -// Lighting related defines -#define GL_LIGHTING 0x0B50 -#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 -#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 -#define GL_LIGHT_MODEL_AMBIENT 0x0B53 -#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 -#define GL_SINGLE_COLOR 0x81F9 -#define GL_SEPARATE_SPECULAR_COLOR 0x81FA - -#define GL_FLAT 0x1D00 -#define GL_SMOOTH 0x1D01 -#define GL_AMBIENT 0x1200 -#define GL_DIFFUSE 0x1201 -#define GL_SPECULAR 0x1202 -#define GL_POSITION 0x1203 -#define GL_SPOT_DIRECTION 0x1204 -#define GL_SPOT_EXPONENT 0x1205 -#define GL_SPOT_CUTOFF 0x1206 -#define GL_CONSTANT_ATTENUATION 0x1207 -#define GL_LINEAR_ATTENUATION 0x1208 -#define GL_QUADRATIC_ATTENUATION 0x1209 -#define GL_EMISSION 0x1600 -#define GL_SHININESS 0x1601 -#define GL_AMBIENT_AND_DIFFUSE 0x1602 -#define GL_COLOR_INDEXES 0x1603 - -#define GL_LIGHT0 0x4000 -#define GL_LIGHT1 0x4001 -#define GL_LIGHT2 0x4002 -#define GL_LIGHT3 0x4003 -#define GL_LIGHT4 0x4004 -#define GL_LIGHT5 0x4005 -#define GL_LIGHT6 0x4006 -#define GL_LIGHT7 0x4007 - -// Blend factors & modes -#define GL_CONSTANT_COLOR 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -#define GL_FUNC_ADD 0x8006 -#define GL_MIN 0x8007 -#define GL_MAX 0x8008 -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_FUNC_SUBTRACT 0x800A -#define GL_FUNC_REVERSE_SUBTRACT 0x800B -#define GL_BLEND_EQUATION_ALPHA 0x883D - -// Points -#define GL_POINT_SMOOTH 0x0B10 -#define GL_POINT_SIZE 0x0B11 -#define GL_POINT_SIZE_MIN_EXT 0x8126 -#define GL_POINT_SIZE_MAX_EXT 0x8127 -#define GL_DISTANCE_ATTENUATION_EXT 0x8129 - -// Polygon modes -#define GL_POINT 0x1B00 -#define GL_LINE 0x1B01 -#define GL_FILL 0x1B02 - -// Stencil buffer operations -#define GL_KEEP 0x1E00 -#define GL_REPLACE 0x1E01 -#define GL_INCR 0x1E02 -#define GL_INCR_WRAP 0x8507 -#define GL_DECR 0x1E03 -#define GL_DECR_WRAP 0x8508 -#define GL_INVERT 0x150A - -// Texture targets -#define GL_TEXTURE_1D 0x0DE0 -#define GL_TEXTURE_2D 0x0DE1 -#define GL_PROXY_TEXTURE_1D 0x8063 -#define GL_PROXY_TEXTURE_2D 0x8064 -#define GL_TEXTURE_3D 0x806F -#define GL_PROXY_TEXTURE_3D 0x8070 -#define GL_TEXTURE_CUBE_MAP 0x8513 -#define GL_TEXTURE_1D_ARRAY 0x8C18 -#define GL_TEXTURE_2D_ARRAY 0x8C1A - -// Texture parameters -#define GL_TEXTURE_WIDTH 0x1000 -#define GL_TEXTURE_HEIGHT 0x1001 - -// Texture Unit indices -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE0_ARB 0x84C0 -#define GL_TEXTURE1 0x84C1 -#define GL_TEXTURE1_ARB 0x84C1 -#define GL_TEXTURE2 0x84C2 -#define GL_TEXTURE2_ARB 0x84C2 -#define GL_TEXTURE3 0x84C3 -#define GL_TEXTURE3_ARB 0x84C3 -#define GL_TEXTURE4 0x84C4 -#define GL_TEXTURE4_ARB 0x84C4 -#define GL_TEXTURE5 0x84C5 -#define GL_TEXTURE5_ARB 0x84C5 -#define GL_TEXTURE6 0x84C6 -#define GL_TEXTURE6_ARB 0x84C6 -#define GL_TEXTURE7 0x84C7 -#define GL_TEXTURE7_ARB 0x84C7 -#define GL_TEXTURE8 0x84C8 -#define GL_TEXTURE8_ARB 0x84C8 -#define GL_TEXTURE9 0x84C9 -#define GL_TEXTURE9_ARB 0x84C9 -#define GL_TEXTURE10 0x84CA -#define GL_TEXTURE10_ARB 0x84CA -#define GL_TEXTURE11 0x84CB -#define GL_TEXTURE11_ARB 0x84CB -#define GL_TEXTURE12 0x84CC -#define GL_TEXTURE12_ARB 0x84CC -#define GL_TEXTURE13 0x84CD -#define GL_TEXTURE13_ARB 0x84CD -#define GL_TEXTURE14 0x84CE -#define GL_TEXTURE14_ARB 0x84CE -#define GL_TEXTURE15 0x84CF -#define GL_TEXTURE15_ARB 0x84CF -#define GL_TEXTURE16 0x84D0 -#define GL_TEXTURE16_ARB 0x84D0 -#define GL_TEXTURE17 0x84D1 -#define GL_TEXTURE17_ARB 0x84D1 -#define GL_TEXTURE18 0x84D2 -#define GL_TEXTURE18_ARB 0x84D2 -#define GL_TEXTURE19 0x84D3 -#define GL_TEXTURE19_ARB 0x84D3 -#define GL_TEXTURE20 0x84D4 -#define GL_TEXTURE20_ARB 0x84D4 -#define GL_TEXTURE21 0x84D5 -#define GL_TEXTURE21_ARB 0x84D5 -#define GL_TEXTURE22 0x84D6 -#define GL_TEXTURE22_ARB 0x84D6 -#define GL_TEXTURE23 0x84D7 -#define GL_TEXTURE23_ARB 0x84D7 -#define GL_TEXTURE24 0x84D8 -#define GL_TEXTURE24_ARB 0x84D8 -#define GL_TEXTURE25 0x84D9 -#define GL_TEXTURE25_ARB 0x84D9 -#define GL_TEXTURE26 0x84DA -#define GL_TEXTURE26_ARB 0x84DA -#define GL_TEXTURE27 0x84DB -#define GL_TEXTURE27_ARB 0x84DB -#define GL_TEXTURE28 0x84DC -#define GL_TEXTURE28_ARB 0x84DC -#define GL_TEXTURE29 0x84DD -#define GL_TEXTURE29_ARB 0x84DD -#define GL_TEXTURE30 0x84DE -#define GL_TEXTURE30_ARB 0x84DE -#define GL_TEXTURE31 0x84DF -#define GL_TEXTURE31_ARB 0x84DF - -// Texture coord names -#define GL_S 0x2000 -#define GL_T 0x2001 -#define GL_R 0x2002 -#define GL_Q 0x2003 - -// Texture Environment and Parameters -#define GL_ADD 0x0104 -#define GL_ALPHA_SCALE 0x0D1C -#define GL_MODULATE 0x2100 -#define GL_DECAL 0x2101 -#define GL_TEXTURE_ENV_MODE 0x2200 -#define GL_TEXTURE_ENV_COLOR 0x2201 -#define GL_TEXTURE_ENV 0x2300 -#define GL_NEAREST 0x2600 -#define GL_LINEAR 0x2601 -#define GL_NEAREST_MIPMAP_NEAREST 0x2700 -#define GL_LINEAR_MIPMAP_NEAREST 0x2701 -#define GL_NEAREST_MIPMAP_LINEAR 0x2702 -#define GL_LINEAR_MIPMAP_LINEAR 0x2703 -#define GL_TEXTURE_MAG_FILTER 0x2800 -#define GL_TEXTURE_MIN_FILTER 0x2801 -#define GL_TEXTURE_WRAP_S 0x2802 -#define GL_TEXTURE_WRAP_T 0x2803 -#define GL_CLAMP 0x2900 -#define GL_REPEAT 0x2901 -#define GL_CLAMP_TO_BORDER 0x812D -#define GL_CLAMP_TO_EDGE 0x812F -#define GL_GENERATE_MIPMAP 0x8191 -#define GL_MIRRORED_REPEAT 0x8370 -#define GL_SUBTRACT 0x84E7 -#define GL_TEXTURE_FILTER_CONTROL 0x8500 -#define GL_TEXTURE_LOD_BIAS 0x8501 -#define GL_COMBINE 0x8570 -#define GL_COMBINE_RGB 0x8571 -#define GL_COMBINE_ALPHA 0x8572 -#define GL_RGB_SCALE 0x8573 -#define GL_ADD_SIGNED 0x8574 -#define GL_INTERPOLATE 0x8575 -#define GL_CONSTANT 0x8576 -#define GL_PRIMARY_COLOR 0x8577 -#define GL_PREVIOUS 0x8578 -#define GL_SRC0_RGB 0x8580 -#define GL_SOURCE0_RGB 0x8580 -#define GL_SRC1_RGB 0x8581 -#define GL_SOURCE1_RGB 0x8581 -#define GL_SRC2_RGB 0x8582 -#define GL_SOURCE2_RGB 0x8582 -#define GL_SRC0_ALPHA 0x8588 -#define GL_SOURCE0_ALPHA 0x8588 -#define GL_SRC1_ALPHA 0x8589 -#define GL_SOURCE1_ALPHA 0x8589 -#define GL_SRC2_ALPHA 0x858A -#define GL_SOURCE2_ALPHA 0x858A -#define GL_OPERAND0_RGB 0x8590 -#define GL_OPERAND1_RGB 0x8591 -#define GL_OPERAND2_RGB 0x8592 -#define GL_OPERAND0_ALPHA 0x8598 -#define GL_OPERAND1_ALPHA 0x8599 -#define GL_OPERAND2_ALPHA 0x859A -#define GL_DOT3_RGB 0x86AE -#define GL_DOT3_RGBA 0x86AF - -// Texture gen modes -#define GL_EYE_LINEAR 0x2400 -#define GL_OBJECT_LINEAR 0x2401 -#define GL_SPHERE_MAP 0x2402 -#define GL_NORMAL_MAP 0x8511 -#define GL_REFLECTION_MAP 0x8512 - -// Texture gen parameters -#define GL_TEXTURE_BORDER_COLOR 0x1004 -#define GL_TEXTURE_GEN_MODE 0x2500 -#define GL_OBJECT_PLANE 0x2501 -#define GL_EYE_PLANE 0x2502 - -// Client state capabilities -#define GL_VERTEX_ARRAY 0x8074 -#define GL_COLOR_ARRAY 0x8076 -#define GL_TEXTURE_COORD_ARRAY 0x8078 - -// Fog parameters -#define GL_EXP 0x0800 -#define GL_EXP2 0x0801 -#define GL_FOG_MODE 0x0B65 -#define GL_FOG_COLOR 0x0B66 -#define GL_FOG_DENSITY 0x0B62 - -// Scissor enums -#define GL_SCISSOR_BOX 0x0C10 -#define GL_SCISSOR_TEST 0x0C11 - -// OpenGL State & GLGet -#define GL_MODELVIEW_MATRIX 0x0BA6 -#define GL_PROJECTION_MATRIX 0x0BA7 - -// User clipping planes -#define GL_MAX_CLIP_PLANES 0x0D32 -#define GL_CLIP_PLANE0 0x3000 -#define GL_CLIP_PLANE1 0x3001 -#define GL_CLIP_PLANE2 0x3002 -#define GL_CLIP_PLANE3 0x3003 -#define GL_CLIP_PLANE4 0x3004 -#define GL_CLIP_PLANE5 0x3005 - -// Buffer objects -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 - -#define GL_STREAM_DRAW 0x88e0 -#define GL_STREAM_READ 0x88e1 -#define GL_STREAM_COPY 0x88e2 -#define GL_STATIC_DRAW 0x88e4 -#define GL_STATIC_READ 0x88e5 -#define GL_STATIC_COPY 0x88e6 -#define GL_DYNAMIC_DRAW 0x88e8 -#define GL_DYNAMIC_READ 0x88e9 -#define GL_DYNAMIC_COPY 0x88ea -// Programmable pipeline -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_SHADER_TYPE 0x8B4F -#define GL_DELETE_STATUS 0x8B80 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_LINK_STATUS 0x8B82 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 - -#ifdef __cplusplus -} -#endif diff --git a/Userland/Libraries/LibGL/GL/glext.h b/Userland/Libraries/LibGL/GL/glext.h deleted file mode 100644 index ce6698ee38c..00000000000 --- a/Userland/Libraries/LibGL/GL/glext.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2021, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -#define GL_GLEXT_VERSION 20211115 - -typedef void(APIENTRYP PFNGLLOCKARRAYSEXTPROC)(GLint first, GLsizei count); -typedef void(APIENTRYP PFNGLUNLOCKARRAYSEXTPROC)(void); diff --git a/Userland/Libraries/LibGL/GL/glplatform.h b/Userland/Libraries/LibGL/GL/glplatform.h deleted file mode 100644 index 1fd509bcca1..00000000000 --- a/Userland/Libraries/LibGL/GL/glplatform.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2021-2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#ifndef GLAPI -# define GLAPI extern -#endif -#define GLAPIENTRY -#define APIENTRY GLAPIENTRY -#ifndef APIENTRYP -# define APIENTRYP APIENTRY* -#endif - -// -// OpenGL typedefs -// -// Defines types used by all OpenGL applications -// https://www.khronos.org/opengl/wiki/OpenGL_Type -typedef char GLchar; -typedef signed char GLbyte; -typedef unsigned char GLuchar; -typedef unsigned char GLubyte; -typedef unsigned char GLboolean; -typedef short GLshort; -typedef unsigned short GLushort; -typedef int GLint; -typedef long GLint64; -typedef long GLintptr; -typedef unsigned int GLuint; -typedef unsigned long GLuint64; -typedef int GLfixed; -typedef int GLsizei; -typedef long GLsizeiptr; -typedef void GLvoid; -typedef float GLfloat; -typedef double GLclampd; -typedef float GLclampf; -typedef double GLdouble; -typedef unsigned int GLenum; -typedef unsigned int GLbitfield; diff --git a/Userland/Libraries/LibGL/GLAPI.json b/Userland/Libraries/LibGL/GLAPI.json deleted file mode 100644 index 216b8ddbdf9..00000000000 --- a/Userland/Libraries/LibGL/GLAPI.json +++ /dev/null @@ -1,1246 +0,0 @@ -{ - "ActiveTexture": { - "arguments": [ - {"type": "GLenum", "name": "texture"} - ], - "variants": { - "api_suffixes": ["", "ARB"] - } - }, - "AlphaFunc": { - "arguments": [ - {"type": "GLenum", "name": "func"}, - {"type": "GLclampf", "name": "ref"} - ] - }, - "ArrayElement": { - "arguments": [ - {"type": "GLint", "name": "i"} - ] - }, - "AttachShader": { - "arguments": [ - {"type": "GLuint", "name": "program"}, - {"type": "GLuint", "name": "shader"} - ] - }, - "Begin": { - "arguments": [ - {"type": "GLenum", "name": "mode"} - ] - }, - "BindBuffer": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLuint", "name": "buffer"} - ] - }, - "BindTexture": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLuint", "name": "texture"} - ] - }, - "Bitmap": { - "arguments": [ - {"type": "GLsizei", "name": ["width", "height"]}, - {"type": "GLfloat", "name": ["xorig", "yorig", "xmove", "ymove"]}, - {"type": "GLubyte const*", "name": "bitmap"} - ] - }, - "BlendColor": { - "arguments": [ - {"type": "GLclampf", "name": ["red", "green", "blue", "alpha"]} - ] - }, - "BlendEquation": { - "arguments": [ - {"type": "GLenum", "name": "mode"}, - {"expression": "mode"} - ], - "implementation": "blend_equation_separate" - }, - "BlendEquationSeparate": { - "arguments": [ - {"type": "GLenum", "name": ["modeRGB", "modeAlpha"]} - ] - }, - "BlendFunc": { - "arguments": [ - {"type": "GLenum", "name": ["sfactor", "dfactor"]} - ] - }, - "BufferData": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLsizeiptr", "name": "size"}, - {"type": "void const*", "name": "data"}, - {"type": "GLenum", "name": "usage"} - ] - }, - "BufferSubData": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLintptr", "name": "offset"}, - {"type": "GLsizeiptr", "name": "size"}, - {"type": "void const*", "name": "data"} - ] - }, - "CallList": { - "arguments": [ - {"type": "GLuint", "name": "list"} - ] - }, - "CallLists": { - "arguments": [ - {"type": "GLsizei", "name": "n"}, - {"type": "GLenum", "name": "type"}, - {"type": "void const*", "name": "lists"} - ] - }, - "Clear": { - "arguments": [ - {"type": "GLbitfield", "name": "mask"} - ] - }, - "ClearColor": { - "arguments": [ - {"type": "GLclampf", "name": ["red", "green", "blue", "alpha"]} - ] - }, - "ClearDepth": { - "arguments": [ - {"type": "GLdouble", "name": "depth", "cast_to": "GLfloat"} - ] - }, - "ClearDepthf": { - "arguments": [ - {"type": "GLfloat", "name": "depth"} - ], - "implementation": "clear_depth" - }, - "ClearStencil": { - "arguments": [ - {"type": "GLint", "name": "s"} - ] - }, - "ClientActiveTexture": { - "arguments": [ - {"type": "GLenum", "name": "target"} - ], - "variants": { - "api_suffixes": ["", "ARB"] - } - }, - "ClipPlane": { - "arguments": [ - {"type": "GLenum", "name": "plane"}, - {"type": "GLdouble const*", "name": "equation"} - ] - }, - "Color": { - "arguments": [ - {"name": ["red", "green", "blue", "alpha"], "cast_to": "GLfloat"} - ], - "variants": { - "argument_counts": [3, 4], - "argument_defaults": ["0.f", "0.f", "0.f", "1.f"], - "convert_range": true, - "pointer_argument": "v", - "types": { - "b": {}, - "bv": {}, - "d": {}, - "dv": {}, - "f": {}, - "fv": {}, - "i": {}, - "iv": {}, - "s": {}, - "sv": {}, - "ub": {}, - "ubv": {}, - "ui": {}, - "uiv": {}, - "us": {}, - "usv": {} - } - } - }, - "ColorMask": { - "arguments": [ - {"type": "GLboolean", "name": ["red", "green", "blue", "alpha"]} - ] - }, - "ColorMaterial": { - "arguments": [ - {"type": "GLenum", "name": "face"}, - {"type": "GLenum", "name": "mode"} - ] - }, - "ColorPointer": { - "arguments": [ - {"type": "GLint", "name": "size"}, - {"type": "GLenum", "name": "type"}, - {"type": "GLsizei", "name": "stride"}, - {"type": "void const*", "name": "pointer"} - ] - }, - "CompileShader": { - "arguments": [ - {"type": "GLuint", "name": "shader"} - ] - }, - "CopyTexImage2D": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLint", "name": "level"}, - {"type": "GLenum", "name": "internalformat"}, - {"type": "GLint", "name": ["x", "y"]}, - {"type": "GLsizei", "name": ["width", "height"]}, - {"type": "GLint", "name": "border"} - ], - "implementation": "copy_tex_image_2d" - }, - "CopyTexSubImage2D": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLint", "name": ["level", "xoffset", "yoffset", "x", "y"]}, - {"type": "GLsizei", "name": ["width", "height"]} - ], - "implementation": "copy_tex_sub_image_2d" - }, - "CreateProgram": { - "return_type": "GLuint" - }, - "CreateShader": { - "arguments": [ - {"type": "GLenum", "name": "shader_type"} - ], - "return_type": "GLuint" - }, - "CullFace": { - "arguments": [ - {"type": "GLenum", "name": "mode"} - ] - }, - "DeleteBuffers": { - "arguments": [ - {"type": "GLsizei", "name": "n"}, - {"type": "GLuint const*", "name": "buffers"} - ] - }, - "DeleteLists": { - "arguments": [ - {"type": "GLuint", "name": "list"}, - {"type": "GLsizei", "name": "range"} - ] - }, - "DeleteProgram": { - "arguments": [ - {"type": "GLuint", "name": "program"} - ] - }, - "DeleteShader": { - "arguments": [ - {"type": "GLuint", "name": "shader"} - ] - }, - "DeleteTextures": { - "arguments": [ - {"type": "GLsizei", "name": "n"}, - {"type": "GLuint const*", "name": "textures"} - ] - }, - "DepthFunc": { - "arguments": [ - {"type": "GLenum", "name": "func"} - ] - }, - "DepthMask": { - "arguments": [ - {"type": "GLboolean", "name": "flag"} - ] - }, - "DepthRange": { - "arguments": [ - {"type": "GLdouble", "name": ["nearVal", "farVal"]} - ] - }, - "DepthRangef": { - "arguments": [ - {"type": "GLfloat", "name": ["nearVal", "farVal"], "cast_to": "GLdouble"} - ], - "implementation": "depth_range" - }, - "Disable": { - "arguments": [ - {"type": "GLenum", "name": "cap"} - ] - }, - "DisableClientState": { - "arguments": [ - {"type": "GLenum", "name": "cap"} - ] - }, - "DrawArrays": { - "arguments": [ - {"type": "GLenum", "name": "mode"}, - {"type": "GLint", "name": "first"}, - {"type": "GLsizei", "name": "count"} - ] - }, - "DrawBuffer": { - "arguments": [ - {"type": "GLenum", "name": "buffer"} - ] - }, - "DrawElements": { - "arguments": [ - {"type": "GLenum", "name": "mode"}, - {"type": "GLsizei", "name": "count"}, - {"type": "GLenum", "name": "type"}, - {"type": "void const*", "name": "indices"} - ] - }, - "DrawPixels": { - "arguments": [ - {"type": "GLsizei", "name": ["width", "height"]}, - {"type": "GLenum", "name": ["format", "type"]}, - {"type": "void const*", "name": "data"} - ] - }, - "Enable": { - "arguments": [ - {"type": "GLenum", "name": "cap"} - ] - }, - "EnableClientState": { - "arguments": [ - {"type": "GLenum", "name": "cap"} - ] - }, - "End": {}, - "EndList": {}, - "EvalCoord": { - "arguments": [ - {"name": ["u", "v"]} - ], - "unimplemented": true, - "variants": { - "argument_counts": [1, 2], - "argument_defaults": ["0.", "0."], - "pointer_argument": "u", - "types": { - "d": {}, - "dv": {}, - "f": {}, - "fv": {} - } - } - }, - "EvalMesh1": { - "arguments": [ - {"type": "GLenum", "name": "mode"}, - {"type": "GLint", "name": ["i1", "i2"]} - ], - "unimplemented": true - }, - "EvalMesh2": { - "arguments": [ - {"type": "GLenum", "name": "mode"}, - {"type": "GLint", "name": ["i1", "i2", "j1", "j2"]} - ], - "unimplemented": true - }, - "EvalPoint": { - "arguments": [ - {"name": ["i", "j"]} - ], - "unimplemented": true, - "variants": { - "argument_counts": [1, 2], - "argument_defaults": ["0", "0"], - "types": { - "i": {} - } - } - }, - "Finish": {}, - "Flush": {}, - "Fog": { - "arguments": [ - {"type": "GLenum", "name": "pname"}, - {"name": "param"} - ], - "variants": { - "argument_counts": [1], - "pointer_argument": "params", - "types": { - "f": {"implementation": "fogf"}, - "fv": {"implementation": "fogfv"}, - "i": {"implementation": "fogi"}, - "iv": {"unimplemented": true} - } - } - }, - "FrontFace": { - "arguments": [ - {"type": "GLenum", "name": "mode"} - ] - }, - "Frustum": { - "arguments": [ - {"type": "GLdouble", "name": ["left", "right", "bottom", "top", "nearVal", "farVal"]} - ] - }, - "GenBuffers": { - "arguments": [ - {"type": "GLsizei", "name": "n"}, - {"type": "GLuint*", "name": "buffers"} - ] - }, - "GenLists": { - "arguments": [ - {"type": "GLsizei", "name": "range"} - ], - "return_type": "GLuint" - }, - "GenTextures": { - "arguments": [ - {"type": "GLsizei", "name": "n"}, - {"type": "GLuint*", "name": "textures"} - ] - }, - "GetBooleanv": { - "arguments": [ - {"type": "GLenum", "name": "pname"}, - {"type": "GLboolean*", "name": "data"} - ] - }, - "GetClipPlane": { - "arguments": [ - {"type": "GLenum", "name": "plane"}, - {"type": "GLdouble*", "name": "equation"} - ] - }, - "GetDoublev": { - "arguments": [ - {"type": "GLenum", "name": "pname"}, - {"type": "GLdouble*", "name": "data"} - ] - }, - "GetError": { - "return_type": "GLenum" - }, - "GetFloatv": { - "arguments": [ - {"type": "GLenum", "name": "pname"}, - {"type": "GLfloat*", "name": "data"} - ] - }, - "GetIntegerv": { - "arguments": [ - {"type": "GLenum", "name": "pname"}, - {"type": "GLint*", "name": "data"} - ] - }, - "GetLight": { - "arguments": [ - {"type": "GLenum", "name": "light"}, - {"type": "GLenum", "name": "pname"}, - {"name": "params"}, - {"type": "GLenum", "expression": "@variant_gl_type@"} - ], - "variants": { - "argument_counts": [1], - "pointer_argument": "params", - "types": { - "fv!": {}, - "iv!": {} - } - } - }, - "GetMaterial": { - "arguments": [ - {"type": "GLenum", "name": "face"}, - {"type": "GLenum", "name": "pname"}, - {"name": "params"}, - {"type": "GLenum", "expression": "@variant_gl_type@"} - ], - "variants": { - "argument_counts": [1], - "pointer_argument": "params", - "types": { - "fv!": {}, - "iv!": {} - } - } - }, - "GetProgramiv": { - "arguments": [ - {"type": "GLuint", "name": "program"}, - {"type": "GLenum", "name": "pname"}, - {"type": "GLint*", "name": "params"} - ], - "implementation": "get_program" - }, - "GetShaderInfoLog": { - "arguments": [ - {"type": "GLuint", "name": "shader"}, - {"type": "GLsizei", "name": "maxLength"}, - {"type": "GLsizei*", "name": "length"}, - {"type": "GLchar*", "name": "infoLog"} - ], - "unimplemented": true - }, - "GetShaderiv": { - "arguments": [ - {"type": "GLuint", "name": "shader"}, - {"type": "GLenum", "name": "pname"}, - {"type": "GLint*", "name": "params"} - ], - "implementation": "get_shader" - }, - "GetString": { - "arguments": [ - {"type": "GLenum", "name": "name"} - ], - "return_type": "GLubyte const*" - }, - "GetTexImage": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLint", "name": "level"}, - {"type": "GLenum", "name": ["format", "type"]}, - {"type": "void*", "name": "pixels"} - ] - }, - "GetTexLevelParameter": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLint", "name": "level"}, - {"type": "GLenum", "name": "pname"}, - {"name": "params"} - ], - "variants": { - "argument_counts": [1], - "pointer_argument": "params", - "types": { - "fv!": {"unimplemented": true}, - "iv!": {"implementation": "get_tex_parameter_integerv"} - } - } - }, - "GetUniformLocation": { - "arguments": [ - {"type": "GLuint", "name": "program"}, - {"type": "GLchar const*", "name": "name"} - ], - "unimplemented": true - }, - "Hint": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLenum", "name": "mode"} - ] - }, - "IsEnabled": { - "arguments": [ - {"type": "GLenum", "name": "cap"} - ], - "return_type": "GLboolean" - }, - "IsList": { - "arguments": [ - {"type": "GLuint", "name": "list"} - ], - "return_type": "GLboolean" - }, - "IsTexture": { - "arguments": [ - {"type": "GLuint", "name": "texture"} - ], - "return_type": "GLboolean" - }, - "Light": { - "arguments": [ - {"type": "GLenum", "name": "light"}, - {"type": "GLenum", "name": "pname"}, - {"name": "param", "cast_to": "GLfloat"} - ], - "variants": { - "argument_counts": [1], - "pointer_argument": "params", - "types": { - "f": {}, - "fv": {"implementation": "lightfv"}, - "i": {}, - "iv": {"implementation": "lightiv"}, - "x": {}, - "xv": {"implementation": "lightiv"} - } - }, - "implementation": "lightf" - }, - "LightModel": { - "arguments": [ - {"type": "GLenum", "name": "pname"}, - {"name": "param"}, - {"name": ["y", "z", "w"]} - ], - "variants": { - "argument_counts": [1], - "argument_defaults": ["0.f", "0.f", "0.f", "0.f"], - "types": { - "f": {}, - "i": {} - } - } - }, - "LightModel_v": { - "arguments": [ - {"type": "GLenum", "name": "pname"}, - {"name": "param"}, - {"type": "GLenum", "expression": "@variant_gl_type@"} - ], - "implementation": "light_modelv", - "name": "LightModel", - "variants": { - "argument_counts": [1], - "pointer_argument": "params", - "types": { - "fv": {}, - "iv": {} - } - } - }, - "LineWidth": { - "arguments": [ - {"type": "GLfloat", "name": "width"} - ] - }, - "LinkProgram": { - "arguments": [ - {"type": "GLuint", "name": "program"} - ] - }, - "ListBase": { - "arguments": [ - {"type": "GLuint", "name": "base"} - ] - }, - "LoadIdentity": {}, - "LoadMatrixd": { - "arguments": [ - {"type": "GLdouble const*", "name": "m", "expression": "GL::transpose_input_matrix(@argument_name@)"} - ], - "implementation": "load_matrix" - }, - "LoadMatrixf": { - "arguments": [ - {"type": "GLfloat const*", "name": "m", "expression": "GL::transpose_input_matrix(@argument_name@)"} - ], - "implementation": "load_matrix" - }, - "Map1d": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLdouble","name": ["u1", "u2"]}, - {"type": "GLint", "name": ["stride", "order"]}, - {"type": "GLdouble const*", "name": "points"} - ], - "unimplemented": true - }, - "Map1f": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLfloat","name": ["u1", "u2"]}, - {"type": "GLint", "name": ["stride", "order"]}, - {"type": "GLfloat const*", "name": "points"} - ], - "unimplemented": true - }, - "Map2d": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLdouble","name": ["u1", "u2"]}, - {"type": "GLint", "name": ["ustride", "uorder"]}, - {"type": "GLdouble","name": ["v1", "v2"]}, - {"type": "GLint", "name": ["vstride", "vorder"]}, - {"type": "GLdouble const*", "name": "points"} - ], - "unimplemented": true - }, - "Map2f": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLfloat","name": ["u1", "u2"]}, - {"type": "GLint", "name": ["ustride", "uorder"]}, - {"type": "GLfloat","name": ["v1", "v2"]}, - {"type": "GLint", "name": ["vstride", "vorder"]}, - {"type": "GLfloat const*", "name": "points"} - ], - "unimplemented": true - }, - "MapGrid1": { - "arguments": [ - {"type": "GLint", "name": "un"}, - {"name": ["u1", "u2"]} - ], - "unimplemented": true, - "variants": { - "types": { - "d": {}, - "f": {} - } - } - }, - "MapGrid2": { - "arguments": [ - {"type": "GLint", "name": "un"}, - {"name": ["u1", "u2"]}, - {"type": "GLint", "name": "vn"}, - {"name": ["v1", "v2"]} - ], - "unimplemented": true, - "variants": { - "types": { - "d": {}, - "f": {} - } - } - }, - "Material": { - "arguments": [ - {"type": "GLenum", "name": "face"}, - {"type": "GLenum", "name": "pname"}, - {"name": "param", "cast_to": "GLfloat"} - ], - "implementation": "materialf", - "variants": { - "argument_counts": [1], - "pointer_argument": "params", - "types": { - "f": {}, - "fv": { - "implementation": "materialfv" - }, - "i": {}, - "iv": { - "implementation": "materialiv" - } - } - } - }, - "MatrixMode": { - "arguments": [ - {"type": "GLenum", "name": "mode"} - ] - }, - "MultiTexCoord": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"name": ["s", "t", "r", "q"], "cast_to": "GLfloat"} - ], - "variants": { - "api_suffixes": ["", "ARB"], - "argument_counts": [1, 2, 3, 4], - "argument_defaults": ["0.f", "0.f", "0.f", "1.f"], - "pointer_argument": "v", - "types": { - "d": {}, - "dv": {}, - "f": {}, - "fv": {}, - "i": {}, - "iv": {}, - "s": {}, - "sv": {} - } - } - }, - "MultMatrixd": { - "arguments": [ - {"type": "GLdouble const*", "name": "m", "expression": "GL::transpose_input_matrix(@argument_name@)"} - ], - "implementation": "mult_matrix" - }, - "MultMatrixf": { - "arguments": [ - {"type": "GLfloat const*", "name": "m", "expression": "GL::transpose_input_matrix(@argument_name@)"} - ], - "implementation": "mult_matrix" - }, - "NewList": { - "arguments": [ - {"type": "GLuint", "name": "list"}, - {"type": "GLenum", "name": "mode"} - ] - }, - "Normal3": { - "arguments": [ - {"name": ["nx", "ny", "nz"], "cast_to": "GLfloat"} - ], - "implementation": "normal", - "variants": { - "convert_range": true, - "pointer_argument": "v", - "types": { - "b": {}, - "bv": {}, - "d": {}, - "dv": {}, - "f": {}, - "fv": {}, - "i": {}, - "iv": {}, - "s": {}, - "sv": {} - } - } - }, - "NormalPointer": { - "arguments": [ - {"type": "GLenum", "name": "type"}, - {"type": "GLsizei", "name": "stride"}, - {"type": "void const*", "name": "pointer"} - ] - }, - "Ortho": { - "arguments": [ - {"type": "GLdouble", "name": ["left", "right", "bottom", "top", "nearVal", "farVal"]} - ] - }, - "PixelStore": { - "arguments": [ - {"type": "GLenum", "name": "pname"}, - {"name": "param", "cast_to": "GLint"} - ], - "implementation": "pixel_storei", - "variants": { - "types": { - "f": {}, - "i": {} - } - } - }, - "PointSize": { - "arguments": [ - {"type": "GLfloat", "name": "size"} - ] - }, - "PolygonMode": { - "arguments": [ - {"type": "GLenum", "name": ["face", "mode"]} - ] - }, - "PolygonOffset": { - "arguments": [ - {"type": "GLfloat", "name": ["factor", "units"]} - ] - }, - "PopAttrib": {}, - "PopMatrix": {}, - "PushAttrib": { - "arguments": [ - {"type": "GLbitfield", "name": "mask"} - ] - }, - "PushMatrix": {}, - "RasterPos": { - "arguments": [ - {"name": ["x", "y", "z", "w"], "cast_to": "GLfloat"} - ], - "variants": { - "argument_counts": [2, 3, 4], - "argument_defaults": ["0.f", "0.f", "0.f", "1.f"], - "pointer_argument": "v", - "types": { - "d": {}, - "dv": {}, - "f": {}, - "fv": {}, - "i": {}, - "iv": {}, - "s": {}, - "sv": {} - } - } - }, - "ReadBuffer": { - "arguments": [ - {"type": "GLenum", "name": "mode"} - ] - }, - "ReadPixels": { - "arguments": [ - {"type": "GLint", "name": "x"}, - {"type": "GLint", "name": "y"}, - {"type": "GLsizei", "name": "width"}, - {"type": "GLsizei", "name": "height"}, - {"type": "GLenum", "name": "format"}, - {"type": "GLenum", "name": "type"}, - {"type": "void*", "name": "data"} - ] - }, - "Rect": { - "arguments": [ - {"name": ["x1", "y1", "x2", "y2"], "cast_to": "GLdouble"} - ], - "variants": { - "types": { - "d": {}, - "f": {}, - "i": {}, - "s": {} - } - } - }, - "Rotate": { - "arguments": [ - {"name": ["angle", "x", "y", "z"], "cast_to": "GLfloat"} - ], - "variants": { - "types": { - "d": {}, - "f": {} - } - } - }, - "Scale": { - "arguments": [ - {"name": ["x", "y", "z"], "cast_to": "GLfloat"} - ], - "variants": { - "types": { - "d": {}, - "f": {} - } - } - }, - "Scissor": { - "arguments": [ - {"type": "GLint", "name": ["x", "y"]}, - {"type": "GLsizei", "name": ["width", "height"]} - ] - }, - "ShadeModel": { - "arguments": [ - {"type": "GLenum", "name": "mode"} - ] - }, - "ShaderSource": { - "arguments": [ - {"type": "GLuint", "name": "shader"}, - {"type": "GLsizei", "name": "count"}, - {"type": "GLchar const**", "name": "string"}, - {"type": "GLint const*", "name": "length"} - ] - }, - "StencilFunc": { - "arguments": [ - {"expression": "GL_FRONT_AND_BACK"}, - {"type": "GLenum", "name": "func"}, - {"type": "GLint", "name": "ref"}, - {"type": "GLuint", "name": "mask"} - ], - "implementation": "stencil_func_separate" - }, - "StencilFuncSeparate": { - "arguments": [ - {"type": "GLenum", "name": ["face", "func"]}, - {"type": "GLint", "name": "ref"}, - {"type": "GLuint", "name": "mask"} - ] - }, - "StencilMask": { - "arguments": [ - {"expression": "GL_FRONT_AND_BACK"}, - {"type": "GLuint", "name": "mask"} - ], - "implementation": "stencil_mask_separate" - }, - "StencilMaskSeparate": { - "arguments": [ - {"type": "GLenum", "name": "face"}, - {"type": "GLuint", "name": "mask"} - ] - }, - "StencilOp": { - "arguments": [ - {"expression": "GL_FRONT_AND_BACK"}, - {"type": "GLenum", "name": ["sfail", "dpfail", "dppass"]} - ], - "implementation": "stencil_op_separate" - }, - "StencilOpSeparate": { - "arguments": [ - {"type": "GLenum", "name": ["face", "sfail", "dpfail", "dppass"]} - ] - }, - "TexCoord": { - "arguments": [ - {"name": ["s", "t", "r", "q"], "cast_to": "GLfloat"} - ], - "variants": { - "argument_counts": [1, 2, 3, 4], - "argument_defaults": ["0.f", "0.f", "0.f", "1.f"], - "pointer_argument": "v", - "types": { - "d": {}, - "dv": {}, - "f": {}, - "fv": {}, - "i": {}, - "iv": {}, - "s": {}, - "sv": {} - } - } - }, - "TexCoordPointer": { - "arguments": [ - {"type": "GLint", "name": "size"}, - {"type": "GLenum", "name": "type"}, - {"type": "GLsizei", "name": "stride"}, - {"type": "void const*", "name": "pointer"} - ] - }, - "TexEnv": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLenum", "name": "pname"}, - {"name": "param"}, - {"type": "GLenum", "expression": "@variant_gl_type@"} - ], - "implementation": "tex_envv", - "variants": { - "argument_counts": [1], - "pointer_argument": "params", - "types": { - "fv": {}, - "iv": {} - } - } - }, - "TexEnvf": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLenum", "name": "pname"}, - {"type": "GLfloat", "name": "x", "expression": "{@argument_name@, 0.f, 0.f, 0.f}"} - ], - "implementation": "tex_env" - }, - "TexEnvi": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLenum", "name": "pname"}, - {"type": "GLint", "name": "x", "expression": "{static_cast(@argument_name@), 0.f, 0.f, 0.f}"} - ], - "implementation": "tex_env" - }, - "TexGen": { - "arguments": [ - {"type": "GLenum", "name": "coord"}, - {"type": "GLenum", "name": "pname"}, - {"name": "param", "cast_to": "GLint"} - ], - "variants": { - "argument_counts": [1], - "pointer_argument": "params", - "types": { - "d": {}, - "dv": {"unimplemented": true}, - "f": {}, - "fv": {"implementation": "tex_gen_floatv"}, - "i": {}, - "iv": {"unimplemented": true} - } - } - }, - "TexImage1D": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLint", "name": "level"}, - {"type": "GLint", "name": "internalFormat"}, - {"type": "GLsizei", "name": "width"}, - {"type": "GLint", "name": "border"}, - {"type": "GLenum", "name": "format"}, - {"type": "GLenum", "name": "type"}, - {"type": "void const*", "name": "data"} - ], - "unimplemented": true - }, - "TexImage2D": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLint", "name": "level"}, - {"type": "GLint", "name": "internalFormat"}, - {"type": "GLsizei", "name": "width"}, - {"type": "GLsizei", "name": "height"}, - {"type": "GLint", "name": "border"}, - {"type": "GLenum", "name": "format"}, - {"type": "GLenum", "name": "type"}, - {"type": "void const*", "name": "data"} - ], - "implementation": "tex_image_2d" - }, - "TexImage3D": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLint", "name": "level"}, - {"type": "GLint", "name": "internalFormat"}, - {"type": "GLsizei", "name": "width"}, - {"type": "GLsizei", "name": "height"}, - {"type": "GLsizei", "name": "depth"}, - {"type": "GLint", "name": "border"}, - {"type": "GLenum", "name": "format"}, - {"type": "GLenum", "name": "type"}, - {"type": "void const*", "name": "data"} - ], - "unimplemented": true - }, - "TexParameter": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLenum", "name": "pname"}, - {"name": "param"} - ], - "variants": { - "pointer_argument": "params", - "types": { - "f": {}, - "fv": {"unimplemented": true}, - "i": {}, - "iv": {"unimplemented": true} - } - } - }, - "TexSubImage1D": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLint", "name": "level"}, - {"type": "GLint", "name": "xoffset"}, - {"type": "GLsizei", "name": "width"}, - {"type": "GLenum", "name": "format"}, - {"type": "GLenum", "name": "type"}, - {"type": "void const*", "name": "pixels"} - ], - "unimplemented": true - }, - "TexSubImage2D": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLint", "name": "level"}, - {"type": "GLint", "name": "xoffset"}, - {"type": "GLint", "name": "yoffset"}, - {"type": "GLsizei", "name": "width"}, - {"type": "GLsizei", "name": "height"}, - {"type": "GLenum", "name": "format"}, - {"type": "GLenum", "name": "type"}, - {"type": "void const*", "name": "pixels"} - ], - "implementation": "tex_sub_image_2d" - }, - "TexSubImage3D": { - "arguments": [ - {"type": "GLenum", "name": "target"}, - {"type": "GLint", "name": "level"}, - {"type": "GLint", "name": "xoffset"}, - {"type": "GLint", "name": "yoffset"}, - {"type": "GLint", "name": "zoffset"}, - {"type": "GLsizei", "name": "width"}, - {"type": "GLsizei", "name": "height"}, - {"type": "GLsizei", "name": "depth"}, - {"type": "GLenum", "name": "format"}, - {"type": "GLenum", "name": "type"}, - {"type": "void const*", "name": "pixels"} - ], - "unimplemented": true - }, - "Translate": { - "arguments": [ - {"name": ["x", "y", "z"], "cast_to": "GLfloat"} - ], - "variants": { - "types": { - "d": {}, - "f": {} - } - } - }, - "Uniform": { - "arguments": [ - {"type": "GLint", "name": "location"}, - {"name": ["v0", "v1", "v2", "v3"]} - ], - "unimplemented": true, - "variants": { - "argument_counts": [1, 2, 3, 4], - "argument_defaults": ["0.", "0.", "0.", "0."], - "types": { - "f": {}, - "i": {}, - "ui": {} - } - } - }, - "Uniform_v": { - "arguments": [ - {"type": "GLint", "name": "location"}, - {"type": "GLsizei", "name": "count"}, - {"name": "value"} - ], - "name": "Uniform", - "unimplemented": true, - "variants": { - "argument_counts": [1, 2, 3, 4], - "pointer_argument": "value", - "types": { - "fv": {}, - "iv": {}, - "uiv": {} - } - } - }, - "UseProgram": { - "arguments": [ - {"type": "GLuint", "name": "program"} - ] - }, - "Vertex": { - "arguments": [ - {"name": ["x", "y", "z", "w"], "cast_to": "GLdouble"} - ], - "variants": { - "argument_counts": [2, 3, 4], - "argument_defaults": ["0.", "0.", "0.", "1."], - "pointer_argument": "v", - "types": { - "d": {}, - "dv": {}, - "f": {}, - "fv": {}, - "i": {}, - "iv": {}, - "s": {}, - "sv": {} - } - } - }, - "VertexPointer": { - "arguments": [ - {"type": "GLint", "name": "size"}, - {"type": "GLenum", "name": "type"}, - {"type": "GLsizei", "name": "stride"}, - {"type": "void const*", "name": "pointer"} - ] - }, - "Viewport": { - "arguments": [ - {"type": "GLint", "name": ["x", "y"]}, - {"type": "GLsizei", "name": ["width", "height"]} - ] - } -} diff --git a/Userland/Libraries/LibGL/GLContext.cpp b/Userland/Libraries/LibGL/GLContext.cpp deleted file mode 100644 index 169a9c817fd..00000000000 --- a/Userland/Libraries/LibGL/GLContext.cpp +++ /dev/null @@ -1,905 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022-2024, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -__attribute__((visibility("hidden"))) GL::GLContext* g_gl_context; - -namespace GL { - -GLContext::GLContext(RefPtr driver, NonnullOwnPtr device, Gfx::Bitmap& frontbuffer) - : m_driver { driver } - , m_rasterizer { move(device) } - , m_device_info { m_rasterizer->info() } - , m_viewport { frontbuffer.rect() } - , m_frontbuffer { frontbuffer } -{ - m_texture_units.resize(m_device_info.num_texture_units); - m_active_texture_unit = &m_texture_units[0]; - - // All texture units are initialized with default textures for all targets; these - // can be referenced later on with texture name 0 in operations like glBindTexture(). - auto default_texture_2d = adopt_ref(*new Texture2D()); - m_default_textures.set(GL_TEXTURE_2D, default_texture_2d); - for (auto& texture_unit : m_texture_units) - texture_unit.set_texture_2d_target_texture(default_texture_2d); - - // Query the number lights from the device and set set up their state - // locally in the GL - m_light_states.resize(m_device_info.num_lights); - - // Set-up light0's state, as it has a different default state - // to the other lights, as per the OpenGL 1.5 spec - auto& light0 = m_light_states.at(0); - light0.diffuse_intensity = { 1.0f, 1.0f, 1.0f, 1.0f }; - light0.specular_intensity = { 1.0f, 1.0f, 1.0f, 1.0f }; - m_light_state_is_dirty = true; - - m_client_side_texture_coord_array_enabled.resize(m_device_info.num_texture_units); - m_client_tex_coord_pointer.resize(m_device_info.num_texture_units); - m_current_vertex_tex_coord.resize(m_device_info.num_texture_units); - for (auto& tex_coord : m_current_vertex_tex_coord) - tex_coord = { 0.0f, 0.0f, 0.0f, 1.0f }; - - // Initialize the texture coordinate generation coefficients - // Indices 0,1,2,3 refer to the S,T,R and Q coordinate of the respective texture - // coordinate generation config. - m_texture_coordinate_generation.resize(m_device_info.num_texture_units); - for (auto& texture_coordinate_generation : m_texture_coordinate_generation) { - texture_coordinate_generation[0].object_plane_coefficients = { 1.f, 0.f, 0.f, 0.f }; - texture_coordinate_generation[0].eye_plane_coefficients = { 1.f, 0.f, 0.f, 0.f }; - texture_coordinate_generation[1].object_plane_coefficients = { 0.f, 1.f, 0.f, 0.f }; - texture_coordinate_generation[1].eye_plane_coefficients = { 0.f, 1.f, 0.f, 0.f }; - texture_coordinate_generation[2].object_plane_coefficients = { 0.f, 0.f, 0.f, 0.f }; - texture_coordinate_generation[2].eye_plane_coefficients = { 0.f, 0.f, 0.f, 0.f }; - texture_coordinate_generation[3].object_plane_coefficients = { 0.f, 0.f, 0.f, 0.f }; - texture_coordinate_generation[3].eye_plane_coefficients = { 0.f, 0.f, 0.f, 0.f }; - } - - m_extensions = build_extension_string().release_value_but_fixme_should_propagate_errors(); -} - -GLContext::~GLContext() -{ - dbgln_if(GL_DEBUG, "GLContext::~GLContext() {:p}", this); - if (g_gl_context == this) - make_context_current(nullptr); -} - -void GLContext::gl_begin(GLenum mode) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_begin, mode); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(mode > GL_POLYGON, GL_INVALID_ENUM); - - m_current_draw_mode = mode; - m_in_draw_state = true; // Certain commands will now generate an error -} - -void GLContext::gl_clear(GLbitfield mask) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear, mask); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT), GL_INVALID_ENUM); - - if (mask & GL_COLOR_BUFFER_BIT) - m_rasterizer->clear_color(m_clear_color); - - if (mask & GL_DEPTH_BUFFER_BIT) - m_rasterizer->clear_depth(m_clear_depth); - - if (mask & GL_STENCIL_BUFFER_BIT) - m_rasterizer->clear_stencil(m_clear_stencil); -} - -void GLContext::gl_clear_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_color, red, green, blue, alpha); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - m_clear_color = { red, green, blue, alpha }; - m_clear_color.clamp(0.f, 1.f); -} - -void GLContext::gl_clear_depth(GLfloat depth) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_depth, depth); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - m_clear_depth = clamp(depth, 0.f, 1.f); -} - -void GLContext::gl_end() -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_end); - - // Make sure we had a `glBegin` before this call... - RETURN_WITH_ERROR_IF(!m_in_draw_state, GL_INVALID_OPERATION); - m_in_draw_state = false; - - sync_device_config(); - - GPU::PrimitiveType primitive_type; - switch (m_current_draw_mode) { - case GL_LINE_LOOP: - primitive_type = GPU::PrimitiveType::LineLoop; - break; - case GL_LINE_STRIP: - primitive_type = GPU::PrimitiveType::LineStrip; - break; - case GL_LINES: - primitive_type = GPU::PrimitiveType::Lines; - break; - case GL_POINTS: - primitive_type = GPU::PrimitiveType::Points; - break; - case GL_TRIANGLES: - primitive_type = GPU::PrimitiveType::Triangles; - break; - case GL_TRIANGLE_STRIP: - case GL_QUAD_STRIP: - primitive_type = GPU::PrimitiveType::TriangleStrip; - break; - case GL_TRIANGLE_FAN: - case GL_POLYGON: - primitive_type = GPU::PrimitiveType::TriangleFan; - break; - case GL_QUADS: - primitive_type = GPU::PrimitiveType::Quads; - break; - default: - VERIFY_NOT_REACHED(); - } - - m_rasterizer->draw_primitives(primitive_type, m_vertex_list); - m_vertex_list.clear_with_capacity(); -} - -GLenum GLContext::gl_get_error() -{ - if (m_in_draw_state) - return GL_INVALID_OPERATION; - - auto last_error = m_error; - m_error = GL_NO_ERROR; - return last_error; -} - -GLubyte const* GLContext::gl_get_string(GLenum name) -{ - RETURN_VALUE_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION, nullptr); - - switch (name) { - case GL_VENDOR: - return reinterpret_cast(m_device_info.vendor_name.characters()); - case GL_RENDERER: - return reinterpret_cast(m_device_info.device_name.characters()); - case GL_VERSION: - return reinterpret_cast("1.5"); - case GL_EXTENSIONS: - return reinterpret_cast(m_extensions.data()); - case GL_SHADING_LANGUAGE_VERSION: - return reinterpret_cast("0.0"); - default: - dbgln_if(GL_DEBUG, "gl_get_string({:#x}): unknown name", name); - break; - } - - RETURN_VALUE_WITH_ERROR_IF(true, GL_INVALID_ENUM, nullptr); -} - -void GLContext::gl_viewport(GLint x, GLint y, GLsizei width, GLsizei height) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_viewport, x, y, width, height); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE); - - m_viewport = { x, y, width, height }; - - auto rasterizer_options = m_rasterizer->options(); - rasterizer_options.viewport = m_viewport; - m_rasterizer->set_options(rasterizer_options); -} - -void GLContext::gl_front_face(GLenum face) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_front_face, face); - - RETURN_WITH_ERROR_IF(face < GL_CW || face > GL_CCW, GL_INVALID_ENUM); - - m_front_face = face; - - auto rasterizer_options = m_rasterizer->options(); - rasterizer_options.front_face = (face == GL_CW) ? GPU::WindingOrder::Clockwise : GPU::WindingOrder::CounterClockwise; - m_rasterizer->set_options(rasterizer_options); -} - -void GLContext::gl_cull_face(GLenum cull_mode) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_cull_face, cull_mode); - - RETURN_WITH_ERROR_IF(cull_mode != GL_FRONT && cull_mode != GL_BACK && cull_mode != GL_FRONT_AND_BACK, GL_INVALID_ENUM); - - m_culled_sides = cull_mode; - - auto rasterizer_options = m_rasterizer->options(); - rasterizer_options.cull_back = cull_mode == GL_BACK || cull_mode == GL_FRONT_AND_BACK; - rasterizer_options.cull_front = cull_mode == GL_FRONT || cull_mode == GL_FRONT_AND_BACK; - m_rasterizer->set_options(rasterizer_options); -} - -void GLContext::gl_flush() -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // No-op since GLContext is completely synchronous at the moment -} - -void GLContext::gl_finish() -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // No-op since GLContext is completely synchronous at the moment -} - -void GLContext::gl_alpha_func(GLenum func, GLclampf ref) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_alpha_func, func, ref); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(func < GL_NEVER || func > GL_ALWAYS, GL_INVALID_ENUM); - - m_alpha_test_func = func; - m_alpha_test_ref_value = ref; - - auto options = m_rasterizer->options(); - - switch (func) { - case GL_NEVER: - options.alpha_test_func = GPU::AlphaTestFunction::Never; - break; - case GL_ALWAYS: - options.alpha_test_func = GPU::AlphaTestFunction::Always; - break; - case GL_LESS: - options.alpha_test_func = GPU::AlphaTestFunction::Less; - break; - case GL_LEQUAL: - options.alpha_test_func = GPU::AlphaTestFunction::LessOrEqual; - break; - case GL_EQUAL: - options.alpha_test_func = GPU::AlphaTestFunction::Equal; - break; - case GL_NOTEQUAL: - options.alpha_test_func = GPU::AlphaTestFunction::NotEqual; - break; - case GL_GEQUAL: - options.alpha_test_func = GPU::AlphaTestFunction::GreaterOrEqual; - break; - case GL_GREATER: - options.alpha_test_func = GPU::AlphaTestFunction::Greater; - break; - default: - VERIFY_NOT_REACHED(); - } - - options.alpha_test_ref_value = m_alpha_test_ref_value; - m_rasterizer->set_options(options); -} - -void GLContext::gl_hint(GLenum target, GLenum mode) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_hint, target, mode); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(target != GL_PERSPECTIVE_CORRECTION_HINT - && target != GL_POINT_SMOOTH_HINT - && target != GL_LINE_SMOOTH_HINT - && target != GL_POLYGON_SMOOTH_HINT - && target != GL_FOG_HINT - && target != GL_GENERATE_MIPMAP_HINT - && target != GL_TEXTURE_COMPRESSION_HINT, - GL_INVALID_ENUM); - - RETURN_WITH_ERROR_IF(mode != GL_DONT_CARE - && mode != GL_FASTEST - && mode != GL_NICEST, - GL_INVALID_ENUM); - - // According to the spec implementors are free to ignore glHint. So we do. -} - -void GLContext::gl_read_buffer(GLenum mode) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_read_buffer, mode); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // FIXME: Also allow aux buffers GL_AUX0 through GL_AUX3 here - // plus any aux buffer between 0 and GL_AUX_BUFFERS - RETURN_WITH_ERROR_IF(mode != GL_FRONT_LEFT - && mode != GL_FRONT_RIGHT - && mode != GL_BACK_LEFT - && mode != GL_BACK_RIGHT - && mode != GL_FRONT - && mode != GL_BACK - && mode != GL_LEFT - && mode != GL_RIGHT, - GL_INVALID_ENUM); - - // FIXME: We do not currently have aux buffers, so make it an invalid - // operation to select anything but front or back buffers. Also we do - // not allow selecting the stereoscopic RIGHT buffers since we do not - // have them configured. - RETURN_WITH_ERROR_IF(mode != GL_FRONT_LEFT - && mode != GL_FRONT - && mode != GL_BACK_LEFT - && mode != GL_BACK - && mode != GL_FRONT - && mode != GL_BACK - && mode != GL_LEFT, - GL_INVALID_OPERATION); - - m_current_read_buffer = mode; -} - -void GLContext::gl_draw_buffer(GLenum buffer) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_draw_buffer, buffer); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // FIXME: Also allow aux buffers GL_AUX0 through GL_AUX3 here - // plus any aux buffer between 0 and GL_AUX_BUFFERS - RETURN_WITH_ERROR_IF(buffer != GL_NONE - && buffer != GL_FRONT_LEFT - && buffer != GL_FRONT_RIGHT - && buffer != GL_BACK_LEFT - && buffer != GL_BACK_RIGHT - && buffer != GL_FRONT - && buffer != GL_BACK - && buffer != GL_LEFT - && buffer != GL_RIGHT, - GL_INVALID_ENUM); - - // FIXME: We do not currently have aux buffers, so make it an invalid - // operation to select anything but front or back buffers. Also we do - // not allow selecting the stereoscopic RIGHT buffers since we do not - // have them configured. - RETURN_WITH_ERROR_IF(buffer != GL_NONE - && buffer != GL_FRONT_LEFT - && buffer != GL_FRONT - && buffer != GL_BACK_LEFT - && buffer != GL_BACK - && buffer != GL_FRONT - && buffer != GL_BACK - && buffer != GL_LEFT, - GL_INVALID_OPERATION); - - m_current_draw_buffer = buffer; - - auto rasterizer_options = m_rasterizer->options(); - // FIXME: We only have a single draw buffer in SoftGPU at the moment, - // so we simply disable color writes if GL_NONE is selected - rasterizer_options.enable_color_write = m_current_draw_buffer != GL_NONE; - m_rasterizer->set_options(rasterizer_options); -} - -void GLContext::gl_read_pixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE); - - RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM); - auto pixel_type_or_error = get_validated_pixel_type(GL_NONE, GL_NONE, format, type); - RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code()); - - auto pixel_type = pixel_type_or_error.release_value(); - GPU::ImageDataLayout output_layout = { - .pixel_type = pixel_type, - .packing = get_packing_specification(PackingType::Pack), - .dimensions = { - .width = static_cast(width), - .height = static_cast(height), - .depth = 1, - }, - .selection = { - .width = static_cast(width), - .height = static_cast(height), - .depth = 1, - }, - }; - - if (pixel_type.format == GPU::PixelFormat::DepthComponent) { - // FIXME: This check needs to be a bit more sophisticated. Currently the buffers are - // hardcoded. Once we add proper structures for them we need to correct this check - - // Error because only back buffer has a depth buffer - RETURN_WITH_ERROR_IF(m_current_read_buffer == GL_FRONT - || m_current_read_buffer == GL_FRONT_LEFT - || m_current_read_buffer == GL_FRONT_RIGHT, - GL_INVALID_OPERATION); - - m_rasterizer->blit_from_depth_buffer(pixels, { x, y }, output_layout); - } else if (pixel_type.format == GPU::PixelFormat::StencilIndex) { - dbgln("gl_read_pixels(): GL_STENCIL_INDEX is not yet supported"); - } else { - m_rasterizer->blit_from_color_buffer(pixels, { x, y }, output_layout); - } -} - -void GLContext::gl_depth_mask(GLboolean flag) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_depth_mask, flag); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - auto options = m_rasterizer->options(); - options.enable_depth_write = (flag != GL_FALSE); - m_rasterizer->set_options(options); -} - -void GLContext::gl_draw_pixels(GLsizei width, GLsizei height, GLenum format, GLenum type, void const* data) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_draw_pixels, width, height, format, type, data); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE); - - // FIXME: GL_INVALID_OPERATION is generated if format is GL_STENCIL_INDEX and there is no stencil buffer - // FIXME: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER - // target and the buffer object's data store is currently mapped. - // FIXME: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER - // target and the data would be unpacked from the buffer object such that the memory reads required would - // exceed the data store size. - // FIXME: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER - // target and data is not evenly divisible into the number of bytes needed to store in memory a datum - // indicated by type. - - RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM); - auto pixel_type_or_error = get_validated_pixel_type(GL_NONE, GL_NONE, format, type); - RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code()); - - auto pixel_type = pixel_type_or_error.release_value(); - GPU::ImageDataLayout input_layout = { - .pixel_type = pixel_type, - .packing = get_packing_specification(PackingType::Unpack), - .dimensions = { - .width = static_cast(width), - .height = static_cast(height), - .depth = 1, - }, - .selection = { - .width = static_cast(width), - .height = static_cast(height), - .depth = 1, - }, - }; - - if (pixel_type.format == GPU::PixelFormat::DepthComponent) { - m_rasterizer->blit_to_depth_buffer_at_raster_position(data, input_layout); - } else if (pixel_type.format == GPU::PixelFormat::StencilIndex) { - dbgln("gl_draw_pixels(): GL_STENCIL_INDEX is not yet supported"); - } else { - m_rasterizer->blit_to_color_buffer_at_raster_position(data, input_layout); - } -} - -void GLContext::gl_depth_range(GLdouble min, GLdouble max) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_depth_range, min, max); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - auto options = m_rasterizer->options(); - options.depth_min = clamp(min, 0.f, 1.f); - options.depth_max = clamp(max, 0.f, 1.f); - m_rasterizer->set_options(options); -} - -void GLContext::gl_depth_func(GLenum func) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_depth_func, func); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(!(func == GL_NEVER - || func == GL_LESS - || func == GL_EQUAL - || func == GL_LEQUAL - || func == GL_GREATER - || func == GL_NOTEQUAL - || func == GL_GEQUAL - || func == GL_ALWAYS), - GL_INVALID_ENUM); - - auto options = m_rasterizer->options(); - - switch (func) { - case GL_NEVER: - options.depth_func = GPU::DepthTestFunction::Never; - break; - case GL_ALWAYS: - options.depth_func = GPU::DepthTestFunction::Always; - break; - case GL_LESS: - options.depth_func = GPU::DepthTestFunction::Less; - break; - case GL_LEQUAL: - options.depth_func = GPU::DepthTestFunction::LessOrEqual; - break; - case GL_EQUAL: - options.depth_func = GPU::DepthTestFunction::Equal; - break; - case GL_NOTEQUAL: - options.depth_func = GPU::DepthTestFunction::NotEqual; - break; - case GL_GEQUAL: - options.depth_func = GPU::DepthTestFunction::GreaterOrEqual; - break; - case GL_GREATER: - options.depth_func = GPU::DepthTestFunction::Greater; - break; - default: - VERIFY_NOT_REACHED(); - } - - m_rasterizer->set_options(options); -} - -void GLContext::gl_color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) -{ - auto options = m_rasterizer->options(); - options.color_mask = (red == GL_TRUE ? 0xff : 0) - | (green == GL_TRUE ? 0xff00 : 0) - | (blue == GL_TRUE ? 0xff0000 : 0) - | (alpha == GL_TRUE ? 0xff000000 : 0); - m_rasterizer->set_options(options); -} - -void GLContext::gl_polygon_mode(GLenum face, GLenum mode) -{ - RETURN_WITH_ERROR_IF(!(face == GL_BACK || face == GL_FRONT || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(!(mode == GL_POINT || mode == GL_LINE || mode == GL_FILL), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - auto options = m_rasterizer->options(); - - // FIXME: This must support different polygon modes for front- and backside - if (face == GL_BACK) { - dbgln_if(GL_DEBUG, "gl_polygon_mode(GL_BACK, {:#x}): unimplemented", mode); - return; - } - - auto map_mode = [](GLenum mode) -> GPU::PolygonMode { - switch (mode) { - case GL_FILL: - return GPU::PolygonMode::Fill; - case GL_LINE: - return GPU::PolygonMode::Line; - case GL_POINT: - return GPU::PolygonMode::Point; - default: - VERIFY_NOT_REACHED(); - } - }; - - options.polygon_mode = map_mode(mode); - m_rasterizer->set_options(options); -} - -void GLContext::gl_polygon_offset(GLfloat factor, GLfloat units) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_polygon_offset, factor, units); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - auto rasterizer_options = m_rasterizer->options(); - rasterizer_options.depth_offset_factor = factor; - rasterizer_options.depth_offset_constant = units; - m_rasterizer->set_options(rasterizer_options); -} - -void GLContext::gl_fogfv(GLenum pname, GLfloat const* params) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_fogfv, pname, params); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - auto options = m_rasterizer->options(); - - switch (pname) { - case GL_FOG_COLOR: - options.fog_color = { params[0], params[1], params[2], params[3] }; - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - - m_rasterizer->set_options(options); -} - -void GLContext::gl_fogf(GLenum pname, GLfloat param) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_fogf, pname, param); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(param < 0.0f, GL_INVALID_VALUE); - - auto options = m_rasterizer->options(); - - switch (pname) { - case GL_FOG_DENSITY: - options.fog_density = param; - break; - case GL_FOG_END: - options.fog_end = param; - break; - case GL_FOG_START: - options.fog_start = param; - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - - m_rasterizer->set_options(options); -} - -void GLContext::gl_fogi(GLenum pname, GLint param) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_fogi, pname, param); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(param != GL_LINEAR && param != GL_EXP && param != GL_EXP2, GL_INVALID_ENUM); - - auto options = m_rasterizer->options(); - - switch (pname) { - case GL_FOG_MODE: - switch (param) { - case GL_LINEAR: - options.fog_mode = GPU::FogMode::Linear; - break; - case GL_EXP: - options.fog_mode = GPU::FogMode::Exp; - break; - case GL_EXP2: - options.fog_mode = GPU::FogMode::Exp2; - break; - } - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - - m_rasterizer->set_options(options); -} - -void GLContext::gl_pixel_storei(GLenum pname, GLint param) -{ - auto const is_packing_parameter = (pname >= GL_PACK_SWAP_BYTES && pname <= GL_PACK_ALIGNMENT) - || pname == GL_PACK_SKIP_IMAGES - || pname == GL_PACK_IMAGE_HEIGHT; - auto& pixel_parameters = is_packing_parameter ? m_packing_parameters : m_unpacking_parameters; - - switch (pname) { - case GL_PACK_ALIGNMENT: - case GL_UNPACK_ALIGNMENT: - RETURN_WITH_ERROR_IF(param != 1 && param != 2 && param != 4 && param != 8, GL_INVALID_VALUE); - pixel_parameters.pack_alignment = param; - break; - case GL_PACK_IMAGE_HEIGHT: - case GL_UNPACK_IMAGE_HEIGHT: - RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE); - pixel_parameters.image_height = param; - break; - case GL_PACK_LSB_FIRST: - case GL_UNPACK_LSB_FIRST: - pixel_parameters.least_significant_bit_first = (param != 0); - break; - case GL_PACK_ROW_LENGTH: - case GL_UNPACK_ROW_LENGTH: - RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE); - pixel_parameters.row_length = param; - break; - case GL_PACK_SKIP_IMAGES: - case GL_UNPACK_SKIP_IMAGES: - RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE); - pixel_parameters.skip_images = param; - break; - case GL_PACK_SKIP_PIXELS: - case GL_UNPACK_SKIP_PIXELS: - RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE); - pixel_parameters.skip_pixels = param; - break; - case GL_PACK_SKIP_ROWS: - case GL_UNPACK_SKIP_ROWS: - RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE); - pixel_parameters.skip_rows = param; - break; - case GL_PACK_SWAP_BYTES: - case GL_UNPACK_SWAP_BYTES: - pixel_parameters.swap_bytes = (param != 0); - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } -} - -void GLContext::gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_scissor, x, y, width, height); - RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE); - - auto options = m_rasterizer->options(); - options.scissor_box = { x, y, width, height }; - m_rasterizer->set_options(options); -} - -void GLContext::gl_raster_pos(GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_raster_pos, x, y, z, w); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - sync_matrices(); - m_rasterizer->set_raster_position({ x, y, z, w }); -} - -void GLContext::gl_line_width(GLfloat width) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_line_width, width); - - RETURN_WITH_ERROR_IF(width <= 0, GL_INVALID_VALUE); - - m_line_width = width; - auto options = m_rasterizer->options(); - options.line_width = width; - m_rasterizer->set_options(options); -} - -void GLContext::gl_push_attrib(GLbitfield mask) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_push_attrib, mask); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // FIXME: implement - dbgln_if(GL_DEBUG, "GLContext FIXME: implement gl_push_attrib({})", mask); -} - -void GLContext::gl_pop_attrib() -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_pop_attrib); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // FIXME: implement - dbgln_if(GL_DEBUG, "GLContext FIXME: implement gl_pop_attrib()"); -} - -void GLContext::gl_bitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, GLubyte const* bitmap) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_bitmap, width, height, xorig, yorig, xmove, ymove, bitmap); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - if (bitmap != nullptr) { - // FIXME: implement - dbgln_if(GL_DEBUG, "gl_bitmap({}, {}, {}, {}, {}, {}, {}): unimplemented", width, height, xorig, yorig, xmove, ymove, bitmap); - } - - auto raster_position = m_rasterizer->raster_position(); - raster_position.window_coordinates += { xmove, ymove, 0.f, 0.f }; - m_rasterizer->set_raster_position(raster_position); -} - -void GLContext::gl_rect(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_rect, x1, y1, x2, y2); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - gl_begin(GL_POLYGON); - gl_vertex(x1, y1, 0.0, 1.0); - gl_vertex(x2, y1, 0.0, 1.0); - gl_vertex(x2, y2, 0.0, 1.0); - gl_vertex(x1, y2, 0.0, 1.0); - gl_end(); -} - -void GLContext::gl_point_size(GLfloat size) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_point_size, size); - RETURN_WITH_ERROR_IF(size <= 0.f, GL_INVALID_VALUE); - - m_point_size = size; - - auto rasterizer_options = m_rasterizer->options(); - rasterizer_options.point_size = size; - m_rasterizer->set_options(rasterizer_options); -} - -void GLContext::present() -{ - m_rasterizer->blit_from_color_buffer(*m_frontbuffer); -} - -void GLContext::sync_device_config() -{ - sync_clip_planes(); - sync_device_sampler_config(); - sync_device_texture_units(); - sync_light_state(); - sync_matrices(); - sync_stencil_configuration(); -} - -ErrorOr GLContext::build_extension_string() -{ - Vector extensions; - - // FIXME: npot texture support became a required core feature starting with OpenGL 2.0 (https://www.khronos.org/opengl/wiki/NPOT_Texture) - // Ideally we would verify if the selected device adheres to the requested OpenGL context version before context creation - // and refuse to create a context if it doesn't. - if (m_device_info.supports_npot_textures) - TRY(extensions.try_append("GL_ARB_texture_non_power_of_two"sv)); - - if (m_device_info.num_texture_units > 1) - TRY(extensions.try_append("GL_ARB_multitexture"sv)); - - if (m_device_info.supports_texture_clamp_to_edge) - TRY(extensions.try_append("GL_EXT_texture_edge_clamp"sv)); - - if (m_device_info.supports_texture_env_add) { - TRY(extensions.try_append("GL_ARB_texture_env_add"sv)); - TRY(extensions.try_append("GL_EXT_texture_env_add"sv)); - } - - if (m_device_info.max_texture_lod_bias > 0.f) - TRY(extensions.try_append("GL_EXT_texture_lod_bias"sv)); - - StringBuilder string_builder {}; - TRY(string_builder.try_join(' ', extensions)); - - // Create null-terminated string - auto extensions_bytes = TRY(string_builder.to_byte_buffer()); - TRY(extensions_bytes.try_append(0)); - return extensions_bytes; -} - -ErrorOr> create_context(Gfx::Bitmap& bitmap) -{ - // FIXME: Make driver selectable. This is currently hardcoded to LibSoftGPU - auto driver = TRY(GPU::Driver::try_create("softgpu"sv)); - auto device = TRY(driver->try_create_device(bitmap.size())); - auto context = make(driver, move(device), bitmap); - dbgln_if(GL_DEBUG, "GL::create_context({}) -> {:p}", bitmap.size(), context.ptr()); - - if (!g_gl_context) - make_context_current(context); - - return context; -} - -void make_context_current(GLContext* context) -{ - if (g_gl_context == context) - return; - - dbgln_if(GL_DEBUG, "GL::make_context_current({:p})", context); - g_gl_context = context; -} - -} diff --git a/Userland/Libraries/LibGL/GLContext.h b/Userland/Libraries/LibGL/GLContext.h deleted file mode 100644 index 6f25d4370da..00000000000 --- a/Userland/Libraries/LibGL/GLContext.h +++ /dev/null @@ -1,619 +0,0 @@ -/* - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2021-2022, Jesse Buhagiar - * Copyright (c) 2022-2024, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace GL { - -#define APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(name, ...) \ - if (should_append_to_listing()) { \ - append_to_listing<&GLContext::name>(__VA_ARGS__); \ - if (!should_execute_after_appending_to_listing()) \ - return; \ - } - -#define APPEND_TO_CALL_LIST_WITH_ARG_AND_RETURN_IF_NEEDED(name, arg) \ - if (should_append_to_listing()) { \ - auto ptr = store_in_listing(arg); \ - append_to_listing<&GLContext::name>(*ptr); \ - if (!should_execute_after_appending_to_listing()) \ - return; \ - } - -#define RETURN_WITH_ERROR_IF(condition, error) \ - if (condition) { \ - dbgln_if(GL_DEBUG, "{}(): error {:#x}", __func__, error); \ - if (m_error == GL_NO_ERROR) \ - m_error = error; \ - return; \ - } - -#define RETURN_VALUE_WITH_ERROR_IF(condition, error, return_value) \ - if (condition) { \ - dbgln_if(GL_DEBUG, "{}(): error {:#x}", __func__, error); \ - if (m_error == GL_NO_ERROR) \ - m_error = error; \ - return return_value; \ - } - -constexpr size_t MODELVIEW_MATRIX_STACK_LIMIT = 64; -constexpr size_t PROJECTION_MATRIX_STACK_LIMIT = 8; -constexpr size_t TEXTURE_MATRIX_STACK_LIMIT = 8; - -struct ContextParameter { - GLenum type; - bool is_capability { false }; - u8 count { 1 }; - union { - bool boolean_value; - GLint integer_value; - GLint integer_list[4]; - GLdouble double_value; - GLdouble double_list[4]; - } value; -}; - -struct VertexAttribPointer { - GLint size { 4 }; - GLenum type { GL_FLOAT }; - bool normalize; - GLsizei stride { 0 }; - void const* pointer { 0 }; -}; - -enum Face { - Front = 0, - Back = 1, -}; - -enum class PackingType { - Pack, - Unpack, -}; - -class GLContext final { -public: - GLContext(RefPtr driver, NonnullOwnPtr, Gfx::Bitmap&); - ~GLContext(); - - NonnullRefPtr frontbuffer() const { return m_frontbuffer; } - void present(); - - void gl_begin(GLenum mode); - void gl_clear(GLbitfield mask); - void gl_clear_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); - void gl_clear_depth(GLfloat depth); - void gl_clear_stencil(GLint s); - void gl_color(GLfloat r, GLfloat g, GLfloat b, GLfloat a); - void gl_delete_textures(GLsizei n, GLuint const* textures); - void gl_end(); - void gl_frustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val); - void gl_gen_textures(GLsizei n, GLuint* textures); - GLenum gl_get_error(); - GLubyte const* gl_get_string(GLenum name); - void gl_load_identity(); - void gl_load_matrix(FloatMatrix4x4 const& matrix); - void gl_matrix_mode(GLenum mode); - void gl_ortho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val); - void gl_push_matrix(); - void gl_pop_matrix(); - void gl_mult_matrix(FloatMatrix4x4 const& matrix); - void gl_rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); - void gl_scale(GLfloat x, GLfloat y, GLfloat z); - void gl_translate(GLfloat x, GLfloat y, GLfloat z); - void gl_vertex(GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void gl_viewport(GLint x, GLint y, GLsizei width, GLsizei height); - void gl_enable(GLenum); - void gl_disable(GLenum); - GLboolean gl_is_enabled(GLenum); - void gl_front_face(GLenum); - void gl_cull_face(GLenum); - GLuint gl_gen_lists(GLsizei range); - void gl_call_list(GLuint list); - void gl_call_lists(GLsizei n, GLenum type, void const* lists); - void gl_delete_lists(GLuint list, GLsizei range); - void gl_list_base(GLuint base); - void gl_end_list(void); - void gl_new_list(GLuint list, GLenum mode); - GLboolean gl_is_list(GLuint list); - void gl_flush(); - void gl_finish(); - void gl_blend_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); - void gl_blend_equation_separate(GLenum rgb_mode, GLenum alpha_mode); - void gl_blend_func(GLenum src_factor, GLenum dst_factor); - void gl_shade_model(GLenum mode); - void gl_alpha_func(GLenum func, GLclampf ref); - void gl_hint(GLenum target, GLenum mode); - void gl_read_buffer(GLenum mode); - void gl_draw_buffer(GLenum buffer); - void gl_read_pixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); - void gl_tex_image_2d(GLenum target, GLint level, GLint internal_format, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLvoid const* data); - void gl_tex_sub_image_2d(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid const* data); - void gl_tex_parameter(GLenum target, GLenum pname, GLfloat param); - void gl_tex_parameterfv(GLenum target, GLenum pname, GLfloat const* params); - void gl_tex_coord(GLfloat s, GLfloat t, GLfloat r, GLfloat q); - void gl_multi_tex_coord(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); - void gl_tex_env(GLenum target, GLenum pname, FloatVector4 params); - void gl_tex_envv(GLenum target, GLenum pname, void const* params, GLenum type); - void gl_bind_texture(GLenum target, GLuint texture); - GLboolean gl_is_texture(GLuint texture); - void gl_active_texture(GLenum texture); - void gl_depth_mask(GLboolean flag); - void gl_enable_client_state(GLenum cap); - void gl_disable_client_state(GLenum cap); - void gl_client_active_texture(GLenum target); - void gl_vertex_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer); - void gl_color_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer); - void gl_tex_coord_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer); - void gl_draw_arrays(GLenum mode, GLint first, GLsizei count); - void gl_draw_elements(GLenum mode, GLsizei count, GLenum type, void const* indices); - void gl_draw_pixels(GLsizei width, GLsizei height, GLenum format, GLenum type, void const* data); - void gl_color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); - void gl_get_booleanv(GLenum pname, GLboolean* data); - void gl_get_doublev(GLenum pname, GLdouble* params); - void gl_get_floatv(GLenum pname, GLfloat* params); - void gl_get_integerv(GLenum pname, GLint* data); - void gl_depth_range(GLdouble min, GLdouble max); - void gl_depth_func(GLenum func); - void gl_polygon_mode(GLenum face, GLenum mode); - void gl_polygon_offset(GLfloat factor, GLfloat units); - void gl_fogfv(GLenum pname, GLfloat const* params); - void gl_fogf(GLenum pname, GLfloat param); - void gl_fogi(GLenum pname, GLint param); - void gl_pixel_storei(GLenum pname, GLint param); - void gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height); - void gl_stencil_func_separate(GLenum face, GLenum func, GLint ref, GLuint mask); - void gl_stencil_mask_separate(GLenum face, GLuint mask); - void gl_stencil_op_separate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); - void gl_normal(GLfloat nx, GLfloat ny, GLfloat nz); - void gl_normal_pointer(GLenum type, GLsizei stride, void const* pointer); - void gl_raster_pos(GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void gl_line_width(GLfloat width); - void gl_push_attrib(GLbitfield mask); - void gl_pop_attrib(); - void gl_light_model(GLenum pname, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void gl_light_modelv(GLenum pname, void const* params, GLenum type); - void gl_bitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, GLubyte const* bitmap); - void gl_copy_tex_image_2d(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); - void gl_get_tex_image(GLenum target, GLint level, GLenum format, GLenum type, void* pixels); - void gl_get_tex_parameter_integerv(GLenum target, GLint level, GLenum pname, GLint* params); - void gl_rect(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); - void gl_tex_gen(GLenum coord, GLenum pname, GLint param); - void gl_tex_gen_floatv(GLenum coord, GLenum pname, GLfloat const* params); - void gl_lightf(GLenum light, GLenum pname, GLfloat param); - void gl_lightfv(GLenum light, GLenum pname, GLfloat const* params); - void gl_lightiv(GLenum light, GLenum pname, GLint const* params); - void gl_materialf(GLenum face, GLenum pname, GLfloat param); - void gl_materialfv(GLenum face, GLenum pname, GLfloat const* params); - void gl_materialiv(GLenum face, GLenum pname, GLint const* params); - void gl_color_material(GLenum face, GLenum mode); - void gl_get_light(GLenum light, GLenum pname, void* params, GLenum type); - void gl_get_material(GLenum face, GLenum pname, void* params, GLenum type); - void gl_clip_plane(GLenum plane, GLdouble const* equation); - void gl_get_clip_plane(GLenum plane, GLdouble* equation); - void gl_array_element(GLint i); - void gl_copy_tex_sub_image_2d(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); - void gl_point_size(GLfloat size); - void gl_bind_buffer(GLenum target, GLuint buffer); - void gl_buffer_data(GLenum target, GLsizeiptr size, void const* data, GLenum usage); - void gl_buffer_sub_data(GLenum target, GLintptr offset, GLsizeiptr size, void const* data); - void gl_delete_buffers(GLsizei n, GLuint const* buffers); - void gl_gen_buffers(GLsizei n, GLuint* buffers); - - GLuint gl_create_shader(GLenum shader_type); - void gl_delete_shader(GLuint shader); - void gl_shader_source(GLuint shader, GLsizei count, GLchar const** string, GLint const* length); - void gl_compile_shader(GLuint shader); - void gl_get_shader(GLuint shader, GLenum pname, GLint* params); - - GLuint gl_create_program(); - void gl_delete_program(GLuint program); - void gl_attach_shader(GLuint program, GLuint shader); - void gl_link_program(GLuint program); - void gl_use_program(GLuint program); - void gl_get_program(GLuint program, GLenum pname, GLint* params); - -private: - void sync_clip_planes(); - void sync_device_config(); - void sync_device_sampler_config(); - void sync_device_texture_units(); - void sync_light_state(); - void sync_matrices(); - void sync_stencil_configuration(); - - ErrorOr build_extension_string(); - - template - T* store_in_listing(T value) - { - VERIFY(m_current_listing_index.has_value()); - auto& listing = m_current_listing_index->listing; - listing.saved_arguments.empend(make(move(value))); - return listing.saved_arguments.last()->template get_pointer(); - } - - template - void append_to_listing(Args&&... args) - { - VERIFY(m_current_listing_index.has_value()); - m_current_listing_index->listing.entries.empend(member, Listing::ArgumentsFor { forward(args)... }); - } - - Optional get_context_parameter(GLenum pname); - GPU::PackingSpecification get_packing_specification(PackingType); - - template - void get_floating_point(GLenum pname, T* params); - template - void get_light_param(GLenum light, GLenum pname, T* params); - template - void get_material_param(Face face, GLenum pname, T* params); - - void invoke_list(size_t list_index); - [[nodiscard]] bool should_append_to_listing() const { return m_current_listing_index.has_value(); } - [[nodiscard]] bool should_execute_after_appending_to_listing() const { return m_current_listing_index.has_value() && m_current_listing_index->mode == GL_COMPILE_AND_EXECUTE; } - - // FIXME: we store GPU::Texture objects that do not point back to either the driver or device, so we need - // to destruct the latter two at the very end. Fix this by making all GPU objects point back to - // the device that created them, and the device back to the driver. - RefPtr m_driver; - NonnullOwnPtr m_rasterizer; - GPU::DeviceInfo const m_device_info; - - GLenum m_current_draw_mode; - GLenum m_current_matrix_mode { GL_MODELVIEW }; - - FloatMatrix4x4& projection_matrix() { return m_projection_matrix_stack.last(); } - FloatMatrix4x4& model_view_matrix() { return m_model_view_matrix_stack.last(); } - - Vector m_projection_matrix_stack { FloatMatrix4x4::identity() }; - Vector m_model_view_matrix_stack { FloatMatrix4x4::identity() }; - Vector* m_current_matrix_stack { &m_model_view_matrix_stack }; - FloatMatrix4x4* m_current_matrix { &m_current_matrix_stack->last() }; - bool m_matrices_dirty { true }; - - ALWAYS_INLINE void update_current_matrix(FloatMatrix4x4 const& new_matrix) - { - *m_current_matrix = new_matrix; - m_matrices_dirty = true; - - if (m_current_matrix_mode == GL_TEXTURE) - m_texture_units_dirty = true; - } - - Gfx::IntRect m_viewport; - - FloatVector4 m_clear_color { 0.0f, 0.0f, 0.0f, 0.0f }; - float m_clear_depth { 1.f }; - u8 m_clear_stencil { 0 }; - - FloatVector4 m_current_vertex_color { 1.0f, 1.0f, 1.0f, 1.0f }; - Vector m_current_vertex_tex_coord; - FloatVector3 m_current_vertex_normal { 0.0f, 0.0f, 1.0f }; - - Vector m_vertex_list; - - GLenum m_error = GL_NO_ERROR; - bool m_in_draw_state = false; - - bool m_depth_test_enabled { false }; - bool m_depth_offset_enabled { false }; - - bool m_cull_faces = false; - GLenum m_front_face = GL_CCW; - GLenum m_culled_sides = GL_BACK; - - bool m_blend_enabled = false; - FloatVector4 m_blend_color { 0.f, 0.f, 0.f, 0.f }; - GLenum m_blend_source_factor = GL_ONE; - GLenum m_blend_destination_factor = GL_ZERO; - - GLenum m_blend_equation_rgb = GL_FUNC_ADD; - GLenum m_blend_equation_alpha = GL_FUNC_ADD; - - bool m_alpha_test_enabled = false; - GLenum m_alpha_test_func = GL_ALWAYS; - GLclampf m_alpha_test_ref_value = 0; - - bool m_dither_enabled { true }; - bool m_normalize { false }; - - // Stencil configuration - bool m_stencil_test_enabled { false }; - bool m_stencil_configuration_dirty { true }; - - struct StencilFunctionOptions { - GLenum func { GL_ALWAYS }; - GLint reference_value { 0 }; - GLuint mask { NumericLimits::max() }; - }; - Array m_stencil_function; - - struct StencilOperationOptions { - GLenum op_fail { GL_KEEP }; - GLenum op_depth_fail { GL_KEEP }; - GLenum op_pass { GL_KEEP }; - GLuint write_mask { NumericLimits::max() }; - }; - Array m_stencil_operation; - - GLenum m_current_read_buffer = GL_BACK; - GLenum m_current_draw_buffer = GL_BACK; - - // User-defined clip planes - struct ClipPlaneAttributes { - Array eye_clip_plane; // TODO: Change to use device-defined constant - GLuint enabled { 0 }; - } m_clip_plane_attributes; - bool m_clip_planes_dirty { true }; - - // Client side arrays - bool m_client_side_vertex_array_enabled { false }; - bool m_client_side_color_array_enabled { false }; - Vector m_client_side_texture_coord_array_enabled; - size_t m_client_active_texture { 0 }; - bool m_client_side_normal_array_enabled { false }; - - NonnullRefPtr m_frontbuffer; - - // Texture objects - template - RefPtr get_default_texture(GLenum target) - { - auto default_texture = m_default_textures.get(target); - VERIFY(default_texture.has_value()); - return static_cast(default_texture.value()); - } - - NameAllocator m_texture_name_allocator; - HashMap> m_allocated_textures; - HashMap> m_default_textures; - Vector m_texture_units; - TextureUnit* m_active_texture_unit; - size_t m_active_texture_unit_index { 0 }; - bool m_texture_units_dirty { true }; - - // Texture coordinate generation state - struct TextureCoordinateGeneration { - bool enabled { false }; - GLenum generation_mode { GL_EYE_LINEAR }; - FloatVector4 object_plane_coefficients { 0.0f, 0.0f, 0.0f, 0.0f }; - FloatVector4 eye_plane_coefficients { 0.0f, 0.0f, 0.0f, 0.0f }; - }; - Vector> m_texture_coordinate_generation; - ALWAYS_INLINE TextureCoordinateGeneration& texture_coordinate_generation(size_t texture_unit, GLenum capability) - { - return m_texture_coordinate_generation[texture_unit][capability - GL_TEXTURE_GEN_S]; - } - - bool m_sampler_config_is_dirty { true }; - bool m_light_state_is_dirty { true }; - - NameAllocator m_shader_name_allocator; - NameAllocator m_program_name_allocator; - HashMap> m_allocated_shaders; - HashMap> m_allocated_programs; - RefPtr m_current_program; - - struct Listing { - - template - struct TupleTypeForArgumentListOf_; - - template - struct TupleTypeForArgumentListOf_ { - using Type = Tuple; - }; - - template - using TupleTypeForArgumentListOf = typename TupleTypeForArgumentListOf_::Type; - - template - using ArgumentsFor = TupleTypeForArgumentListOf; - - template - struct FunctionAndArgs { - Variant function; - Variant...> arguments; - }; - - using FunctionsAndArgs = FunctionAndArgs< - decltype(&GLContext::gl_begin), - decltype(&GLContext::gl_clear), - decltype(&GLContext::gl_clear_color), - decltype(&GLContext::gl_clear_depth), - decltype(&GLContext::gl_clear_stencil), - decltype(&GLContext::gl_color), - decltype(&GLContext::gl_end), - decltype(&GLContext::gl_frustum), - decltype(&GLContext::gl_load_identity), - decltype(&GLContext::gl_load_matrix), - decltype(&GLContext::gl_matrix_mode), - decltype(&GLContext::gl_ortho), - decltype(&GLContext::gl_push_matrix), - decltype(&GLContext::gl_pop_matrix), - decltype(&GLContext::gl_mult_matrix), - decltype(&GLContext::gl_rotate), - decltype(&GLContext::gl_scale), - decltype(&GLContext::gl_translate), - decltype(&GLContext::gl_vertex), - decltype(&GLContext::gl_viewport), - decltype(&GLContext::gl_enable), - decltype(&GLContext::gl_disable), - decltype(&GLContext::gl_front_face), - decltype(&GLContext::gl_cull_face), - decltype(&GLContext::gl_call_list), - decltype(&GLContext::gl_call_lists), - decltype(&GLContext::gl_blend_color), - decltype(&GLContext::gl_blend_equation_separate), - decltype(&GLContext::gl_blend_func), - decltype(&GLContext::gl_shade_model), - decltype(&GLContext::gl_alpha_func), - decltype(&GLContext::gl_hint), - decltype(&GLContext::gl_read_buffer), - decltype(&GLContext::gl_tex_parameter), - decltype(&GLContext::gl_tex_parameterfv), - decltype(&GLContext::gl_depth_mask), - decltype(&GLContext::gl_draw_pixels), - decltype(&GLContext::gl_depth_range), - decltype(&GLContext::gl_polygon_offset), - decltype(&GLContext::gl_scissor), - decltype(&GLContext::gl_stencil_func_separate), - decltype(&GLContext::gl_stencil_mask_separate), - decltype(&GLContext::gl_stencil_op_separate), - decltype(&GLContext::gl_normal), - decltype(&GLContext::gl_raster_pos), - decltype(&GLContext::gl_line_width), - decltype(&GLContext::gl_push_attrib), - decltype(&GLContext::gl_pop_attrib), - decltype(&GLContext::gl_light_model), - decltype(&GLContext::gl_bitmap), - decltype(&GLContext::gl_copy_tex_image_2d), - decltype(&GLContext::gl_rect), - decltype(&GLContext::gl_tex_env), - decltype(&GLContext::gl_tex_gen), - decltype(&GLContext::gl_tex_gen_floatv), - decltype(&GLContext::gl_fogf), - decltype(&GLContext::gl_fogfv), - decltype(&GLContext::gl_fogi), - decltype(&GLContext::gl_lightf), - decltype(&GLContext::gl_lightfv), - decltype(&GLContext::gl_lightiv), - decltype(&GLContext::gl_materialf), - decltype(&GLContext::gl_materialfv), - decltype(&GLContext::gl_materialiv), - decltype(&GLContext::gl_color_material), - decltype(&GLContext::gl_get_light), - decltype(&GLContext::gl_clip_plane), - decltype(&GLContext::gl_copy_tex_sub_image_2d), - decltype(&GLContext::gl_point_size)>; - - using ExtraSavedArguments = Variant< - FloatMatrix4x4>; - - Vector> saved_arguments; - Vector entries; - }; - - static constexpr size_t max_allowed_gl_call_depth { 128 }; - size_t m_gl_call_depth { 0 }; - Vector m_listings; - size_t m_list_base { 0 }; - struct CurrentListing { - Listing listing; - size_t index { 0 }; - GLenum mode { GL_COMPILE }; - }; - Optional m_current_listing_index; - - VertexAttribPointer m_client_vertex_pointer; - VertexAttribPointer m_client_color_pointer; - Vector m_client_tex_coord_pointer; - VertexAttribPointer m_client_normal_pointer; - - struct PixelParameters { - i32 image_height { 0 }; - bool least_significant_bit_first { false }; - u8 pack_alignment { 4 }; - i32 row_length { 0 }; - i32 skip_images { 0 }; - i32 skip_pixels { 0 }; - i32 skip_rows { 0 }; - bool swap_bytes { false }; - }; - PixelParameters m_packing_parameters; - PixelParameters m_unpacking_parameters; - - // Point drawing configuration - bool m_point_smooth { false }; - float m_point_size { 1.f }; - - // Line drawing configuration - bool m_line_smooth { false }; - float m_line_width { 1.f }; - - // Lighting configuration - bool m_lighting_enabled { false }; - Vector m_light_states; - Array m_material_states; - - // Color material - bool m_color_material_enabled { false }; - GLenum m_color_material_face { GL_FRONT_AND_BACK }; - GLenum m_color_material_mode { GL_AMBIENT_AND_DIFFUSE }; - - // GL Extension string - ByteBuffer m_extensions; - - // Buffer objects - NameAllocator m_buffer_name_allocator; - HashMap> m_allocated_buffers; - RefPtr m_array_buffer; - RefPtr m_element_array_buffer; -}; - -// Transposes input matrices (column-major) to our Matrix (row-major). -template -constexpr FloatMatrix4x4 transpose_input_matrix(I const* matrix) -{ - Array elements; - for (size_t i = 0; i < 16; ++i) - elements[i] = static_cast(matrix[i]); - // clang-format off - return { - elements[0], elements[4], elements[8], elements[12], - elements[1], elements[5], elements[9], elements[13], - elements[2], elements[6], elements[10], elements[14], - elements[3], elements[7], elements[11], elements[15], - }; - // clang-format on -} - -template<> -constexpr FloatMatrix4x4 transpose_input_matrix(float const* matrix) -{ - // clang-format off - return { - matrix[0], matrix[4], matrix[8], matrix[12], - matrix[1], matrix[5], matrix[9], matrix[13], - matrix[2], matrix[6], matrix[10], matrix[14], - matrix[3], matrix[7], matrix[11], matrix[15], - }; - // clang-format on -} - -ErrorOr> create_context(Gfx::Bitmap&); -void make_context_current(GLContext*); - -} diff --git a/Userland/Libraries/LibGL/Image.cpp b/Userland/Libraries/LibGL/Image.cpp deleted file mode 100644 index 10bd7637208..00000000000 --- a/Userland/Libraries/LibGL/Image.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (c) 2022-2023, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace GL { - -ErrorOr get_validated_pixel_type(GLenum target, GLenum internal_format, GLenum format, GLenum type) -{ - // We accept GL_NONE as target for non-texture related calls (such as `glDrawPixels`) - if (target != GL_NONE - && target != GL_TEXTURE_1D - && target != GL_TEXTURE_2D - && target != GL_TEXTURE_3D - && target != GL_TEXTURE_1D_ARRAY - && target != GL_TEXTURE_2D_ARRAY - && target != GL_TEXTURE_CUBE_MAP - && target != GL_PROXY_TEXTURE_1D - && target != GL_PROXY_TEXTURE_2D - && target != GL_PROXY_TEXTURE_3D) - return Error::from_errno(GL_INVALID_ENUM); - - // Internal format can be a number between 1 and 4. Symbolic formats were only added with EXT_texture, promoted to core in OpenGL 1.1 - if (internal_format == 1) - internal_format = GL_ALPHA; - else if (internal_format == 2) - internal_format = GL_LUMINANCE_ALPHA; - else if (internal_format == 3) - internal_format = GL_RGB; - else if (internal_format == 4) - internal_format = GL_RGBA; - - if (internal_format != GL_NONE - && internal_format != GL_ALPHA - && internal_format != GL_ALPHA4 - && internal_format != GL_ALPHA8 - && internal_format != GL_ALPHA12 - && internal_format != GL_ALPHA16 - && internal_format != GL_COMPRESSED_ALPHA - && internal_format != GL_COMPRESSED_LUMINANCE - && internal_format != GL_COMPRESSED_LUMINANCE_ALPHA - && internal_format != GL_COMPRESSED_INTENSITY - && internal_format != GL_COMPRESSED_RGB - && internal_format != GL_COMPRESSED_RGBA - && internal_format != GL_DEPTH_COMPONENT - && internal_format != GL_DEPTH_COMPONENT16 - && internal_format != GL_DEPTH_COMPONENT24 - && internal_format != GL_DEPTH_COMPONENT32 - && internal_format != GL_DEPTH_STENCIL - && internal_format != GL_LUMINANCE - && internal_format != GL_LUMINANCE4 - && internal_format != GL_LUMINANCE8 - && internal_format != GL_LUMINANCE12 - && internal_format != GL_LUMINANCE16 - && internal_format != GL_LUMINANCE_ALPHA - && internal_format != GL_LUMINANCE4_ALPHA4 - && internal_format != GL_LUMINANCE6_ALPHA2 - && internal_format != GL_LUMINANCE8_ALPHA8 - && internal_format != GL_LUMINANCE12_ALPHA4 - && internal_format != GL_LUMINANCE12_ALPHA12 - && internal_format != GL_LUMINANCE16_ALPHA16 - && internal_format != GL_INTENSITY - && internal_format != GL_INTENSITY4 - && internal_format != GL_INTENSITY8 - && internal_format != GL_INTENSITY12 - && internal_format != GL_INTENSITY16 - && internal_format != GL_R3_G3_B2 - && internal_format != GL_RED - && internal_format != GL_RG - && internal_format != GL_RGB - && internal_format != GL_RGB4 - && internal_format != GL_RGB5 - && internal_format != GL_RGB8 - && internal_format != GL_RGB10 - && internal_format != GL_RGB12 - && internal_format != GL_RGB16 - && internal_format != GL_RGBA - && internal_format != GL_RGBA2 - && internal_format != GL_RGBA4 - && internal_format != GL_RGB5_A1 - && internal_format != GL_RGBA8 - && internal_format != GL_RGB10_A2 - && internal_format != GL_RGBA12 - && internal_format != GL_RGBA16 - && internal_format != GL_SLUMINANCE - && internal_format != GL_SLUMINANCE8 - && internal_format != GL_SLUMINANCE_ALPHA - && internal_format != GL_SLUMINANCE8_ALPHA8 - && internal_format != GL_SRGB - && internal_format != GL_SRGB8 - && internal_format != GL_SRGB_ALPHA - && internal_format != GL_SRGB8_ALPHA8) - return Error::from_errno(GL_INVALID_ENUM); - - if (format != GL_NONE - && (format < GL_COLOR_INDEX || format > GL_LUMINANCE_ALPHA) - && format != GL_BGR - && format != GL_BGRA) - return Error::from_errno(GL_INVALID_ENUM); - - if (type != GL_NONE - && type != GL_BITMAP - && (type < GL_BYTE || type > GL_FLOAT) - && type != GL_HALF_FLOAT - && (type < GL_UNSIGNED_BYTE_3_3_2 || type > GL_UNSIGNED_INT_10_10_10_2) - && (type < GL_UNSIGNED_BYTE_2_3_3_REV || type > GL_UNSIGNED_INT_2_10_10_10_REV)) - return Error::from_errno(GL_INVALID_ENUM); - - if (type == GL_BITMAP && format != GL_COLOR_INDEX && format != GL_STENCIL_INDEX) - return Error::from_errno(GL_INVALID_ENUM); - - if (format != GL_RGB && (type == GL_UNSIGNED_BYTE_3_3_2 || type == GL_UNSIGNED_BYTE_2_3_3_REV || type == GL_UNSIGNED_SHORT_5_6_5 || type == GL_UNSIGNED_SHORT_5_6_5_REV)) - return Error::from_errno(GL_INVALID_OPERATION); - - if ((type == GL_UNSIGNED_SHORT_4_4_4_4 - || type == GL_UNSIGNED_SHORT_4_4_4_4_REV - || type == GL_UNSIGNED_SHORT_5_5_5_1 - || type == GL_UNSIGNED_SHORT_1_5_5_5_REV - || type == GL_UNSIGNED_INT_8_8_8_8 - || type == GL_UNSIGNED_INT_8_8_8_8_REV - || type == GL_UNSIGNED_INT_10_10_10_2 - || type == GL_UNSIGNED_INT_2_10_10_10_REV) - && format != GL_RGBA - && format != GL_BGRA) - return Error::from_errno(GL_INVALID_OPERATION); - - if (internal_format != GL_NONE) { - auto const internal_format_is_depth = internal_format == GL_DEPTH_COMPONENT - || internal_format == GL_DEPTH_COMPONENT16 - || internal_format == GL_DEPTH_COMPONENT24 - || internal_format == GL_DEPTH_COMPONENT32; - - if ((target != GL_TEXTURE_2D && target != GL_PROXY_TEXTURE_2D && internal_format_is_depth) - || (format == GL_DEPTH_COMPONENT && !internal_format_is_depth) - || (format != GL_DEPTH_COMPONENT && internal_format_is_depth)) - return Error::from_errno(GL_INVALID_OPERATION); - } - - return get_format_specification(format, type); -} - -GPU::PixelType get_format_specification(GLenum format, GLenum type) -{ - auto get_format = [](GLenum format) -> GPU::PixelFormat { - switch (format) { - case GL_ALPHA: - return GPU::PixelFormat::Alpha; - case GL_BGR: - return GPU::PixelFormat::BGR; - case GL_BGRA: - return GPU::PixelFormat::BGRA; - case GL_BLUE: - return GPU::PixelFormat::Blue; - case GL_COLOR_INDEX: - return GPU::PixelFormat::ColorIndex; - case GL_DEPTH_COMPONENT: - return GPU::PixelFormat::DepthComponent; - case GL_GREEN: - return GPU::PixelFormat::Green; - case GL_LUMINANCE: - return GPU::PixelFormat::Luminance; - case GL_LUMINANCE_ALPHA: - return GPU::PixelFormat::LuminanceAlpha; - case GL_RED: - return GPU::PixelFormat::Red; - case GL_RGB: - return GPU::PixelFormat::RGB; - case GL_RGBA: - return GPU::PixelFormat::RGBA; - case GL_STENCIL_INDEX: - return GPU::PixelFormat::StencilIndex; - } - VERIFY_NOT_REACHED(); - }; - auto pixel_format = get_format(format); - - switch (type) { - case GL_BITMAP: - return { pixel_format, GPU::PixelComponentBits::AllBits, GPU::PixelDataType::Bitmap, GPU::ComponentsOrder::Normal }; - case GL_BYTE: - return { pixel_format, GPU::PixelComponentBits::AllBits, GPU::PixelDataType::Byte, GPU::ComponentsOrder::Normal }; - case GL_FLOAT: - return { pixel_format, GPU::PixelComponentBits::AllBits, GPU::PixelDataType::Float, GPU::ComponentsOrder::Normal }; - case GL_HALF_FLOAT: - return { pixel_format, GPU::PixelComponentBits::AllBits, GPU::PixelDataType::HalfFloat, GPU::ComponentsOrder::Normal }; - case GL_INT: - return { pixel_format, GPU::PixelComponentBits::AllBits, GPU::PixelDataType::Int, GPU::ComponentsOrder::Normal }; - case GL_SHORT: - return { pixel_format, GPU::PixelComponentBits::AllBits, GPU::PixelDataType::Short, GPU::ComponentsOrder::Normal }; - case GL_UNSIGNED_BYTE: - return { pixel_format, GPU::PixelComponentBits::AllBits, GPU::PixelDataType::UnsignedByte, GPU::ComponentsOrder::Normal }; - case GL_UNSIGNED_BYTE_2_3_3_REV: - return { pixel_format, GPU::PixelComponentBits::B2_3_3, GPU::PixelDataType::UnsignedByte, GPU::ComponentsOrder::Reversed }; - case GL_UNSIGNED_BYTE_3_3_2: - return { pixel_format, GPU::PixelComponentBits::B3_3_2, GPU::PixelDataType::UnsignedByte, GPU::ComponentsOrder::Normal }; - case GL_UNSIGNED_INT: - return { pixel_format, GPU::PixelComponentBits::AllBits, GPU::PixelDataType::UnsignedInt, GPU::ComponentsOrder::Normal }; - case GL_UNSIGNED_INT_2_10_10_10_REV: - return { pixel_format, GPU::PixelComponentBits::B2_10_10_10, GPU::PixelDataType::UnsignedInt, GPU::ComponentsOrder::Reversed }; - case GL_UNSIGNED_INT_8_8_8_8: - return { pixel_format, GPU::PixelComponentBits::B8_8_8_8, GPU::PixelDataType::UnsignedInt, GPU::ComponentsOrder::Normal }; - case GL_UNSIGNED_INT_8_8_8_8_REV: - return { pixel_format, GPU::PixelComponentBits::B8_8_8_8, GPU::PixelDataType::UnsignedInt, GPU::ComponentsOrder::Reversed }; - case GL_UNSIGNED_INT_10_10_10_2: - return { pixel_format, GPU::PixelComponentBits::B10_10_10_2, GPU::PixelDataType::UnsignedInt, GPU::ComponentsOrder::Normal }; - case GL_UNSIGNED_SHORT: - return { pixel_format, GPU::PixelComponentBits::AllBits, GPU::PixelDataType::UnsignedShort, GPU::ComponentsOrder::Normal }; - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - return { pixel_format, GPU::PixelComponentBits::B1_5_5_5, GPU::PixelDataType::UnsignedShort, GPU::ComponentsOrder::Reversed }; - case GL_UNSIGNED_SHORT_4_4_4_4: - return { pixel_format, GPU::PixelComponentBits::B4_4_4_4, GPU::PixelDataType::UnsignedShort, GPU::ComponentsOrder::Normal }; - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - return { pixel_format, GPU::PixelComponentBits::B4_4_4_4, GPU::PixelDataType::UnsignedShort, GPU::ComponentsOrder::Reversed }; - case GL_UNSIGNED_SHORT_5_6_5: - return { pixel_format, GPU::PixelComponentBits::B5_6_5, GPU::PixelDataType::UnsignedShort, GPU::ComponentsOrder::Normal }; - case GL_UNSIGNED_SHORT_5_6_5_REV: - return { pixel_format, GPU::PixelComponentBits::B5_6_5, GPU::PixelDataType::UnsignedShort, GPU::ComponentsOrder::Reversed }; - case GL_UNSIGNED_SHORT_5_5_5_1: - return { pixel_format, GPU::PixelComponentBits::B5_5_5_1, GPU::PixelDataType::UnsignedShort, GPU::ComponentsOrder::Normal }; - } - VERIFY_NOT_REACHED(); -} - -GPU::PixelFormat pixel_format_for_internal_format(GLenum internal_format) -{ - // FIXME: add support for all the SRGB formats - - // Numbers 1-4 are supported deprecated values - switch (internal_format) { - case 1: - case GL_ALPHA: - case GL_ALPHA4: - case GL_ALPHA8: - case GL_ALPHA12: - case GL_ALPHA16: - case GL_COMPRESSED_ALPHA: - return GPU::PixelFormat::Alpha; - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT32: - return GPU::PixelFormat::DepthComponent; - case GL_INTENSITY: - case GL_INTENSITY4: - case GL_INTENSITY8: - case GL_INTENSITY12: - case GL_INTENSITY16: - case GL_COMPRESSED_INTENSITY: - return GPU::PixelFormat::Intensity; - case GL_LUMINANCE: - case GL_LUMINANCE4: - case GL_LUMINANCE8: - case GL_LUMINANCE12: - case GL_LUMINANCE16: - case GL_COMPRESSED_LUMINANCE: - return GPU::PixelFormat::Luminance; - case 2: - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE4_ALPHA4: - case GL_LUMINANCE6_ALPHA2: - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE12_ALPHA4: - case GL_LUMINANCE12_ALPHA12: - case GL_LUMINANCE16_ALPHA16: - return GPU::PixelFormat::LuminanceAlpha; - case 3: - case GL_RGB: - case GL_R3_G3_B2: - case GL_RGB4: - case GL_RGB5: - case GL_RGB8: - case GL_RGB10: - case GL_RGB12: - case GL_RGB16: - case GL_COMPRESSED_RGB: - return GPU::PixelFormat::RGB; - case 4: - case GL_RGBA: - case GL_RGBA2: - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGBA8: - case GL_RGB10_A2: - case GL_RGBA12: - case GL_RGBA16: - case GL_COMPRESSED_RGBA: - return GPU::PixelFormat::RGBA; - } - - dbgln("{}({:#x}): unsupported internal format", __FUNCTION__, internal_format); - VERIFY_NOT_REACHED(); -} - -} diff --git a/Userland/Libraries/LibGL/Image.h b/Userland/Libraries/LibGL/Image.h deleted file mode 100644 index ca3ffe1c879..00000000000 --- a/Userland/Libraries/LibGL/Image.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace GL { - -GPU::PixelType get_format_specification(GLenum format, GLenum type); -ErrorOr get_validated_pixel_type(GLenum target, GLenum internal_format, GLenum format, GLenum type); -GPU::PixelFormat pixel_format_for_internal_format(GLenum internal_format); - -} diff --git a/Userland/Libraries/LibGL/Lighting.cpp b/Userland/Libraries/LibGL/Lighting.cpp deleted file mode 100644 index 82639724925..00000000000 --- a/Userland/Libraries/LibGL/Lighting.cpp +++ /dev/null @@ -1,557 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace GL { - -template -void GLContext::get_light_param(GLenum light, GLenum pname, T* params) -{ - auto const& light_state = m_light_states[light - GL_LIGHT0]; - switch (pname) { - case GL_AMBIENT: - params[0] = light_state.ambient_intensity.x(); - params[1] = light_state.ambient_intensity.y(); - params[2] = light_state.ambient_intensity.z(); - params[3] = light_state.ambient_intensity.w(); - break; - case GL_DIFFUSE: - params[0] = light_state.diffuse_intensity.x(); - params[1] = light_state.diffuse_intensity.y(); - params[2] = light_state.diffuse_intensity.z(); - params[3] = light_state.diffuse_intensity.w(); - break; - case GL_SPECULAR: - params[0] = light_state.specular_intensity.x(); - params[1] = light_state.specular_intensity.y(); - params[2] = light_state.specular_intensity.z(); - params[3] = light_state.specular_intensity.w(); - break; - case GL_SPOT_DIRECTION: - params[0] = light_state.spotlight_direction.x(); - params[1] = light_state.spotlight_direction.y(); - params[2] = light_state.spotlight_direction.z(); - break; - case GL_SPOT_EXPONENT: - *params = light_state.spotlight_exponent; - break; - case GL_SPOT_CUTOFF: - *params = light_state.spotlight_cutoff_angle; - break; - case GL_CONSTANT_ATTENUATION: - *params = light_state.constant_attenuation; - break; - case GL_LINEAR_ATTENUATION: - *params = light_state.linear_attenuation; - break; - case GL_QUADRATIC_ATTENUATION: - *params = light_state.quadratic_attenuation; - break; - } -} - -template -void GLContext::get_material_param(Face face, GLenum pname, T* params) -{ - auto const& material = m_material_states[face]; - switch (pname) { - case GL_AMBIENT: - params[0] = static_cast(material.ambient.x()); - params[1] = static_cast(material.ambient.y()); - params[2] = static_cast(material.ambient.z()); - params[3] = static_cast(material.ambient.w()); - break; - case GL_DIFFUSE: - params[0] = static_cast(material.diffuse.x()); - params[1] = static_cast(material.diffuse.y()); - params[2] = static_cast(material.diffuse.z()); - params[3] = static_cast(material.diffuse.w()); - break; - case GL_SPECULAR: - params[0] = static_cast(material.specular.x()); - params[1] = static_cast(material.specular.y()); - params[2] = static_cast(material.specular.z()); - params[3] = static_cast(material.specular.w()); - break; - case GL_EMISSION: - params[0] = static_cast(material.emissive.x()); - params[1] = static_cast(material.emissive.y()); - params[2] = static_cast(material.emissive.z()); - params[3] = static_cast(material.emissive.w()); - break; - case GL_SHININESS: - *params = material.shininess; - break; - } -} - -void GLContext::gl_color_material(GLenum face, GLenum mode) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_color_material, face, mode); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(face != GL_FRONT - && face != GL_BACK - && face != GL_FRONT_AND_BACK, - GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(mode != GL_EMISSION - && mode != GL_AMBIENT - && mode != GL_DIFFUSE - && mode != GL_SPECULAR - && mode != GL_AMBIENT_AND_DIFFUSE, - GL_INVALID_ENUM); - - m_color_material_face = face; - m_color_material_mode = mode; - - m_light_state_is_dirty = true; -} - -void GLContext::gl_get_light(GLenum light, GLenum pname, void* params, GLenum type) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_get_light, light, pname, params, type); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(light < GL_LIGHT0 || light > GL_LIGHT0 + m_device_info.num_lights, GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(!(pname == GL_AMBIENT || pname == GL_DIFFUSE || pname == GL_SPECULAR || pname == GL_SPOT_DIRECTION || pname == GL_SPOT_EXPONENT || pname == GL_SPOT_CUTOFF || pname == GL_CONSTANT_ATTENUATION || pname == GL_LINEAR_ATTENUATION || pname == GL_QUADRATIC_ATTENUATION), GL_INVALID_ENUM); - - if (type == GL_FLOAT) - get_light_param(light, pname, static_cast(params)); - else if (type == GL_INT) - get_light_param(light, pname, static_cast(params)); - else - VERIFY_NOT_REACHED(); -} - -void GLContext::gl_get_material(GLenum face, GLenum pname, void* params, GLenum type) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_get_material, face, pname, params, type); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(!(pname == GL_AMBIENT || pname == GL_DIFFUSE || pname == GL_SPECULAR || pname == GL_EMISSION), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK), GL_INVALID_ENUM); - - Face material_face = Front; - switch (face) { - case GL_FRONT: - material_face = Front; - break; - case GL_BACK: - material_face = Back; - break; - } - - if (type == GL_FLOAT) - get_material_param(material_face, pname, static_cast(params)); - else if (type == GL_INT) - get_material_param(material_face, pname, static_cast(params)); - else - VERIFY_NOT_REACHED(); -} - -void GLContext::gl_light_model(GLenum pname, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_light_model, pname, x, y, z, w); - - RETURN_WITH_ERROR_IF(pname != GL_LIGHT_MODEL_AMBIENT - && pname != GL_LIGHT_MODEL_COLOR_CONTROL - && pname != GL_LIGHT_MODEL_LOCAL_VIEWER - && pname != GL_LIGHT_MODEL_TWO_SIDE, - GL_INVALID_ENUM); - - auto lighting_params = m_rasterizer->light_model(); - - switch (pname) { - case GL_LIGHT_MODEL_AMBIENT: - lighting_params.scene_ambient_color = { x, y, z, w }; - break; - case GL_LIGHT_MODEL_COLOR_CONTROL: { - auto color_control = static_cast(x); - RETURN_WITH_ERROR_IF(color_control != GL_SINGLE_COLOR && color_control != GL_SEPARATE_SPECULAR_COLOR, GL_INVALID_ENUM); - lighting_params.color_control = (color_control == GL_SINGLE_COLOR) ? GPU::ColorControl::SingleColor : GPU::ColorControl::SeparateSpecularColor; - break; - } - case GL_LIGHT_MODEL_LOCAL_VIEWER: - // 0 means the viewer is at infinity - // 1 means they're in local (eye) space - lighting_params.viewer_at_infinity = (x == 0.f); - break; - case GL_LIGHT_MODEL_TWO_SIDE: - lighting_params.two_sided_lighting = (x != 0.f); - break; - default: - VERIFY_NOT_REACHED(); - } - - m_rasterizer->set_light_model_params(lighting_params); -} - -void GLContext::gl_light_modelv(GLenum pname, void const* params, GLenum type) -{ - VERIFY(type == GL_FLOAT || type == GL_INT); - - auto parameters_to_vector = [&](T const* params) -> FloatVector4 { - return (pname == GL_LIGHT_MODEL_AMBIENT) - ? Vector4 { params[0], params[1], params[2], params[3] }.template to_type() - : Vector4 { params[0], 0, 0, 0 }.template to_type(); - }; - - auto light_model_parameters = (type == GL_FLOAT) - ? parameters_to_vector(reinterpret_cast(params)) - : parameters_to_vector(reinterpret_cast(params)); - - // Normalize integers to -1..1 - if (pname == GL_LIGHT_MODEL_AMBIENT && type == GL_INT) - light_model_parameters = (light_model_parameters + 2147483648.f) / 2147483647.5f - 1.f; - - gl_light_model(pname, light_model_parameters[0], light_model_parameters[1], light_model_parameters[2], light_model_parameters[3]); -} - -void GLContext::gl_lightf(GLenum light, GLenum pname, GLfloat param) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_lightf, light, pname, param); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(light < GL_LIGHT0 || light >= (GL_LIGHT0 + m_device_info.num_lights), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(!(pname == GL_CONSTANT_ATTENUATION || pname == GL_LINEAR_ATTENUATION || pname == GL_QUADRATIC_ATTENUATION || pname != GL_SPOT_EXPONENT || pname != GL_SPOT_CUTOFF), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(param < 0.f, GL_INVALID_VALUE); - - auto& light_state = m_light_states.at(light - GL_LIGHT0); - - switch (pname) { - case GL_CONSTANT_ATTENUATION: - light_state.constant_attenuation = param; - break; - case GL_LINEAR_ATTENUATION: - light_state.linear_attenuation = param; - break; - case GL_QUADRATIC_ATTENUATION: - light_state.quadratic_attenuation = param; - break; - case GL_SPOT_EXPONENT: - RETURN_WITH_ERROR_IF(param > 128.f, GL_INVALID_VALUE); - light_state.spotlight_exponent = param; - break; - case GL_SPOT_CUTOFF: - RETURN_WITH_ERROR_IF(param > 90.f && param != 180.f, GL_INVALID_VALUE); - light_state.spotlight_cutoff_angle = param; - break; - default: - VERIFY_NOT_REACHED(); - } - - m_light_state_is_dirty = true; -} - -void GLContext::gl_lightfv(GLenum light, GLenum pname, GLfloat const* params) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_lightfv, light, pname, params); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(light < GL_LIGHT0 || light >= (GL_LIGHT0 + m_device_info.num_lights), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(!(pname == GL_AMBIENT || pname == GL_DIFFUSE || pname == GL_SPECULAR || pname == GL_POSITION || pname == GL_CONSTANT_ATTENUATION || pname == GL_LINEAR_ATTENUATION || pname == GL_QUADRATIC_ATTENUATION || pname == GL_SPOT_CUTOFF || pname == GL_SPOT_EXPONENT || pname == GL_SPOT_DIRECTION), GL_INVALID_ENUM); - - auto& light_state = m_light_states.at(light - GL_LIGHT0); - - switch (pname) { - case GL_AMBIENT: - light_state.ambient_intensity = { params[0], params[1], params[2], params[3] }; - break; - case GL_DIFFUSE: - light_state.diffuse_intensity = { params[0], params[1], params[2], params[3] }; - break; - case GL_SPECULAR: - light_state.specular_intensity = { params[0], params[1], params[2], params[3] }; - break; - case GL_POSITION: - light_state.position = { params[0], params[1], params[2], params[3] }; - light_state.position = model_view_matrix() * light_state.position; - break; - case GL_CONSTANT_ATTENUATION: - RETURN_WITH_ERROR_IF(params[0] < 0.f, GL_INVALID_VALUE); - light_state.constant_attenuation = params[0]; - break; - case GL_LINEAR_ATTENUATION: - RETURN_WITH_ERROR_IF(params[0] < 0.f, GL_INVALID_VALUE); - light_state.linear_attenuation = params[0]; - break; - case GL_QUADRATIC_ATTENUATION: - RETURN_WITH_ERROR_IF(params[0] < 0.f, GL_INVALID_VALUE); - light_state.quadratic_attenuation = params[0]; - break; - case GL_SPOT_EXPONENT: { - auto exponent = params[0]; - RETURN_WITH_ERROR_IF(exponent < 0.f || exponent > 128.f, GL_INVALID_VALUE); - light_state.spotlight_exponent = exponent; - break; - } - case GL_SPOT_CUTOFF: { - auto cutoff = params[0]; - RETURN_WITH_ERROR_IF((cutoff < 0.f || cutoff > 90.f) && cutoff != 180.f, GL_INVALID_VALUE); - light_state.spotlight_cutoff_angle = cutoff; - break; - } - case GL_SPOT_DIRECTION: { - FloatVector4 direction_vector = { params[0], params[1], params[2], 0.f }; - direction_vector = model_view_matrix() * direction_vector; - light_state.spotlight_direction = direction_vector.xyz(); - break; - } - default: - VERIFY_NOT_REACHED(); - } - - m_light_state_is_dirty = true; -} - -void GLContext::gl_lightiv(GLenum light, GLenum pname, GLint const* params) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_lightiv, light, pname, params); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(light < GL_LIGHT0 || light >= (GL_LIGHT0 + m_device_info.num_lights), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(!(pname == GL_AMBIENT || pname == GL_DIFFUSE || pname == GL_SPECULAR || pname == GL_POSITION || pname == GL_CONSTANT_ATTENUATION || pname == GL_LINEAR_ATTENUATION || pname == GL_QUADRATIC_ATTENUATION || pname == GL_SPOT_CUTOFF || pname == GL_SPOT_EXPONENT || pname == GL_SPOT_DIRECTION), GL_INVALID_ENUM); - - auto& light_state = m_light_states[light - GL_LIGHT0]; - - auto const to_float_vector = [](GLfloat x, GLfloat y, GLfloat z, GLfloat w) { - return FloatVector4(x, y, z, w); - }; - - switch (pname) { - case GL_AMBIENT: - light_state.ambient_intensity = to_float_vector(params[0], params[1], params[2], params[3]); - break; - case GL_DIFFUSE: - light_state.diffuse_intensity = to_float_vector(params[0], params[1], params[2], params[3]); - break; - case GL_SPECULAR: - light_state.specular_intensity = to_float_vector(params[0], params[1], params[2], params[3]); - break; - case GL_POSITION: - light_state.position = to_float_vector(params[0], params[1], params[2], params[3]); - light_state.position = model_view_matrix() * light_state.position; - break; - case GL_CONSTANT_ATTENUATION: - RETURN_WITH_ERROR_IF(params[0] < 0, GL_INVALID_VALUE); - light_state.constant_attenuation = static_cast(params[0]); - break; - case GL_LINEAR_ATTENUATION: - RETURN_WITH_ERROR_IF(params[0] < 0, GL_INVALID_VALUE); - light_state.linear_attenuation = static_cast(params[0]); - break; - case GL_QUADRATIC_ATTENUATION: - RETURN_WITH_ERROR_IF(params[0] < 0, GL_INVALID_VALUE); - light_state.quadratic_attenuation = static_cast(params[0]); - break; - case GL_SPOT_EXPONENT: { - auto exponent = static_cast(params[0]); - RETURN_WITH_ERROR_IF(exponent < 0.f || exponent > 128.f, GL_INVALID_VALUE); - light_state.spotlight_exponent = exponent; - break; - } - case GL_SPOT_CUTOFF: { - auto cutoff = static_cast(params[0]); - RETURN_WITH_ERROR_IF((cutoff < 0.f || cutoff > 90.f) && cutoff != 180.f, GL_INVALID_VALUE); - light_state.spotlight_cutoff_angle = cutoff; - break; - } - case GL_SPOT_DIRECTION: { - auto direction_vector = to_float_vector(params[0], params[1], params[2], 0.0f); - direction_vector = model_view_matrix() * direction_vector; - light_state.spotlight_direction = direction_vector.xyz(); - break; - } - default: - VERIFY_NOT_REACHED(); - } - - m_light_state_is_dirty = true; -} - -void GLContext::gl_materialf(GLenum face, GLenum pname, GLfloat param) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_materialf, face, pname, param); - RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(pname != GL_SHININESS, GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(param > 128.0f, GL_INVALID_VALUE); - - switch (face) { - case GL_FRONT: - m_material_states[Face::Front].shininess = param; - break; - case GL_BACK: - m_material_states[Face::Back].shininess = param; - break; - case GL_FRONT_AND_BACK: - m_material_states[Face::Front].shininess = param; - m_material_states[Face::Back].shininess = param; - break; - default: - VERIFY_NOT_REACHED(); - } - - m_light_state_is_dirty = true; -} - -void GLContext::gl_materialfv(GLenum face, GLenum pname, GLfloat const* params) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_materialfv, face, pname, params); - RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(!(pname == GL_AMBIENT || pname == GL_DIFFUSE || pname == GL_SPECULAR || pname == GL_EMISSION || pname == GL_SHININESS || pname == GL_AMBIENT_AND_DIFFUSE), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF((pname == GL_SHININESS && *params > 128.0f), GL_INVALID_VALUE); - - auto update_material = [](GPU::Material& material, GLenum pname, GLfloat const* params) { - switch (pname) { - case GL_AMBIENT: - material.ambient = { params[0], params[1], params[2], params[3] }; - break; - case GL_DIFFUSE: - material.diffuse = { params[0], params[1], params[2], params[3] }; - break; - case GL_SPECULAR: - material.specular = { params[0], params[1], params[2], params[3] }; - break; - case GL_EMISSION: - material.emissive = { params[0], params[1], params[2], params[3] }; - break; - case GL_SHININESS: - material.shininess = params[0]; - break; - case GL_AMBIENT_AND_DIFFUSE: - material.ambient = { params[0], params[1], params[2], params[3] }; - material.diffuse = { params[0], params[1], params[2], params[3] }; - break; - } - }; - - switch (face) { - case GL_FRONT: - update_material(m_material_states[Face::Front], pname, params); - break; - case GL_BACK: - update_material(m_material_states[Face::Back], pname, params); - break; - case GL_FRONT_AND_BACK: - update_material(m_material_states[Face::Front], pname, params); - update_material(m_material_states[Face::Back], pname, params); - break; - } - - m_light_state_is_dirty = true; -} - -void GLContext::gl_materialiv(GLenum face, GLenum pname, GLint const* params) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_materialiv, face, pname, params); - RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(!(pname == GL_AMBIENT || pname == GL_DIFFUSE || pname == GL_SPECULAR || pname == GL_EMISSION || pname == GL_SHININESS || pname == GL_AMBIENT_AND_DIFFUSE), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF((pname == GL_SHININESS && *params > 128), GL_INVALID_VALUE); - - auto update_material = [](GPU::Material& material, GLenum pname, GLint const* params) { - switch (pname) { - case GL_AMBIENT: - material.ambient = { static_cast(params[0]), static_cast(params[1]), static_cast(params[2]), static_cast(params[3]) }; - break; - case GL_DIFFUSE: - material.diffuse = { static_cast(params[0]), static_cast(params[1]), static_cast(params[2]), static_cast(params[3]) }; - break; - case GL_SPECULAR: - material.specular = { static_cast(params[0]), static_cast(params[1]), static_cast(params[2]), static_cast(params[3]) }; - break; - case GL_EMISSION: - material.emissive = { static_cast(params[0]), static_cast(params[1]), static_cast(params[2]), static_cast(params[3]) }; - break; - case GL_SHININESS: - material.shininess = static_cast(params[0]); - break; - case GL_AMBIENT_AND_DIFFUSE: - material.ambient = { static_cast(params[0]), static_cast(params[1]), static_cast(params[2]), static_cast(params[3]) }; - material.diffuse = { static_cast(params[0]), static_cast(params[1]), static_cast(params[2]), static_cast(params[3]) }; - break; - } - }; - - switch (face) { - case GL_FRONT: - update_material(m_material_states[Face::Front], pname, params); - break; - case GL_BACK: - update_material(m_material_states[Face::Back], pname, params); - break; - case GL_FRONT_AND_BACK: - update_material(m_material_states[Face::Front], pname, params); - update_material(m_material_states[Face::Back], pname, params); - break; - } - - m_light_state_is_dirty = true; -} - -void GLContext::gl_shade_model(GLenum mode) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_shade_model, mode); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(mode != GL_FLAT && mode != GL_SMOOTH, GL_INVALID_ENUM); - - auto options = m_rasterizer->options(); - options.shade_smooth = (mode == GL_SMOOTH); - m_rasterizer->set_options(options); -} - -void GLContext::sync_light_state() -{ - if (!m_light_state_is_dirty) - return; - - m_light_state_is_dirty = false; - - auto options = m_rasterizer->options(); - options.color_material_enabled = m_color_material_enabled; - switch (m_color_material_face) { - case GL_BACK: - options.color_material_face = GPU::ColorMaterialFace::Back; - break; - case GL_FRONT: - options.color_material_face = GPU::ColorMaterialFace::Front; - break; - case GL_FRONT_AND_BACK: - options.color_material_face = GPU::ColorMaterialFace::FrontAndBack; - break; - default: - VERIFY_NOT_REACHED(); - } - switch (m_color_material_mode) { - case GL_AMBIENT: - options.color_material_mode = GPU::ColorMaterialMode::Ambient; - break; - case GL_AMBIENT_AND_DIFFUSE: - options.color_material_mode = GPU::ColorMaterialMode::AmbientAndDiffuse; - break; - case GL_DIFFUSE: - options.color_material_mode = GPU::ColorMaterialMode::Diffuse; - break; - case GL_EMISSION: - options.color_material_mode = GPU::ColorMaterialMode::Emissive; - break; - case GL_SPECULAR: - options.color_material_mode = GPU::ColorMaterialMode::Specular; - break; - default: - VERIFY_NOT_REACHED(); - } - m_rasterizer->set_options(options); - - for (auto light_id = 0u; light_id < m_device_info.num_lights; light_id++) { - auto const& current_light_state = m_light_states.at(light_id); - m_rasterizer->set_light_state(light_id, current_light_state); - } - - m_rasterizer->set_material_state(GPU::Face::Front, m_material_states[Face::Front]); - m_rasterizer->set_material_state(GPU::Face::Back, m_material_states[Face::Back]); -} - -} diff --git a/Userland/Libraries/LibGL/List.cpp b/Userland/Libraries/LibGL/List.cpp deleted file mode 100644 index 672885fd2f8..00000000000 --- a/Userland/Libraries/LibGL/List.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -namespace GL { - -void GLContext::gl_call_list(GLuint list) -{ - if (m_gl_call_depth > max_allowed_gl_call_depth) - return; - - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_call_list, list); - - if (m_listings.size() < list) - return; - - TemporaryChange change { m_gl_call_depth, m_gl_call_depth + 1 }; - - invoke_list(list); -} - -void GLContext::gl_call_lists(GLsizei n, GLenum type, void const* lists) -{ - if (m_gl_call_depth > max_allowed_gl_call_depth) - return; - - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_call_lists, n, type, lists); - - RETURN_WITH_ERROR_IF(n < 0, GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(!(type == GL_BYTE - || type == GL_UNSIGNED_BYTE - || type == GL_SHORT - || type == GL_UNSIGNED_SHORT - || type == GL_INT - || type == GL_UNSIGNED_INT - || type == GL_FLOAT - || type == GL_2_BYTES - || type == GL_3_BYTES - || type == GL_4_BYTES), - GL_INVALID_ENUM); - - TemporaryChange change { m_gl_call_depth, m_gl_call_depth + 1 }; - - auto invoke_all_lists = [&](T const* lists) { - for (int i = 0; i < n; ++i) { - auto list = static_cast(lists[i]); - invoke_list(m_list_base + list); - } - }; - switch (type) { - case GL_BYTE: - invoke_all_lists(static_cast(lists)); - break; - case GL_UNSIGNED_BYTE: - invoke_all_lists(static_cast(lists)); - break; - case GL_SHORT: - invoke_all_lists(static_cast(lists)); - break; - case GL_UNSIGNED_SHORT: - invoke_all_lists(static_cast(lists)); - break; - case GL_INT: - invoke_all_lists(static_cast(lists)); - break; - case GL_UNSIGNED_INT: - invoke_all_lists(static_cast(lists)); - break; - case GL_FLOAT: - invoke_all_lists(static_cast(lists)); - break; - case GL_2_BYTES: - case GL_3_BYTES: - case GL_4_BYTES: - dbgln("GLContext FIXME: unimplemented glCallLists() with type {}", type); - break; - default: - VERIFY_NOT_REACHED(); - } -} - -void GLContext::gl_delete_lists(GLuint list, GLsizei range) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(range < 0, GL_INVALID_VALUE); - - if (m_listings.size() < list || m_listings.size() <= list + range) - return; - - for (auto& entry : m_listings.span().slice(list - 1, range)) - entry.entries.clear_with_capacity(); -} - -void GLContext::gl_end_list() -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(!m_current_listing_index.has_value(), GL_INVALID_OPERATION); - - m_listings[m_current_listing_index->index] = move(m_current_listing_index->listing); - m_current_listing_index.clear(); -} - -GLuint GLContext::gl_gen_lists(GLsizei range) -{ - RETURN_VALUE_WITH_ERROR_IF(range <= 0, GL_INVALID_VALUE, 0); - RETURN_VALUE_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION, 0); - - auto initial_entry = m_listings.size(); - m_listings.resize(range + initial_entry); - return initial_entry + 1; -} - -GLboolean GLContext::gl_is_list(GLuint list) -{ - RETURN_VALUE_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION, GL_FALSE); - - return list < m_listings.size() ? GL_TRUE : GL_FALSE; -} - -void GLContext::gl_list_base(GLuint base) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_list_base, base); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - m_list_base = base; -} - -void GLContext::gl_new_list(GLuint list, GLenum mode) -{ - RETURN_WITH_ERROR_IF(list == 0, GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(mode != GL_COMPILE && mode != GL_COMPILE_AND_EXECUTE, GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(m_current_listing_index.has_value(), GL_INVALID_OPERATION); - - if (m_listings.size() < list) - return; - - m_current_listing_index = CurrentListing { {}, static_cast(list - 1), mode }; -} - -void GLContext::invoke_list(size_t list_index) -{ - auto& listing = m_listings[list_index - 1]; - for (auto& entry : listing.entries) { - entry.function.visit([&](auto& function) { - entry.arguments.visit([&](auto& arguments) { - auto apply = [&](Args&&... args) { - if constexpr (requires { (this->*function)(forward(args)...); }) - (this->*function)(forward(args)...); - }; - - arguments.apply_as_args(apply); - }); - }); - } -} - -} diff --git a/Userland/Libraries/LibGL/Matrix.cpp b/Userland/Libraries/LibGL/Matrix.cpp deleted file mode 100644 index 2883c41edf5..00000000000 --- a/Userland/Libraries/LibGL/Matrix.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -namespace GL { - -static constexpr size_t matrix_stack_limit(GLenum matrix_mode) -{ - switch (matrix_mode) { - case GL_MODELVIEW: - return MODELVIEW_MATRIX_STACK_LIMIT; - case GL_PROJECTION: - return PROJECTION_MATRIX_STACK_LIMIT; - case GL_TEXTURE: - return TEXTURE_MATRIX_STACK_LIMIT; - } - VERIFY_NOT_REACHED(); -} - -void GLContext::gl_frustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_frustum, left, right, bottom, top, near_val, far_val); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(near_val < 0 || far_val < 0, GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(left == right || bottom == top || near_val == far_val, GL_INVALID_VALUE); - - // Let's do some math! - auto a = static_cast((right + left) / (right - left)); - auto b = static_cast((top + bottom) / (top - bottom)); - auto c = static_cast(-((far_val + near_val) / (far_val - near_val))); - auto d = static_cast(-((2 * far_val * near_val) / (far_val - near_val))); - - FloatMatrix4x4 frustum { - static_cast(2 * near_val / (right - left)), 0, a, 0, - 0, static_cast(2 * near_val / (top - bottom)), b, 0, - 0, 0, c, d, - 0, 0, -1, 0 - }; - update_current_matrix(*m_current_matrix * frustum); -} - -void GLContext::gl_load_identity() -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_load_identity); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - update_current_matrix(FloatMatrix4x4::identity()); -} - -void GLContext::gl_load_matrix(FloatMatrix4x4 const& matrix) -{ - APPEND_TO_CALL_LIST_WITH_ARG_AND_RETURN_IF_NEEDED(gl_load_matrix, matrix); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - update_current_matrix(matrix); -} - -void GLContext::gl_matrix_mode(GLenum mode) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_matrix_mode, mode); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(mode < GL_MODELVIEW || mode > GL_TEXTURE, GL_INVALID_ENUM); - - m_current_matrix_mode = mode; - switch (mode) { - case GL_MODELVIEW: - m_current_matrix_stack = &m_model_view_matrix_stack; - break; - case GL_PROJECTION: - m_current_matrix_stack = &m_projection_matrix_stack; - break; - case GL_TEXTURE: - m_current_matrix_stack = &m_active_texture_unit->texture_matrix_stack(); - break; - default: - VERIFY_NOT_REACHED(); - } - m_current_matrix = &m_current_matrix_stack->last(); -} - -void GLContext::gl_mult_matrix(FloatMatrix4x4 const& matrix) -{ - APPEND_TO_CALL_LIST_WITH_ARG_AND_RETURN_IF_NEEDED(gl_mult_matrix, matrix); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - update_current_matrix(*m_current_matrix * matrix); -} - -void GLContext::gl_ortho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_ortho, left, right, bottom, top, near_val, far_val); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(left == right || bottom == top || near_val == far_val, GL_INVALID_VALUE); - - auto rl = right - left; - auto tb = top - bottom; - auto fn = far_val - near_val; - auto tx = -(right + left) / rl; - auto ty = -(top + bottom) / tb; - auto tz = -(far_val + near_val) / fn; - - FloatMatrix4x4 projection { - static_cast(2 / rl), 0, 0, static_cast(tx), - 0, static_cast(2 / tb), 0, static_cast(ty), - 0, 0, static_cast(-2 / fn), static_cast(tz), - 0, 0, 0, 1 - }; - update_current_matrix(*m_current_matrix * projection); -} - -void GLContext::gl_pop_matrix() -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_pop_matrix); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(m_current_matrix_stack->size() <= 1, GL_STACK_UNDERFLOW); - - m_current_matrix_stack->take_last(); - m_current_matrix = &m_current_matrix_stack->last(); - m_matrices_dirty = true; -} - -void GLContext::gl_push_matrix() -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_push_matrix); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(m_current_matrix_stack->size() >= matrix_stack_limit(m_current_matrix_mode), GL_STACK_OVERFLOW); - - m_current_matrix_stack->append(*m_current_matrix); - m_current_matrix = &m_current_matrix_stack->last(); - m_matrices_dirty = true; -} - -void GLContext::gl_rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_rotate, angle, x, y, z); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - FloatVector3 axis = { x, y, z }; - if (axis.length() > 0.f) - axis.normalize(); - auto rotation_mat = Gfx::rotation_matrix(axis, AK::to_radians(angle)); - update_current_matrix(*m_current_matrix * rotation_mat); -} - -void GLContext::gl_scale(GLfloat x, GLfloat y, GLfloat z) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_scale, x, y, z); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - auto scale_matrix = Gfx::scale_matrix(FloatVector3 { x, y, z }); - update_current_matrix(*m_current_matrix * scale_matrix); -} - -void GLContext::gl_translate(GLfloat x, GLfloat y, GLfloat z) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_translate, x, y, z); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - auto translation_matrix = Gfx::translation_matrix(FloatVector3 { x, y, z }); - update_current_matrix(*m_current_matrix * translation_matrix); -} - -void GLContext::sync_matrices() -{ - if (!m_matrices_dirty) - return; - - m_rasterizer->set_model_view_transform(model_view_matrix()); - m_rasterizer->set_projection_transform(projection_matrix()); - - m_matrices_dirty = false; -} - -} diff --git a/Userland/Libraries/LibGL/NameAllocator.cpp b/Userland/Libraries/LibGL/NameAllocator.cpp deleted file mode 100644 index 3c5d0619efc..00000000000 --- a/Userland/Libraries/LibGL/NameAllocator.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace GL { - -void NameAllocator::allocate(GLsizei count, GLuint* names) -{ - for (auto i = 0; i < count; ++i) { - if (!m_free_names.is_empty()) { - names[i] = m_free_names.top(); - m_free_names.pop(); - } else { - // We're out of free previously allocated names. Let's allocate a new contiguous amount from the - // last known id - names[i] = m_last_id++; - } - } -} - -void NameAllocator::free(GLuint name) -{ - m_free_names.push(name); -} - -bool NameAllocator::has_allocated_name(GLuint name) const -{ - return name < m_last_id && !m_free_names.contains_slow(name); -} - -} diff --git a/Userland/Libraries/LibGL/NameAllocator.h b/Userland/Libraries/LibGL/NameAllocator.h deleted file mode 100644 index 186f211b3fd..00000000000 --- a/Userland/Libraries/LibGL/NameAllocator.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace GL { - -class NameAllocator { -public: - NameAllocator() = default; - - void allocate(GLsizei count, GLuint* names); - void free(GLuint name); - bool has_allocated_name(GLuint name) const; - -private: - Stack m_free_names; - GLuint m_last_id { 1 }; -}; - -} diff --git a/Userland/Libraries/LibGL/Shader.cpp b/Userland/Libraries/LibGL/Shader.cpp deleted file mode 100644 index 4dedb9dce92..00000000000 --- a/Userland/Libraries/LibGL/Shader.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -namespace GL { - -GLuint GLContext::gl_create_shader(GLenum shader_type) -{ - // FIXME: Add support for GL_COMPUTE_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER and GL_GEOMETRY_SHADER. - RETURN_VALUE_WITH_ERROR_IF(shader_type != GL_VERTEX_SHADER - && shader_type != GL_FRAGMENT_SHADER, - GL_INVALID_ENUM, - 0); - - GLuint shader_name; - m_shader_name_allocator.allocate(1, &shader_name); - auto shader = Shader::create(shader_type); - m_allocated_shaders.set(shader_name, shader); - return shader_name; -} - -void GLContext::gl_delete_shader(GLuint shader) -{ - // "A value of 0 for shader will be silently ignored." (https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDeleteShader.xhtml) - if (shader == 0) - return; - - auto it = m_allocated_shaders.find(shader); - RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_VALUE); - - // FIXME: According to the spec, we should only flag the shader for deletion here and delete it once it is detached from all programs. - m_allocated_shaders.remove(it); - m_shader_name_allocator.free(shader); -} - -void GLContext::gl_shader_source(GLuint shader, GLsizei count, GLchar const** string, GLint const* length) -{ - auto it = m_allocated_shaders.find(shader); - // FIXME: implement check "GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL." - RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(count < 0, GL_INVALID_VALUE); - - it->value->clear_sources(); - for (int i = 0; i < count; i++) { - if (length == nullptr || length[i] < 0) { - auto result = it->value->add_source(StringView(string[i], strlen(string[i]))); - RETURN_WITH_ERROR_IF(result.is_error() && result.error().is_errno() && result.error().code() == ENOMEM, GL_OUT_OF_MEMORY); - RETURN_WITH_ERROR_IF(result.is_error(), GL_INVALID_OPERATION); - } else { - auto result = it->value->add_source(StringView(string[i], length[i])); - RETURN_WITH_ERROR_IF(result.is_error() && result.error().is_errno() && result.error().code() == ENOMEM, GL_OUT_OF_MEMORY); - RETURN_WITH_ERROR_IF(result.is_error(), GL_INVALID_OPERATION); - } - } -} - -void GLContext::gl_compile_shader(GLuint shader) -{ - auto it = m_allocated_shaders.find(shader); - // FIXME: implement check "GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL." - RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_OPERATION); - - // NOTE: We are ignoring the compilation result here since it is tracked inside the shader object - (void)it->value->compile(); -} - -void GLContext::gl_get_shader(GLuint shader, GLenum pname, GLint* params) -{ - RETURN_WITH_ERROR_IF(pname != GL_SHADER_TYPE - && pname != GL_DELETE_STATUS - && pname != GL_COMPILE_STATUS - && pname != GL_INFO_LOG_LENGTH - && pname != GL_SHADER_SOURCE_LENGTH, - GL_INVALID_ENUM); - - // FIXME: implement check "GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL." - // FIXME: implement check "GL_INVALID_OPERATION is generated if pname is GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH, or GL_SHADER_SOURCE_LENGTH but a shader compiler is not supported." - - auto it = m_allocated_shaders.find(shader); - RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_OPERATION); - - switch (pname) { - case GL_SHADER_TYPE: - *params = it->value->type(); - break; - - case GL_DELETE_STATUS: - // FIXME: Return the actual delete status once we implement this missing feature - *params = GL_FALSE; - break; - - case GL_COMPILE_STATUS: - *params = it->value->compile_status() ? GL_TRUE : GL_FALSE; - break; - - case GL_INFO_LOG_LENGTH: - *params = it->value->info_log_length(); - break; - - case GL_SHADER_SOURCE_LENGTH: - *params = it->value->combined_source_length(); - break; - - default: - VERIFY_NOT_REACHED(); - } -} - -GLuint GLContext::gl_create_program() -{ - GLuint program_name; - m_program_name_allocator.allocate(1, &program_name); - auto program = Program::create(); - m_allocated_programs.set(program_name, program); - return program_name; -} - -void GLContext::gl_delete_program(GLuint program) -{ - // "A value of 0 for program will be silently ignored." (https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDeleteProgram.xhtml) - if (program == 0) - return; - - auto it = m_allocated_programs.find(program); - RETURN_WITH_ERROR_IF(it == m_allocated_programs.end(), GL_INVALID_VALUE); - - // FIXME: According to the spec, we should only flag the program for deletion here and delete it once it is not used anymore. - m_allocated_programs.remove(it); - m_program_name_allocator.free(program); -} - -void GLContext::gl_attach_shader(GLuint program, GLuint shader) -{ - auto program_it = m_allocated_programs.find(program); - auto shader_it = m_allocated_shaders.find(shader); - // FIXME: implement check "GL_INVALID_VALUE is generated if either program or shader is not a value generated by OpenGL." - RETURN_WITH_ERROR_IF(program_it == m_allocated_programs.end(), GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(shader_it == m_allocated_shaders.end(), GL_INVALID_OPERATION); - - // NOTE: attach_result is Error if the shader is already attached to this program - auto attach_result = program_it->value->attach_shader(*shader_it->value); - RETURN_WITH_ERROR_IF(attach_result.is_error() && attach_result.error().is_errno() && attach_result.error().code() == ENOMEM, GL_OUT_OF_MEMORY); - RETURN_WITH_ERROR_IF(attach_result.is_error(), GL_INVALID_OPERATION); -} - -void GLContext::gl_link_program(GLuint program) -{ - auto program_it = m_allocated_programs.find(program); - // FIXME: implement check "GL_INVALID_VALUE is generated if program is not a value generated by OpenGL." - RETURN_WITH_ERROR_IF(program_it == m_allocated_programs.end(), GL_INVALID_OPERATION); - // FIXME: implement check "GL_INVALID_OPERATION is generated if program is the currently active program object and transform feedback mode is active." - - // NOTE: We are ignoring the link result since this is tracked inside the program object - (void)program_it->value->link(*m_rasterizer); -} - -void GLContext::gl_use_program(GLuint program) -{ - if (program == 0) { - m_current_program = nullptr; - return; - } - - auto it = m_allocated_programs.find(program); - - // FIXME: implement check "GL_INVALID_VALUE is generated if program is not a value generated by OpenGL." - RETURN_WITH_ERROR_IF(it == m_allocated_programs.end(), GL_INVALID_OPERATION); - // FIXME: implement check "GL_INVALID_OPERATION is generated if transform feedback mode is active." - RETURN_WITH_ERROR_IF(it->value->link_status() != true, GL_INVALID_OPERATION); - - m_current_program = it->value; -} - -void GLContext::gl_get_program(GLuint program, GLenum pname, GLint* params) -{ - auto it = m_allocated_programs.find(program); - - // FIXME: implement check "GL_INVALID_VALUE is generated if program is not a value generated by OpenGL." - RETURN_WITH_ERROR_IF(it == m_allocated_programs.end(), GL_INVALID_OPERATION); - // FIXME: implement check "GL_INVALID_OPERATION is generated if pname is GL_GEOMETRY_VERTICES_OUT, GL_GEOMETRY_INPUT_TYPE, or GL_GEOMETRY_OUTPUT_TYPE, and program does not contain a geometry shader." - - // FIXME: implement all the other allowed pname values (https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetProgram.xhtml) - RETURN_WITH_ERROR_IF(pname != GL_DELETE_STATUS - && pname != GL_LINK_STATUS - && pname != GL_INFO_LOG_LENGTH, - GL_INVALID_ENUM); - - // FIXME: implement check "GL_INVALID_OPERATION is generated if pname is GL_COMPUTE_WORK_GROUP_SIZE and program does not contain a binary for the compute shader stage." - - switch (pname) { - case GL_DELETE_STATUS: - // FIXME: Return the actual delete status once we implement this missing feature - *params = GL_FALSE; - break; - - case GL_LINK_STATUS: - *params = it->value->link_status() ? GL_TRUE : GL_FALSE; - break; - - case GL_INFO_LOG_LENGTH: - *params = it->value->info_log_length(); - break; - - default: - VERIFY_NOT_REACHED(); - } -} - -} diff --git a/Userland/Libraries/LibGL/Shaders/Program.cpp b/Userland/Libraries/LibGL/Shaders/Program.cpp deleted file mode 100644 index ca7e5e7f48c..00000000000 --- a/Userland/Libraries/LibGL/Shaders/Program.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace GL { - -NonnullRefPtr Program::create() -{ - return adopt_ref(*new Program()); -} - -bool Program::is_shader_attached(Shader const& shader) const -{ - switch (shader.type()) { - case GL_VERTEX_SHADER: - return m_vertex_shaders.contains_slow(shader); - case GL_FRAGMENT_SHADER: - return m_fragment_shaders.contains_slow(shader); - default: - VERIFY_NOT_REACHED(); - } -} - -ErrorOr Program::attach_shader(Shader& shader) -{ - if (is_shader_attached(shader)) - return Error::from_string_literal("Trying to attach a shader that is already attached"); - - switch (shader.type()) { - case GL_VERTEX_SHADER: - TRY(m_vertex_shaders.try_append(shader)); - break; - - case GL_FRAGMENT_SHADER: - TRY(m_fragment_shaders.try_append(shader)); - break; - - default: - VERIFY_NOT_REACHED(); - } - - return {}; -} - -ErrorOr Program::link(GPU::Device& device) -{ - m_info_log = String {}; - - GLSL::Linker linker; - - // Link vertex shader objects - - Vector vertex_shader_object_files; - for (auto const& vertex_shader : m_vertex_shaders) - vertex_shader_object_files.append(vertex_shader->object_file()); - - auto linked_vertex_shader_or_error = linker.link(vertex_shader_object_files); - - if (linked_vertex_shader_or_error.is_error()) { - m_link_status = false; - m_info_log = linker.messages(); - return linked_vertex_shader_or_error.release_error(); - } - - m_linked_vertex_shader = linked_vertex_shader_or_error.release_value(); - - // Link fragment shader objects - - Vector fragment_shader_object_files; - for (auto fragment_shader : m_fragment_shaders) - fragment_shader_object_files.append(fragment_shader->object_file()); - - auto linked_fragment_shader_or_error = linker.link(fragment_shader_object_files); - - if (linked_fragment_shader_or_error.is_error()) { - m_link_status = false; - m_info_log = linker.messages(); - return linked_fragment_shader_or_error.release_error(); - } - - m_linked_fragment_shader = linked_fragment_shader_or_error.release_value(); - - m_gpu_vertex_shader = TRY(device.create_shader(m_linked_vertex_shader->intermediate_shader_representation())); - m_gpu_fragment_shader = TRY(device.create_shader(m_linked_fragment_shader->intermediate_shader_representation())); - - m_link_status = true; - return {}; -} - -size_t Program::info_log_length() const -{ - if (!m_info_log.has_value()) - return 0; - - // Per the spec we return the size including the null terminator - return m_info_log.value().bytes().size() + 1; -} - -} diff --git a/Userland/Libraries/LibGL/Shaders/Program.h b/Userland/Libraries/LibGL/Shaders/Program.h deleted file mode 100644 index a5760ee188c..00000000000 --- a/Userland/Libraries/LibGL/Shaders/Program.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace GL { - -class Program final : public RefCounted { -public: - static NonnullRefPtr create(); - - bool is_shader_attached(Shader const&) const; - ErrorOr attach_shader(Shader&); - ErrorOr link(GPU::Device&); - bool link_status() const { return m_link_status; } - size_t info_log_length() const; - -private: - bool m_link_status { false }; - Vector> m_vertex_shaders; - Vector> m_fragment_shaders; - Optional m_info_log; - OwnPtr m_linked_vertex_shader; - OwnPtr m_linked_fragment_shader; - RefPtr m_gpu_vertex_shader; - RefPtr m_gpu_fragment_shader; -}; - -} diff --git a/Userland/Libraries/LibGL/Shaders/Shader.cpp b/Userland/Libraries/LibGL/Shaders/Shader.cpp deleted file mode 100644 index 7e2a1a82cba..00000000000 --- a/Userland/Libraries/LibGL/Shaders/Shader.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace GL { - -NonnullRefPtr Shader::create(GLenum shader_type) -{ - return adopt_ref(*new Shader(shader_type)); -} - -ErrorOr Shader::add_source(StringView source_code) -{ - auto source_code_content = TRY(String::from_utf8(source_code)); - TRY(m_sources.try_append(move(source_code_content))); - return {}; -} - -ErrorOr Shader::compile() -{ - m_info_log = String {}; - - GLSL::Compiler compiler; - - auto object_file_or_error = compiler.compile(m_sources); - - if (object_file_or_error.is_error()) { - m_compile_status = false; - m_info_log = compiler.messages(); - return object_file_or_error.release_error(); - } - - m_object_file = object_file_or_error.release_value(); - - m_compile_status = true; - - return {}; -} - -size_t Shader::info_log_length() const -{ - if (!m_info_log.has_value()) - return 0; - - // Per the spec we return the size including the null terminator - return m_info_log.value().bytes().size() + 1; -} - -size_t Shader::combined_source_length() const -{ - if (m_sources.is_empty()) - return 0; - - size_t combined_size = 0; - for (auto source : m_sources) - combined_size += source.bytes().size(); - - // Per the spec we return the size including the null terminator - return combined_size + 1; -} - -} diff --git a/Userland/Libraries/LibGL/Shaders/Shader.h b/Userland/Libraries/LibGL/Shaders/Shader.h deleted file mode 100644 index c4662ecbd6d..00000000000 --- a/Userland/Libraries/LibGL/Shaders/Shader.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace GL { - -class Shader final : public RefCounted { -public: - static NonnullRefPtr create(GLenum shader_type); - - void clear_sources() { m_sources.clear(); } - ErrorOr add_source(StringView source_code); - ErrorOr compile(); - GLenum type() const { return m_type; } - bool compile_status() const { return m_compile_status; } - GLSL::ObjectFile const* object_file() const { return m_object_file.ptr(); } - - size_t info_log_length() const; - size_t combined_source_length() const; - -private: - explicit Shader(GLenum shader_type) - : m_type { shader_type } - { - } - - Vector m_sources; - GLenum m_type; - bool m_compile_status { false }; - Optional m_info_log; - OwnPtr m_object_file; -}; - -} diff --git a/Userland/Libraries/LibGL/Stencil.cpp b/Userland/Libraries/LibGL/Stencil.cpp deleted file mode 100644 index 95e77dd9c1a..00000000000 --- a/Userland/Libraries/LibGL/Stencil.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace GL { - -void GLContext::gl_clear_stencil(GLint s) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_stencil, s); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - m_clear_stencil = static_cast(s & ((1 << m_device_info.stencil_bits) - 1)); -} - -void GLContext::gl_stencil_func_separate(GLenum face, GLenum func, GLint ref, GLuint mask) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_stencil_func_separate, face, func, ref, mask); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM); - - RETURN_WITH_ERROR_IF(!(func == GL_NEVER - || func == GL_LESS - || func == GL_LEQUAL - || func == GL_GREATER - || func == GL_GEQUAL - || func == GL_EQUAL - || func == GL_NOTEQUAL - || func == GL_ALWAYS), - GL_INVALID_ENUM); - - ref = clamp(ref, 0, (1 << m_device_info.stencil_bits) - 1); - - StencilFunctionOptions new_options = { func, ref, mask }; - if (face == GL_FRONT || face == GL_FRONT_AND_BACK) - m_stencil_function[Face::Front] = new_options; - if (face == GL_BACK || face == GL_FRONT_AND_BACK) - m_stencil_function[Face::Back] = new_options; - - m_stencil_configuration_dirty = true; -} - -void GLContext::gl_stencil_mask_separate(GLenum face, GLuint mask) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_stencil_mask_separate, face, mask); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - if (face == GL_FRONT || face == GL_FRONT_AND_BACK) - m_stencil_operation[Face::Front].write_mask = mask; - if (face == GL_BACK || face == GL_FRONT_AND_BACK) - m_stencil_operation[Face::Back].write_mask = mask; - - m_stencil_configuration_dirty = true; -} - -void GLContext::gl_stencil_op_separate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_stencil_op_separate, face, sfail, dpfail, dppass); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM); - - auto is_valid_op = [](GLenum op) -> bool { - return op == GL_KEEP || op == GL_ZERO || op == GL_REPLACE || op == GL_INCR || op == GL_INCR_WRAP - || op == GL_DECR || op == GL_DECR_WRAP || op == GL_INVERT; - }; - RETURN_WITH_ERROR_IF(!is_valid_op(sfail), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(!is_valid_op(dpfail), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(!is_valid_op(dppass), GL_INVALID_ENUM); - - auto update_stencil_operation = [&](Face face, GLenum sfail, GLenum dpfail, GLenum dppass) { - auto& stencil_operation = m_stencil_operation[face]; - stencil_operation.op_fail = sfail; - stencil_operation.op_depth_fail = dpfail; - stencil_operation.op_pass = dppass; - }; - if (face == GL_FRONT || face == GL_FRONT_AND_BACK) - update_stencil_operation(Face::Front, sfail, dpfail, dppass); - if (face == GL_BACK || face == GL_FRONT_AND_BACK) - update_stencil_operation(Face::Back, sfail, dpfail, dppass); - - m_stencil_configuration_dirty = true; -} - -void GLContext::sync_stencil_configuration() -{ - if (!m_stencil_configuration_dirty) - return; - m_stencil_configuration_dirty = false; - - auto set_device_stencil = [&](GPU::Face face, StencilFunctionOptions func, StencilOperationOptions op) { - GPU::StencilConfiguration device_configuration; - - // Stencil test function - auto map_func = [](GLenum func) -> GPU::StencilTestFunction { - switch (func) { - case GL_ALWAYS: - return GPU::StencilTestFunction::Always; - case GL_EQUAL: - return GPU::StencilTestFunction::Equal; - case GL_GEQUAL: - return GPU::StencilTestFunction::GreaterOrEqual; - case GL_GREATER: - return GPU::StencilTestFunction::Greater; - case GL_LESS: - return GPU::StencilTestFunction::Less; - case GL_LEQUAL: - return GPU::StencilTestFunction::LessOrEqual; - case GL_NEVER: - return GPU::StencilTestFunction::Never; - case GL_NOTEQUAL: - return GPU::StencilTestFunction::NotEqual; - } - VERIFY_NOT_REACHED(); - }; - device_configuration.test_function = map_func(func.func); - device_configuration.reference_value = func.reference_value; - device_configuration.test_mask = func.mask; - - // Stencil operation - auto map_operation = [](GLenum operation) -> GPU::StencilOperation { - switch (operation) { - case GL_DECR: - return GPU::StencilOperation::Decrement; - case GL_DECR_WRAP: - return GPU::StencilOperation::DecrementWrap; - case GL_INCR: - return GPU::StencilOperation::Increment; - case GL_INCR_WRAP: - return GPU::StencilOperation::IncrementWrap; - case GL_INVERT: - return GPU::StencilOperation::Invert; - case GL_KEEP: - return GPU::StencilOperation::Keep; - case GL_REPLACE: - return GPU::StencilOperation::Replace; - case GL_ZERO: - return GPU::StencilOperation::Zero; - } - VERIFY_NOT_REACHED(); - }; - device_configuration.on_stencil_test_fail = map_operation(op.op_fail); - device_configuration.on_depth_test_fail = map_operation(op.op_depth_fail); - device_configuration.on_pass = map_operation(op.op_pass); - device_configuration.write_mask = op.write_mask; - - m_rasterizer->set_stencil_configuration(face, device_configuration); - }; - set_device_stencil(GPU::Face::Front, m_stencil_function[Face::Front], m_stencil_operation[Face::Front]); - set_device_stencil(GPU::Face::Back, m_stencil_function[Face::Back], m_stencil_operation[Face::Back]); -} - -} diff --git a/Userland/Libraries/LibGL/Tex/Sampler2D.h b/Userland/Libraries/LibGL/Tex/Sampler2D.h deleted file mode 100644 index 14fa510f2aa..00000000000 --- a/Userland/Libraries/LibGL/Tex/Sampler2D.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jesse Buhagiar - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace GL { - -class Sampler2D final { -public: - GLint min_filter() const { return m_min_filter; } - GLint mag_filter() const { return m_mag_filter; } - GLint wrap_s_mode() const { return m_wrap_s_mode; } - GLint wrap_t_mode() const { return m_wrap_t_mode; } - FloatVector4 const& border_color() const { return m_border_color; } - - void set_min_filter(GLint value) { m_min_filter = value; } - void set_mag_filter(GLint value) { m_mag_filter = value; } - void set_wrap_s_mode(GLint value) { m_wrap_s_mode = value; } - void set_wrap_t_mode(GLint value) { m_wrap_t_mode = value; } - void set_border_color(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { m_border_color = { r, g, b, a }; } - -private: - GLint m_min_filter { GL_NEAREST_MIPMAP_LINEAR }; - GLint m_mag_filter { GL_LINEAR }; - GLint m_wrap_s_mode { GL_REPEAT }; - GLint m_wrap_t_mode { GL_REPEAT }; - - FloatVector4 m_border_color { 0.0f, 0.0f, 0.0f, 0.0f }; -}; -} diff --git a/Userland/Libraries/LibGL/Tex/Texture.h b/Userland/Libraries/LibGL/Tex/Texture.h deleted file mode 100644 index 5c29fcde7f1..00000000000 --- a/Userland/Libraries/LibGL/Tex/Texture.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace GL { - -class Texture : public RefCounted { -public: - virtual ~Texture() = default; - - virtual bool is_texture_1d() const { return false; } - virtual bool is_texture_2d() const { return false; } - virtual bool is_texture_3d() const { return false; } - virtual bool is_cube_map() const { return false; } - - RefPtr device_image() const { return m_device_image; } - RefPtr device_image() { return m_device_image; } - void set_device_image(RefPtr image) { m_device_image = image; } - - float level_of_detail_bias() const { return m_level_of_detail_bias; } - void set_level_of_detail_bias(float level_of_detail_bias) { m_level_of_detail_bias = level_of_detail_bias; } - -private: - RefPtr m_device_image; - float m_level_of_detail_bias { 0.f }; -}; - -} diff --git a/Userland/Libraries/LibGL/Tex/Texture2D.cpp b/Userland/Libraries/LibGL/Tex/Texture2D.cpp deleted file mode 100644 index 3ed97dc6e9c..00000000000 --- a/Userland/Libraries/LibGL/Tex/Texture2D.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -namespace GL { - -void Texture2D::download_texture_data(GLuint lod, GPU::ImageDataLayout output_layout, GLvoid* pixels) -{ - VERIFY(!device_image().is_null()); - device_image()->read_texels(lod, { 0, 0, 0 }, pixels, output_layout); -} - -void Texture2D::upload_texture_data(GLuint lod, GLenum internal_format, GPU::ImageDataLayout input_layout, GLvoid const* pixels) -{ - m_internal_format = internal_format; - - // No pixel data was supplied; leave the texture memory uninitialized. - if (pixels == nullptr) - return; - - replace_sub_texture_data(lod, input_layout, { 0, 0, 0 }, pixels); - if (lod == 0 && m_generate_mipmaps) - device_image()->regenerate_mipmaps(); -} - -void Texture2D::replace_sub_texture_data(GLuint lod, GPU::ImageDataLayout input_layout, Vector3 const& output_offset, GLvoid const* pixels) -{ - // FIXME: We currently depend on the first glTexImage2D call to attach an image to mipmap level 0, which initializes the GPU image - // Ideally we would create separate GPU images for each level and merge them into a final image - // once used for rendering for the first time. - VERIFY(!device_image().is_null()); - - device_image()->write_texels(lod, output_offset, pixels, input_layout); - if (lod == 0 && m_generate_mipmaps) - device_image()->regenerate_mipmaps(); -} - -void Texture2D::set_generate_mipmaps(bool generate_mipmaps) -{ - if (m_generate_mipmaps == generate_mipmaps) - return; - m_generate_mipmaps = generate_mipmaps; - if (generate_mipmaps && !device_image().is_null()) - device_image()->regenerate_mipmaps(); -} - -} diff --git a/Userland/Libraries/LibGL/Tex/Texture2D.h b/Userland/Libraries/LibGL/Tex/Texture2D.h deleted file mode 100644 index 19f8e5fae97..00000000000 --- a/Userland/Libraries/LibGL/Tex/Texture2D.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Texture.h" - -#include -#include -#include -#include - -namespace GL { - -class Texture2D final : public Texture { -public: - virtual bool is_texture_2d() const override { return true; } - - void download_texture_data(GLuint lod, GPU::ImageDataLayout output_layout, GLvoid* pixels); - void upload_texture_data(GLuint lod, GLenum internal_format, GPU::ImageDataLayout input_layout, GLvoid const* pixels); - void replace_sub_texture_data(GLuint lod, GPU::ImageDataLayout input_layout, Vector3 const& output_offset, GLvoid const* pixels); - - void set_generate_mipmaps(bool generate_mipmaps); - GLenum internal_format() const { return m_internal_format; } - Sampler2D const& sampler() const { return m_sampler; } - Sampler2D& sampler() { return m_sampler; } - - int width_at_lod(unsigned level) const { return static_cast(device_image()->width_at_level(level)); } - int height_at_lod(unsigned level) const { return static_cast(device_image()->height_at_level(level)); } - int depth_at_lod(unsigned level) const { return static_cast(device_image()->depth_at_level(level)); } - -private: - bool m_generate_mipmaps { false }; - GLenum m_internal_format; - Sampler2D m_sampler; -}; - -} diff --git a/Userland/Libraries/LibGL/Tex/TextureUnit.h b/Userland/Libraries/LibGL/Tex/TextureUnit.h deleted file mode 100644 index 7607857f4a7..00000000000 --- a/Userland/Libraries/LibGL/Tex/TextureUnit.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace GL { - -class TextureUnit { -public: - TextureUnit() = default; - - RefPtr texture_2d_target_texture() const { return m_texture_2d_target_texture; } - void set_texture_2d_target_texture(RefPtr const& texture) { m_texture_2d_target_texture = texture; } - - void set_alpha_combinator(GLenum combinator) { m_alpha_combinator = combinator; } - GLenum alpha_combinator() const { return m_alpha_combinator; } - void set_alpha_operand(size_t index, GLenum operand) { m_alpha_operand[index] = operand; } - GLenum alpha_operand(size_t index) const { return m_alpha_operand[index]; } - void set_alpha_scale(float scale) { m_alpha_scale = scale; } - float alpha_scale() const { return m_alpha_scale; } - void set_alpha_source(size_t index, GLenum source) { m_alpha_source[index] = source; } - GLenum alpha_source(size_t index) const { return m_alpha_source[index]; } - void set_color(FloatVector4 color) { m_color = color; } - FloatVector4 color() const { return m_color; } - void set_env_mode(GLenum mode) { m_env_mode = mode; } - GLenum env_mode() const { return m_env_mode; } - void set_level_of_detail_bias(float bias) { m_level_of_detail_bias = bias; } - float level_of_detail_bias() const { return m_level_of_detail_bias; } - void set_rgb_combinator(GLenum combinator) { m_rgb_combinator = combinator; } - GLenum rgb_combinator() const { return m_rgb_combinator; } - void set_rgb_operand(size_t index, GLenum operand) { m_rgb_operand[index] = operand; } - GLenum rgb_operand(size_t index) const { return m_rgb_operand[index]; } - void set_rgb_scale(float scale) { m_rgb_scale = scale; } - float rgb_scale() const { return m_rgb_scale; } - void set_rgb_source(size_t index, GLenum source) { m_rgb_source[index] = source; } - GLenum rgb_source(size_t index) const { return m_rgb_source[index]; } - - bool texture_1d_enabled() const { return m_texture_1d_enabled; } - void set_texture_1d_enabled(bool texture_1d_enabled) { m_texture_1d_enabled = texture_1d_enabled; } - bool texture_2d_enabled() const { return m_texture_2d_enabled; } - void set_texture_2d_enabled(bool texture_2d_enabled) { m_texture_2d_enabled = texture_2d_enabled; } - bool texture_3d_enabled() const { return m_texture_3d_enabled; } - void set_texture_3d_enabled(bool texture_3d_enabled) { m_texture_3d_enabled = texture_3d_enabled; } - bool texture_cube_map_enabled() const { return m_texture_cube_map_enabled; } - void set_texture_cube_map_enabled(bool texture_cube_map_enabled) { m_texture_cube_map_enabled = texture_cube_map_enabled; } - - FloatMatrix4x4& texture_matrix() { return m_texture_matrix_stack.last(); } - Vector& texture_matrix_stack() { return m_texture_matrix_stack; } - -private: - GLenum m_alpha_combinator { GL_MODULATE }; - Array m_alpha_operand { GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA }; - float m_alpha_scale { 1.f }; - Array m_alpha_source { GL_TEXTURE, GL_PREVIOUS, GL_CONSTANT }; - FloatVector4 m_color { 0.f, 0.f, 0.f, 0.f }; - GLenum m_env_mode { GL_MODULATE }; - float m_level_of_detail_bias { 0.f }; - GLenum m_rgb_combinator { GL_MODULATE }; - Array m_rgb_operand { GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_ALPHA }; - float m_rgb_scale { 1.f }; - Array m_rgb_source { GL_TEXTURE, GL_PREVIOUS, GL_CONSTANT }; - - // Bound textures - RefPtr m_texture_2d_target_texture {}; - - // Texturing state per unit, in increasing priority: - bool m_texture_1d_enabled { false }; - bool m_texture_2d_enabled { false }; - bool m_texture_3d_enabled { false }; - bool m_texture_cube_map_enabled { false }; - - // Matrix stack for this unit - Vector m_texture_matrix_stack { FloatMatrix4x4::identity() }; -}; - -} diff --git a/Userland/Libraries/LibGL/Texture.cpp b/Userland/Libraries/LibGL/Texture.cpp deleted file mode 100644 index 4a20dd147c1..00000000000 --- a/Userland/Libraries/LibGL/Texture.cpp +++ /dev/null @@ -1,1015 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace GL { - -// Helper functions to handle type casting. -static u16 max_texture_size(GPU::DeviceInfo const& device_info) -{ - return static_cast(device_info.max_texture_size); -} - -static u8 log2_max_texture_size(GPU::DeviceInfo const& device_info) -{ - return static_cast(AK::log2(device_info.max_texture_size)); -} - -void GLContext::gl_active_texture(GLenum texture) -{ - RETURN_WITH_ERROR_IF(texture < GL_TEXTURE0 || texture >= GL_TEXTURE0 + m_device_info.num_texture_units, GL_INVALID_ENUM); - - m_active_texture_unit_index = texture - GL_TEXTURE0; - m_active_texture_unit = &m_texture_units.at(m_active_texture_unit_index); - - if (m_current_matrix_mode == GL_TEXTURE) { - m_current_matrix_stack = &m_active_texture_unit->texture_matrix_stack(); - m_current_matrix = &m_current_matrix_stack->last(); - } -} - -void GLContext::gl_bind_texture(GLenum target, GLuint texture) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(target != GL_TEXTURE_1D - && target != GL_TEXTURE_2D - && target != GL_TEXTURE_3D - && target != GL_TEXTURE_1D_ARRAY - && target != GL_TEXTURE_2D_ARRAY - && target != GL_TEXTURE_CUBE_MAP, - GL_INVALID_ENUM); - - // FIXME: We only support GL_TEXTURE_2D for now - if (target != GL_TEXTURE_2D) { - dbgln("gl_bind_texture(target = {:#x}): currently only GL_TEXTURE_2D is supported", target); - return; - } - - RefPtr texture_2d; - - if (texture == 0) { - // Texture name 0 refers to the default texture - texture_2d = get_default_texture(target); - } else { - // Find this texture name in our previously allocated textures - auto it = m_allocated_textures.find(texture); - if (it != m_allocated_textures.end()) { - auto texture_object = it->value; - if (!texture_object.is_null()) { - // Texture must have been created with the same target - RETURN_WITH_ERROR_IF(!texture_object->is_texture_2d(), GL_INVALID_OPERATION); - texture_2d = static_cast(texture_object.ptr()); - } - } - - // OpenGL 1.x supports binding texture names that were not previously generated by glGenTextures. - // If there is not an allocated texture, meaning it was not previously generated by glGenTextures, - // we can keep texture_object null to both allocate and bind the texture with the passed in texture name. - // FIXME: Later OpenGL versions such as 4.x enforce that texture names being bound were previously generated - // by glGenTextures. - if (!texture_2d) { - texture_2d = adopt_ref(*new Texture2D()); - m_allocated_textures.set(texture, texture_2d); - } - } - - m_active_texture_unit->set_texture_2d_target_texture(texture_2d); - m_sampler_config_is_dirty = true; -} - -void GLContext::gl_client_active_texture(GLenum target) -{ - RETURN_WITH_ERROR_IF(target < GL_TEXTURE0 || target >= GL_TEXTURE0 + m_device_info.num_texture_units, GL_INVALID_ENUM); - - m_client_active_texture = target - GL_TEXTURE0; -} - -void GLContext::gl_copy_tex_image_2d(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_copy_tex_image_2d, target, level, internalformat, x, y, width, height, border); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(internalformat == GL_NONE, GL_INVALID_ENUM); - auto pixel_type_or_error = get_validated_pixel_type(target, internalformat, GL_NONE, GL_NONE); - RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code()); - - RETURN_WITH_ERROR_IF(level < 0 || level > log2_max_texture_size(m_device_info), GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(width < 0 || height < 0 || width > (2 + max_texture_size(m_device_info)) || height > (2 + max_texture_size(m_device_info)), GL_INVALID_VALUE); - if (!m_device_info.supports_npot_textures) - RETURN_WITH_ERROR_IF(!is_power_of_two(width) || !is_power_of_two(height), GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(border != 0, GL_INVALID_VALUE); - - auto texture_2d = m_active_texture_unit->texture_2d_target_texture(); - VERIFY(!texture_2d.is_null()); - - auto internal_pixel_format = pixel_format_for_internal_format(internalformat); - if (level == 0) { - texture_2d->set_device_image(m_rasterizer->create_image(internal_pixel_format, width, height, 1, log2_max_texture_size(m_device_info))); - m_sampler_config_is_dirty = true; - } - - auto pixel_type = pixel_type_or_error.release_value(); - if (pixel_type.format == GPU::PixelFormat::DepthComponent) { - m_rasterizer->blit_from_depth_buffer( - *texture_2d->device_image(), - level, - { static_cast(width), static_cast(height) }, - { x, y }, - { 0, 0, 0 }); - } else if (pixel_type.format == GPU::PixelFormat::StencilIndex) { - dbgln("{}: GL_STENCIL_INDEX is not yet supported", __FUNCTION__); - } else { - m_rasterizer->blit_from_color_buffer( - *texture_2d->device_image(), - level, - { static_cast(width), static_cast(height) }, - { x, y }, - { 0, 0, 0 }); - } -} - -void GLContext::gl_copy_tex_sub_image_2d(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_copy_tex_sub_image_2d, target, level, xoffset, yoffset, x, y, width, height); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(level < 0 || level > log2_max_texture_size(m_device_info), GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(width < 0 || height < 0 || width > (2 + max_texture_size(m_device_info)) || height > (2 + max_texture_size(m_device_info)), GL_INVALID_VALUE); - - auto texture_2d = m_active_texture_unit->texture_2d_target_texture(); - VERIFY(!texture_2d.is_null()); - RETURN_WITH_ERROR_IF(texture_2d->device_image().is_null(), GL_INVALID_OPERATION); - - m_rasterizer->blit_from_color_buffer( - *texture_2d->device_image(), - level, - { static_cast(width), static_cast(height) }, - { x, y }, - { xoffset, yoffset, 0 }); - - // FIXME: use GPU::PixelFormat for Texture2D's internal format - if (texture_2d->internal_format() == GL_DEPTH_COMPONENT) { - m_rasterizer->blit_from_depth_buffer( - *texture_2d->device_image(), - level, - { static_cast(width), static_cast(height) }, - { x, y }, - { 0, 0, 0 }); - } else if (texture_2d->internal_format() == GL_STENCIL_INDEX) { - dbgln("{}: GL_STENCIL_INDEX is not yet supported", __FUNCTION__); - } else { - m_rasterizer->blit_from_color_buffer( - *texture_2d->device_image(), - level, - { static_cast(width), static_cast(height) }, - { x, y }, - { 0, 0, 0 }); - } -} - -void GLContext::gl_delete_textures(GLsizei n, GLuint const* textures) -{ - RETURN_WITH_ERROR_IF(n < 0, GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - for (auto i = 0; i < n; i++) { - GLuint name = textures[i]; - if (name == 0) - continue; - - auto texture_object = m_allocated_textures.find(name); - if (texture_object == m_allocated_textures.end() || texture_object->value.is_null()) - continue; - - m_texture_name_allocator.free(name); - - auto texture = texture_object->value; - - // Check all texture units - for (auto& texture_unit : m_texture_units) { - if (texture->is_texture_2d() && texture_unit.texture_2d_target_texture() == texture) { - // If a texture that is currently bound is deleted, the binding reverts to 0 (the default texture) - texture_unit.set_texture_2d_target_texture(get_default_texture(GL_TEXTURE_2D)); - } - } - - m_allocated_textures.remove(name); - } -} - -void GLContext::gl_gen_textures(GLsizei n, GLuint* textures) -{ - RETURN_WITH_ERROR_IF(n < 0, GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - m_texture_name_allocator.allocate(n, textures); - - // Initialize all texture names with a nullptr - for (auto i = 0; i < n; ++i) { - GLuint name = textures[i]; - m_allocated_textures.set(name, nullptr); - } -} - -void GLContext::gl_get_tex_image(GLenum target, GLint level, GLenum format, GLenum type, void* pixels) -{ - RETURN_WITH_ERROR_IF(level < 0 || level > log2_max_texture_size(m_device_info), GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM); - auto pixel_type_or_error = get_validated_pixel_type(target, GL_NONE, format, type); - RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code()); - - auto texture_2d = m_active_texture_unit->texture_2d_target_texture(); - VERIFY(!texture_2d.is_null()); - - u32 width = texture_2d->width_at_lod(level); - u32 height = texture_2d->height_at_lod(level); - - GPU::ImageDataLayout output_layout = { - .pixel_type = pixel_type_or_error.release_value(), - .packing = get_packing_specification(PackingType::Pack), - .dimensions = { - .width = width, - .height = height, - .depth = 1, - }, - .selection = { - .width = width, - .height = height, - .depth = 1, - }, - }; - - texture_2d->download_texture_data(level, output_layout, pixels); -} - -void GLContext::gl_get_tex_parameter_integerv(GLenum target, GLint level, GLenum pname, GLint* params) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - // FIXME: support targets other than GL_TEXTURE_2D - RETURN_WITH_ERROR_IF(target != GL_TEXTURE_2D, GL_INVALID_ENUM); - // FIXME: support other parameter names - RETURN_WITH_ERROR_IF(pname < GL_TEXTURE_WIDTH || pname > GL_TEXTURE_HEIGHT, GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(level < 0 || level > log2_max_texture_size(m_device_info), GL_INVALID_VALUE); - // FIXME: GL_INVALID_VALUE is generated if target is GL_TEXTURE_BUFFER and level is not zero - // FIXME: GL_INVALID_OPERATION is generated if GL_TEXTURE_COMPRESSED_IMAGE_SIZE is queried on texture images with an uncompressed internal format or on proxy targets - - VERIFY(!m_active_texture_unit->texture_2d_target_texture().is_null()); - auto const texture_2d = m_active_texture_unit->texture_2d_target_texture(); - - switch (pname) { - case GL_TEXTURE_HEIGHT: - *params = texture_2d->height_at_lod(level); - break; - case GL_TEXTURE_WIDTH: - *params = texture_2d->width_at_lod(level); - break; - } -} - -GLboolean GLContext::gl_is_texture(GLuint texture) -{ - RETURN_VALUE_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION, GL_FALSE); - - if (texture == 0) - return GL_FALSE; - - auto it = m_allocated_textures.find(texture); - if (it == m_allocated_textures.end()) - return GL_FALSE; - - return it->value.is_null() ? GL_FALSE : GL_TRUE; -} - -void GLContext::gl_multi_tex_coord(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_multi_tex_coord, target, s, t, r, q); - - RETURN_WITH_ERROR_IF(target < GL_TEXTURE0 || target >= GL_TEXTURE0 + m_device_info.num_texture_units, GL_INVALID_ENUM); - - m_current_vertex_tex_coord[target - GL_TEXTURE0] = { s, t, r, q }; -} - -void GLContext::gl_tex_coord(GLfloat s, GLfloat t, GLfloat r, GLfloat q) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_coord, s, t, r, q); - - m_current_vertex_tex_coord[0] = { s, t, r, q }; -} - -void GLContext::gl_tex_env(GLenum target, GLenum pname, FloatVector4 params) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_env, target, pname, params); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(target != GL_TEXTURE_ENV && target != GL_TEXTURE_FILTER_CONTROL, GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(target == GL_TEXTURE_FILTER_CONTROL && pname != GL_TEXTURE_LOD_BIAS, GL_INVALID_ENUM); - - auto const param = params[0]; - switch (target) { - case GL_TEXTURE_ENV: - switch (pname) { - case GL_ALPHA_SCALE: - RETURN_WITH_ERROR_IF(param != 1.f && param != 2.f && param != 4.f, GL_INVALID_VALUE); - m_active_texture_unit->set_alpha_scale(param); - break; - case GL_COMBINE_ALPHA: { - auto param_enum = static_cast(param); - switch (param_enum) { - case GL_ADD: - case GL_ADD_SIGNED: - case GL_INTERPOLATE: - case GL_MODULATE: - case GL_REPLACE: - case GL_SUBTRACT: - m_active_texture_unit->set_alpha_combinator(param_enum); - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - break; - } - case GL_COMBINE_RGB: { - auto param_enum = static_cast(param); - switch (param_enum) { - case GL_ADD: - case GL_ADD_SIGNED: - case GL_DOT3_RGB: - case GL_DOT3_RGBA: - case GL_INTERPOLATE: - case GL_MODULATE: - case GL_REPLACE: - case GL_SUBTRACT: - m_active_texture_unit->set_rgb_combinator(param_enum); - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - break; - } - case GL_OPERAND0_ALPHA: - case GL_OPERAND1_ALPHA: - case GL_OPERAND2_ALPHA: { - auto param_enum = static_cast(param); - switch (param_enum) { - case GL_ONE_MINUS_SRC_ALPHA: - case GL_SRC_ALPHA: - m_active_texture_unit->set_alpha_operand(pname - GL_OPERAND0_ALPHA, param_enum); - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - break; - } - case GL_OPERAND0_RGB: - case GL_OPERAND1_RGB: - case GL_OPERAND2_RGB: { - auto param_enum = static_cast(param); - switch (param_enum) { - case GL_ONE_MINUS_SRC_ALPHA: - case GL_ONE_MINUS_SRC_COLOR: - case GL_SRC_ALPHA: - case GL_SRC_COLOR: - m_active_texture_unit->set_rgb_operand(pname - GL_OPERAND0_RGB, param_enum); - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - break; - } - case GL_RGB_SCALE: - RETURN_WITH_ERROR_IF(param != 1.f && param != 2.f && param != 4.f, GL_INVALID_VALUE); - m_active_texture_unit->set_rgb_scale(param); - break; - case GL_SRC0_ALPHA: - case GL_SRC1_ALPHA: - case GL_SRC2_ALPHA: { - auto param_enum = static_cast(param); - switch (param_enum) { - case GL_CONSTANT: - case GL_PREVIOUS: - case GL_PRIMARY_COLOR: - case GL_TEXTURE: - case GL_TEXTURE0 ... GL_TEXTURE31: - m_active_texture_unit->set_alpha_source(pname - GL_SRC0_ALPHA, param_enum); - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - break; - } - case GL_SRC0_RGB: - case GL_SRC1_RGB: - case GL_SRC2_RGB: { - auto param_enum = static_cast(param); - switch (param_enum) { - case GL_CONSTANT: - case GL_PREVIOUS: - case GL_PRIMARY_COLOR: - case GL_TEXTURE: - case GL_TEXTURE0 ... GL_TEXTURE31: - m_active_texture_unit->set_rgb_source(pname - GL_SRC0_RGB, param_enum); - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - break; - } - case GL_TEXTURE_ENV_COLOR: - m_active_texture_unit->set_color(params); - break; - case GL_TEXTURE_ENV_MODE: { - auto param_enum = static_cast(param); - switch (param_enum) { - case GL_ADD: - case GL_BLEND: - case GL_COMBINE: - case GL_DECAL: - case GL_MODULATE: - case GL_REPLACE: - m_active_texture_unit->set_env_mode(param_enum); - break; - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - break; - } - default: - RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); - } - break; - case GL_TEXTURE_FILTER_CONTROL: - switch (pname) { - case GL_TEXTURE_LOD_BIAS: - m_active_texture_unit->set_level_of_detail_bias(param); - break; - default: - VERIFY_NOT_REACHED(); - } - break; - default: - VERIFY_NOT_REACHED(); - } - - m_sampler_config_is_dirty = true; -} - -void GLContext::gl_tex_envv(GLenum target, GLenum pname, void const* params, GLenum type) -{ - VERIFY(type == GL_FLOAT || type == GL_INT); - - auto parameters_to_vector = [&](T const* params) -> FloatVector4 { - auto parameters = (target == GL_TEXTURE_ENV && pname == GL_TEXTURE_ENV_COLOR) - ? Vector4 { params[0], params[1], params[2], params[3] } - : Vector4 { params[0], 0, 0, 0 }; - return parameters.template to_type(); - }; - - auto tex_env_parameters = (type == GL_FLOAT) - ? parameters_to_vector(reinterpret_cast(params)) - : parameters_to_vector(reinterpret_cast(params)); - - // Normalize integers to -1..1 - if (target == GL_TEXTURE_ENV && pname == GL_TEXTURE_ENV_COLOR && type == GL_INT) - tex_env_parameters = (tex_env_parameters + 2147483648.f) / 2147483647.5f - 1.f; - - gl_tex_env(target, pname, tex_env_parameters); -} - -void GLContext::gl_tex_gen(GLenum coord, GLenum pname, GLint param) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_gen, coord, pname, param); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(coord < GL_S || coord > GL_Q, GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(pname != GL_TEXTURE_GEN_MODE, GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(param != GL_EYE_LINEAR - && param != GL_OBJECT_LINEAR - && param != GL_SPHERE_MAP - && param != GL_NORMAL_MAP - && param != GL_REFLECTION_MAP, - GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF((coord == GL_R || coord == GL_Q) && param == GL_SPHERE_MAP, GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(coord == GL_Q && (param == GL_REFLECTION_MAP || param == GL_NORMAL_MAP), GL_INVALID_ENUM); - - GLenum const capability = GL_TEXTURE_GEN_S + (coord - GL_S); - texture_coordinate_generation(m_active_texture_unit_index, capability).generation_mode = param; - m_texture_units_dirty = true; -} - -void GLContext::gl_tex_gen_floatv(GLenum coord, GLenum pname, GLfloat const* params) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_gen_floatv, coord, pname, params); - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(coord < GL_S || coord > GL_Q, GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(pname != GL_TEXTURE_GEN_MODE - && pname != GL_OBJECT_PLANE - && pname != GL_EYE_PLANE, - GL_INVALID_ENUM); - - GLenum const capability = GL_TEXTURE_GEN_S + (coord - GL_S); - - switch (pname) { - case GL_TEXTURE_GEN_MODE: { - auto param = static_cast(params[0]); - RETURN_WITH_ERROR_IF(param != GL_EYE_LINEAR - && param != GL_OBJECT_LINEAR - && param != GL_SPHERE_MAP - && param != GL_NORMAL_MAP - && param != GL_REFLECTION_MAP, - GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF((coord == GL_R || coord == GL_Q) && param == GL_SPHERE_MAP, GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(coord == GL_Q && (param == GL_REFLECTION_MAP || param == GL_NORMAL_MAP), GL_INVALID_ENUM); - - texture_coordinate_generation(m_active_texture_unit_index, capability).generation_mode = param; - break; - } - case GL_OBJECT_PLANE: - texture_coordinate_generation(m_active_texture_unit_index, capability).object_plane_coefficients = { params[0], params[1], params[2], params[3] }; - break; - case GL_EYE_PLANE: { - auto const& inverse_model_view = model_view_matrix().inverse(); - auto input_coefficients = FloatVector4 { params[0], params[1], params[2], params[3] }; - - // Note: we are allowed to store transformed coefficients here, according to the documentation on - // `glGetTexGen`: - // - // "The returned values are those maintained in eye coordinates. They are not equal to the values - // specified using glTexGen, unless the modelview matrix was identity when glTexGen was called." - - texture_coordinate_generation(m_active_texture_unit_index, capability).eye_plane_coefficients = inverse_model_view * input_coefficients; - break; - } - default: - VERIFY_NOT_REACHED(); - } - - m_texture_units_dirty = true; -} - -void GLContext::gl_tex_image_2d(GLenum target, GLint level, GLint internal_format, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLvoid const* data) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(internal_format == GL_NONE || format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM); - auto pixel_type_or_error = get_validated_pixel_type(target, internal_format, format, type); - RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code()); - - RETURN_WITH_ERROR_IF(level < 0 || level > log2_max_texture_size(m_device_info), GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(width < 0 || height < 0 || width > (2 + max_texture_size(m_device_info)) || height > (2 + max_texture_size(m_device_info)), GL_INVALID_VALUE); - if (!m_device_info.supports_npot_textures) - RETURN_WITH_ERROR_IF(!is_power_of_two(width) || !is_power_of_two(height), GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(border != 0, GL_INVALID_VALUE); - - auto texture_2d = m_active_texture_unit->texture_2d_target_texture(); - VERIFY(!texture_2d.is_null()); - - if (level == 0) { - // FIXME: OpenGL has the concept of texture and mipmap completeness. A texture has to fulfill certain criteria to be considered complete. - // Trying to render while an incomplete texture is bound will result in an error. - // Here we simply create a complete device image when mipmap level 0 is attached to the texture object. This has the unfortunate side effect - // that constructing GL textures in any but the default mipmap order, going from level 0 upwards will cause mip levels to stay uninitialized. - // To be spec compliant we should create the device image once the texture has become complete and is used for rendering the first time. - // All images that were attached before the device image was created need to be stored somewhere to be used to initialize the device image once complete. - auto internal_pixel_format = pixel_format_for_internal_format(internal_format); - texture_2d->set_device_image(m_rasterizer->create_image(internal_pixel_format, width, height, 1, log2_max_texture_size(m_device_info))); - m_sampler_config_is_dirty = true; - } - - GPU::ImageDataLayout input_layout = { - .pixel_type = pixel_type_or_error.release_value(), - .packing = get_packing_specification(PackingType::Unpack), - .dimensions = { - .width = static_cast(width), - .height = static_cast(height), - .depth = 1, - }, - .selection = { - .width = static_cast(width), - .height = static_cast(height), - .depth = 1, - }, - }; - - texture_2d->upload_texture_data(level, internal_format, input_layout, data); -} - -void GLContext::gl_tex_parameter(GLenum target, GLenum pname, GLfloat param) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_parameter, target, pname, param); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // FIXME: We currently only support GL_TETXURE_2D targets. 1D, 3D and CUBE should also be supported (https://docs.gl/gl2/glTexParameter) - RETURN_WITH_ERROR_IF(target != GL_TEXTURE_2D, GL_INVALID_ENUM); - - // FIXME: implement the remaining parameters. (https://docs.gl/gl2/glTexParameter) - RETURN_WITH_ERROR_IF(pname != GL_GENERATE_MIPMAP - && pname != GL_TEXTURE_LOD_BIAS - && pname != GL_TEXTURE_MIN_FILTER - && pname != GL_TEXTURE_MAG_FILTER - && pname != GL_TEXTURE_WRAP_S - && pname != GL_TEXTURE_WRAP_T, - GL_INVALID_ENUM); - - // We assume GL_TEXTURE_2D (see above) - auto texture_2d = m_active_texture_unit->texture_2d_target_texture(); - VERIFY(!texture_2d.is_null()); - - switch (pname) { - case GL_GENERATE_MIPMAP: - RETURN_WITH_ERROR_IF(param != GL_TRUE && param != GL_FALSE, GL_INVALID_ENUM); - texture_2d->set_generate_mipmaps(param == GL_TRUE); - break; - case GL_TEXTURE_LOD_BIAS: - texture_2d->set_level_of_detail_bias(param); - break; - case GL_TEXTURE_MIN_FILTER: - RETURN_WITH_ERROR_IF(!(param == GL_NEAREST - || param == GL_LINEAR - || param == GL_NEAREST_MIPMAP_NEAREST - || param == GL_LINEAR_MIPMAP_NEAREST - || param == GL_NEAREST_MIPMAP_LINEAR - || param == GL_LINEAR_MIPMAP_LINEAR), - GL_INVALID_ENUM); - - texture_2d->sampler().set_min_filter(param); - break; - - case GL_TEXTURE_MAG_FILTER: - RETURN_WITH_ERROR_IF(!(param == GL_NEAREST - || param == GL_LINEAR), - GL_INVALID_ENUM); - - texture_2d->sampler().set_mag_filter(param); - break; - - case GL_TEXTURE_WRAP_S: - RETURN_WITH_ERROR_IF(!(param == GL_CLAMP - || param == GL_CLAMP_TO_BORDER - || param == GL_CLAMP_TO_EDGE - || param == GL_MIRRORED_REPEAT - || param == GL_REPEAT), - GL_INVALID_ENUM); - - texture_2d->sampler().set_wrap_s_mode(param); - break; - - case GL_TEXTURE_WRAP_T: - RETURN_WITH_ERROR_IF(!(param == GL_CLAMP - || param == GL_CLAMP_TO_BORDER - || param == GL_CLAMP_TO_EDGE - || param == GL_MIRRORED_REPEAT - || param == GL_REPEAT), - GL_INVALID_ENUM); - - texture_2d->sampler().set_wrap_t_mode(param); - break; - - default: - VERIFY_NOT_REACHED(); - } - - m_sampler_config_is_dirty = true; -} - -void GLContext::gl_tex_parameterfv(GLenum target, GLenum pname, GLfloat const* params) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_parameterfv, target, pname, params); - - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // FIXME: We currently only support GL_TETXURE_2D targets. 1D, 3D and CUBE should also be supported (https://docs.gl/gl2/glTexParameter) - RETURN_WITH_ERROR_IF(target != GL_TEXTURE_2D, GL_INVALID_ENUM); - - // FIXME: implement the remaining parameters. (https://docs.gl/gl2/glTexParameter) - RETURN_WITH_ERROR_IF(pname != GL_TEXTURE_BORDER_COLOR, GL_INVALID_ENUM); - - // We assume GL_TEXTURE_2D (see above) - auto texture_2d = m_active_texture_unit->texture_2d_target_texture(); - RETURN_WITH_ERROR_IF(texture_2d.is_null(), GL_INVALID_OPERATION); - - switch (pname) { - case GL_TEXTURE_BORDER_COLOR: - texture_2d->sampler().set_border_color(params[0], params[1], params[2], params[3]); - break; - default: - VERIFY_NOT_REACHED(); - } - - m_sampler_config_is_dirty = true; -} - -void GLContext::gl_tex_sub_image_2d(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid const* data) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // We only support symbolic constants for now - RETURN_WITH_ERROR_IF(level < 0 || level > log2_max_texture_size(m_device_info), GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(width < 0 || height < 0 || width > (2 + max_texture_size(m_device_info)) || height > (2 + max_texture_size(m_device_info)), GL_INVALID_VALUE); - - // A 2D texture array must have been defined by a previous glTexImage2D operation - auto texture_2d = m_active_texture_unit->texture_2d_target_texture(); - VERIFY(!texture_2d.is_null()); - RETURN_WITH_ERROR_IF(texture_2d->device_image().is_null(), GL_INVALID_OPERATION); - - RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM); - auto pixel_type_or_error = get_validated_pixel_type(target, texture_2d->internal_format(), format, type); - RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code()); - - RETURN_WITH_ERROR_IF(xoffset < 0 || yoffset < 0 || xoffset + width > texture_2d->width_at_lod(level) || yoffset + height > texture_2d->height_at_lod(level), GL_INVALID_VALUE); - - GPU::ImageDataLayout input_layout = { - .pixel_type = pixel_type_or_error.release_value(), - .packing = get_packing_specification(PackingType::Unpack), - .dimensions = { - .width = static_cast(width), - .height = static_cast(height), - .depth = 1, - }, - .selection = { - .width = static_cast(width), - .height = static_cast(height), - .depth = 1, - }, - }; - - texture_2d->replace_sub_texture_data(level, input_layout, { xoffset, yoffset, 0 }, data); -} - -void GLContext::sync_device_sampler_config() -{ - if (!m_sampler_config_is_dirty) - return; - - m_sampler_config_is_dirty = false; - - for (unsigned i = 0; i < m_texture_units.size(); ++i) { - auto const& texture_unit = m_texture_units[i]; - if (!texture_unit.texture_2d_enabled()) - continue; - - GPU::SamplerConfig config; - - auto texture_2d = texture_unit.texture_2d_target_texture(); - VERIFY(!texture_2d.is_null()); - config.bound_image = texture_2d->device_image(); - config.level_of_detail_bias = texture_2d->level_of_detail_bias() + texture_unit.level_of_detail_bias(); - - auto const& sampler = texture_2d->sampler(); - - switch (sampler.min_filter()) { - case GL_NEAREST: - config.texture_min_filter = GPU::TextureFilter::Nearest; - config.mipmap_filter = GPU::MipMapFilter::None; - break; - case GL_LINEAR: - config.texture_min_filter = GPU::TextureFilter::Linear; - config.mipmap_filter = GPU::MipMapFilter::None; - break; - case GL_NEAREST_MIPMAP_NEAREST: - config.texture_min_filter = GPU::TextureFilter::Nearest; - config.mipmap_filter = GPU::MipMapFilter::Nearest; - break; - case GL_LINEAR_MIPMAP_NEAREST: - config.texture_min_filter = GPU::TextureFilter::Linear; - config.mipmap_filter = GPU::MipMapFilter::Nearest; - break; - case GL_NEAREST_MIPMAP_LINEAR: - config.texture_min_filter = GPU::TextureFilter::Nearest; - config.mipmap_filter = GPU::MipMapFilter::Linear; - break; - case GL_LINEAR_MIPMAP_LINEAR: - config.texture_min_filter = GPU::TextureFilter::Linear; - config.mipmap_filter = GPU::MipMapFilter::Linear; - break; - default: - VERIFY_NOT_REACHED(); - } - - switch (sampler.mag_filter()) { - case GL_NEAREST: - config.texture_mag_filter = GPU::TextureFilter::Nearest; - break; - case GL_LINEAR: - config.texture_mag_filter = GPU::TextureFilter::Linear; - break; - default: - VERIFY_NOT_REACHED(); - } - - switch (sampler.wrap_s_mode()) { - case GL_CLAMP: - config.texture_wrap_u = GPU::TextureWrapMode::Clamp; - break; - case GL_CLAMP_TO_BORDER: - config.texture_wrap_u = GPU::TextureWrapMode::ClampToBorder; - break; - case GL_CLAMP_TO_EDGE: - config.texture_wrap_u = GPU::TextureWrapMode::ClampToEdge; - break; - case GL_REPEAT: - config.texture_wrap_u = GPU::TextureWrapMode::Repeat; - break; - case GL_MIRRORED_REPEAT: - config.texture_wrap_u = GPU::TextureWrapMode::MirroredRepeat; - break; - default: - VERIFY_NOT_REACHED(); - } - - switch (sampler.wrap_t_mode()) { - case GL_CLAMP: - config.texture_wrap_v = GPU::TextureWrapMode::Clamp; - break; - case GL_CLAMP_TO_BORDER: - config.texture_wrap_v = GPU::TextureWrapMode::ClampToBorder; - break; - case GL_CLAMP_TO_EDGE: - config.texture_wrap_v = GPU::TextureWrapMode::ClampToEdge; - break; - case GL_REPEAT: - config.texture_wrap_v = GPU::TextureWrapMode::Repeat; - break; - case GL_MIRRORED_REPEAT: - config.texture_wrap_v = GPU::TextureWrapMode::MirroredRepeat; - break; - default: - VERIFY_NOT_REACHED(); - } - - auto& fixed_function_env = config.fixed_function_texture_environment; - fixed_function_env.color = texture_unit.color(); - - auto get_env_mode = [](GLenum mode) { - switch (mode) { - case GL_ADD: - return GPU::TextureEnvMode::Add; - case GL_BLEND: - return GPU::TextureEnvMode::Blend; - case GL_COMBINE: - return GPU::TextureEnvMode::Combine; - case GL_DECAL: - return GPU::TextureEnvMode::Decal; - case GL_MODULATE: - return GPU::TextureEnvMode::Modulate; - case GL_REPLACE: - return GPU::TextureEnvMode::Replace; - default: - VERIFY_NOT_REACHED(); - } - }; - fixed_function_env.env_mode = get_env_mode(texture_unit.env_mode()); - - fixed_function_env.alpha_scale = texture_unit.alpha_scale(); - fixed_function_env.rgb_scale = texture_unit.rgb_scale(); - - auto get_combinator = [](GLenum combinator) { - switch (combinator) { - case GL_ADD: - return GPU::TextureCombinator::Add; - case GL_ADD_SIGNED: - return GPU::TextureCombinator::AddSigned; - case GL_DOT3_RGB: - return GPU::TextureCombinator::Dot3RGB; - case GL_DOT3_RGBA: - return GPU::TextureCombinator::Dot3RGBA; - case GL_INTERPOLATE: - return GPU::TextureCombinator::Interpolate; - case GL_MODULATE: - return GPU::TextureCombinator::Modulate; - case GL_REPLACE: - return GPU::TextureCombinator::Replace; - case GL_SUBTRACT: - return GPU::TextureCombinator::Subtract; - default: - VERIFY_NOT_REACHED(); - } - }; - fixed_function_env.alpha_combinator = get_combinator(texture_unit.alpha_combinator()); - fixed_function_env.rgb_combinator = get_combinator(texture_unit.rgb_combinator()); - - auto get_operand = [](GLenum operand) { - switch (operand) { - case GL_ONE_MINUS_SRC_ALPHA: - return GPU::TextureOperand::OneMinusSourceAlpha; - case GL_ONE_MINUS_SRC_COLOR: - return GPU::TextureOperand::OneMinusSourceColor; - case GL_SRC_ALPHA: - return GPU::TextureOperand::SourceAlpha; - case GL_SRC_COLOR: - return GPU::TextureOperand::SourceColor; - default: - VERIFY_NOT_REACHED(); - } - }; - auto get_source = [](GLenum source) { - switch (source) { - case GL_CONSTANT: - return GPU::TextureSource::Constant; - case GL_PREVIOUS: - return GPU::TextureSource::Previous; - case GL_PRIMARY_COLOR: - return GPU::TextureSource::PrimaryColor; - case GL_TEXTURE: - return GPU::TextureSource::Texture; - case GL_TEXTURE0 ... GL_TEXTURE31: - return GPU::TextureSource::TextureStage; - default: - VERIFY_NOT_REACHED(); - } - }; - for (size_t j = 0; j < 3; ++j) { - fixed_function_env.alpha_operand[j] = get_operand(texture_unit.alpha_operand(j)); - fixed_function_env.alpha_source[j] = get_source(texture_unit.alpha_source(j)); - if (fixed_function_env.alpha_source[j] == GPU::TextureSource::TextureStage) - fixed_function_env.alpha_source_texture_stage = texture_unit.alpha_source(j) - GL_TEXTURE0; - - fixed_function_env.rgb_operand[j] = get_operand(texture_unit.rgb_operand(j)); - fixed_function_env.rgb_source[j] = get_source(texture_unit.rgb_source(j)); - if (fixed_function_env.rgb_source[j] == GPU::TextureSource::TextureStage) - fixed_function_env.rgb_source_texture_stage = texture_unit.rgb_source(j) - GL_TEXTURE0; - } - - config.border_color = sampler.border_color(); - m_rasterizer->set_sampler_config(i, config); - } -} - -void GLContext::sync_device_texture_units() -{ - if (!m_texture_units_dirty) - return; - m_texture_units_dirty = false; - - for (GPU::TextureUnitIndex i = 0; i < m_device_info.num_texture_units; ++i) { - GPU::TextureUnitConfiguration texture_unit_configuration; - texture_unit_configuration.enabled = m_texture_units[i].texture_2d_enabled(); - texture_unit_configuration.transformation_matrix = m_texture_units[i].texture_matrix(); - - // Tex coord generation - u8 enabled_coordinates = GPU::TexCoordGenerationCoordinate::None; - for (GLenum capability = GL_TEXTURE_GEN_S; capability <= GL_TEXTURE_GEN_Q; ++capability) { - auto const context_coordinate_config = texture_coordinate_generation(i, capability); - if (!context_coordinate_config.enabled) - continue; - - GPU::TexCoordGeneration* texcoord_generation; - switch (capability) { - case GL_TEXTURE_GEN_S: - enabled_coordinates |= GPU::TexCoordGenerationCoordinate::S; - texcoord_generation = &texture_unit_configuration.tex_coord_generation[0]; - break; - case GL_TEXTURE_GEN_T: - enabled_coordinates |= GPU::TexCoordGenerationCoordinate::T; - texcoord_generation = &texture_unit_configuration.tex_coord_generation[1]; - break; - case GL_TEXTURE_GEN_R: - enabled_coordinates |= GPU::TexCoordGenerationCoordinate::R; - texcoord_generation = &texture_unit_configuration.tex_coord_generation[2]; - break; - case GL_TEXTURE_GEN_Q: - enabled_coordinates |= GPU::TexCoordGenerationCoordinate::Q; - texcoord_generation = &texture_unit_configuration.tex_coord_generation[3]; - break; - default: - VERIFY_NOT_REACHED(); - } - - switch (context_coordinate_config.generation_mode) { - case GL_OBJECT_LINEAR: - texcoord_generation->mode = GPU::TexCoordGenerationMode::ObjectLinear; - texcoord_generation->coefficients = context_coordinate_config.object_plane_coefficients; - break; - case GL_EYE_LINEAR: - texcoord_generation->mode = GPU::TexCoordGenerationMode::EyeLinear; - texcoord_generation->coefficients = context_coordinate_config.eye_plane_coefficients; - break; - case GL_SPHERE_MAP: - texcoord_generation->mode = GPU::TexCoordGenerationMode::SphereMap; - break; - case GL_REFLECTION_MAP: - texcoord_generation->mode = GPU::TexCoordGenerationMode::ReflectionMap; - break; - case GL_NORMAL_MAP: - texcoord_generation->mode = GPU::TexCoordGenerationMode::NormalMap; - break; - default: - VERIFY_NOT_REACHED(); - } - } - texture_unit_configuration.tex_coord_generation_enabled = enabled_coordinates; - - m_rasterizer->set_texture_unit_configuration(i, texture_unit_configuration); - } -} - -} diff --git a/Userland/Libraries/LibGL/Vertex.cpp b/Userland/Libraries/LibGL/Vertex.cpp deleted file mode 100644 index 4952450a534..00000000000 --- a/Userland/Libraries/LibGL/Vertex.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace GL { - -// General helper function to read arbitrary vertex attribute data into a float array -static void read_from_vertex_attribute_pointer(VertexAttribPointer const& attrib, int index, float* elements) -{ - auto const* byte_ptr = reinterpret_cast(attrib.pointer); - - auto read_values = [&]() { - auto const stride = (attrib.stride == 0) ? sizeof(T) * attrib.size : attrib.stride; - for (int i = 0; i < attrib.size; ++i) { - elements[i] = *(reinterpret_cast(byte_ptr + stride * index) + i); - if constexpr (IsIntegral) { - if (attrib.normalize) - elements[i] /= NumericLimits::max(); - } - } - }; - - switch (attrib.type) { - case GL_BYTE: - read_values.operator()(); - break; - case GL_UNSIGNED_BYTE: - read_values.operator()(); - break; - case GL_SHORT: - read_values.operator()(); - break; - case GL_UNSIGNED_SHORT: - read_values.operator()(); - break; - case GL_INT: - read_values.operator()(); - break; - case GL_UNSIGNED_INT: - read_values.operator()(); - break; - case GL_FLOAT: - read_values.operator()(); - break; - case GL_DOUBLE: - read_values.operator()(); - break; - } -} - -void GLContext::gl_array_element(GLint i) -{ - // NOTE: This always dereferences data; display list support is deferred to the - // individual vertex attribute calls such as `gl_color`, `gl_normal` etc. - RETURN_WITH_ERROR_IF(i < 0, GL_INVALID_VALUE); - - if (m_client_side_color_array_enabled) { - float color[4] { 0.f, 0.f, 0.f, 1.f }; - read_from_vertex_attribute_pointer(m_client_color_pointer, i, color); - gl_color(color[0], color[1], color[2], color[3]); - } - - for (size_t t = 0; t < m_client_tex_coord_pointer.size(); ++t) { - if (m_client_side_texture_coord_array_enabled[t]) { - float tex_coords[4] { 0.f, 0.f, 0.f, 1.f }; - read_from_vertex_attribute_pointer(m_client_tex_coord_pointer[t], i, tex_coords); - gl_multi_tex_coord(GL_TEXTURE0 + t, tex_coords[0], tex_coords[1], tex_coords[2], tex_coords[3]); - } - } - - if (m_client_side_normal_array_enabled) { - float normal[3]; - read_from_vertex_attribute_pointer(m_client_normal_pointer, i, normal); - gl_normal(normal[0], normal[1], normal[2]); - } - - if (m_client_side_vertex_array_enabled) { - float vertex[4] { 0.f, 0.f, 0.f, 1.f }; - read_from_vertex_attribute_pointer(m_client_vertex_pointer, i, vertex); - gl_vertex(vertex[0], vertex[1], vertex[2], vertex[3]); - } -} - -void GLContext::gl_color(GLfloat r, GLfloat g, GLfloat b, GLfloat a) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_color, r, g, b, a); - - m_current_vertex_color = { r, g, b, a }; -} - -void GLContext::gl_color_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(!(size == 3 || size == 4), GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(type != GL_BYTE - && type != GL_UNSIGNED_BYTE - && type != GL_SHORT - && type != GL_UNSIGNED_SHORT - && type != GL_INT - && type != GL_UNSIGNED_INT - && type != GL_FLOAT - && type != GL_DOUBLE, - GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE); - - void const* data_pointer = pointer; - if (m_array_buffer) { - size_t data_offset = reinterpret_cast(pointer); - data_pointer = m_array_buffer->offset_data(data_offset); - } - m_client_color_pointer = { .size = size, .type = type, .normalize = true, .stride = stride, .pointer = data_pointer }; -} - -void GLContext::gl_draw_arrays(GLenum mode, GLint first, GLsizei count) -{ - // NOTE: This always dereferences data; display list support is deferred to the - // individual vertex attribute calls such as `gl_color`, `gl_normal` etc. - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // FIXME: Some modes are still missing (GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES) - RETURN_WITH_ERROR_IF(!(mode == GL_TRIANGLE_STRIP - || mode == GL_TRIANGLE_FAN - || mode == GL_TRIANGLES - || mode == GL_QUADS - || mode == GL_QUAD_STRIP - || mode == GL_POLYGON), - GL_INVALID_ENUM); - - RETURN_WITH_ERROR_IF(count < 0, GL_INVALID_VALUE); - - auto last = first + count; - gl_begin(mode); - for (int i = first; i < last; i++) { - if (m_client_side_color_array_enabled) { - float color[4] { 0.f, 0.f, 0.f, 1.f }; - read_from_vertex_attribute_pointer(m_client_color_pointer, i, color); - gl_color(color[0], color[1], color[2], color[3]); - } - - for (size_t t = 0; t < m_client_tex_coord_pointer.size(); ++t) { - if (m_client_side_texture_coord_array_enabled[t]) { - float tex_coords[4] { 0.f, 0.f, 0.f, 1.f }; - read_from_vertex_attribute_pointer(m_client_tex_coord_pointer[t], i, tex_coords); - gl_multi_tex_coord(GL_TEXTURE0 + t, tex_coords[0], tex_coords[1], tex_coords[2], tex_coords[3]); - } - } - - if (m_client_side_normal_array_enabled) { - float normal[3]; - read_from_vertex_attribute_pointer(m_client_normal_pointer, i, normal); - gl_normal(normal[0], normal[1], normal[2]); - } - - if (m_client_side_vertex_array_enabled) { - float vertex[4] { 0.f, 0.f, 0.f, 1.f }; - read_from_vertex_attribute_pointer(m_client_vertex_pointer, i, vertex); - gl_vertex(vertex[0], vertex[1], vertex[2], vertex[3]); - } - } - gl_end(); -} - -void GLContext::gl_draw_elements(GLenum mode, GLsizei count, GLenum type, void const* indices) -{ - // NOTE: This always dereferences data; display list support is deferred to the - // individual vertex attribute calls such as `gl_color`, `gl_normal` etc. - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - - // FIXME: Some modes are still missing (GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES) - RETURN_WITH_ERROR_IF(!(mode == GL_TRIANGLE_STRIP - || mode == GL_TRIANGLE_FAN - || mode == GL_TRIANGLES - || mode == GL_QUADS - || mode == GL_QUAD_STRIP - || mode == GL_POLYGON), - GL_INVALID_ENUM); - - RETURN_WITH_ERROR_IF(!(type == GL_UNSIGNED_BYTE - || type == GL_UNSIGNED_SHORT - || type == GL_UNSIGNED_INT), - GL_INVALID_ENUM); - - RETURN_WITH_ERROR_IF(count < 0, GL_INVALID_VALUE); - - void const* index_data = indices; - if (m_element_array_buffer) { - size_t data_offset = reinterpret_cast(indices); - index_data = m_element_array_buffer->offset_data(data_offset); - } - - gl_begin(mode); - for (int index = 0; index < count; index++) { - int i = 0; - switch (type) { - case GL_UNSIGNED_BYTE: - i = reinterpret_cast(index_data)[index]; - break; - case GL_UNSIGNED_SHORT: - i = reinterpret_cast(index_data)[index]; - break; - case GL_UNSIGNED_INT: - i = reinterpret_cast(index_data)[index]; - break; - } - - if (m_client_side_color_array_enabled) { - float color[4] { 0.f, 0.f, 0.f, 1.f }; - read_from_vertex_attribute_pointer(m_client_color_pointer, i, color); - gl_color(color[0], color[1], color[2], color[3]); - } - - for (size_t t = 0; t < m_client_tex_coord_pointer.size(); ++t) { - if (m_client_side_texture_coord_array_enabled[t]) { - float tex_coords[4] { 0.f, 0.f, 0.f, 1.f }; - read_from_vertex_attribute_pointer(m_client_tex_coord_pointer[t], i, tex_coords); - gl_multi_tex_coord(GL_TEXTURE0 + t, tex_coords[0], tex_coords[1], tex_coords[2], tex_coords[3]); - } - } - - if (m_client_side_normal_array_enabled) { - float normal[3]; - read_from_vertex_attribute_pointer(m_client_normal_pointer, i, normal); - gl_normal(normal[0], normal[1], normal[2]); - } - - if (m_client_side_vertex_array_enabled) { - float vertex[4] { 0.f, 0.f, 0.f, 1.f }; - read_from_vertex_attribute_pointer(m_client_vertex_pointer, i, vertex); - gl_vertex(vertex[0], vertex[1], vertex[2], vertex[3]); - } - } - gl_end(); -} - -void GLContext::gl_normal(GLfloat nx, GLfloat ny, GLfloat nz) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_normal, nx, ny, nz); - - m_current_vertex_normal = { nx, ny, nz }; -} - -void GLContext::gl_normal_pointer(GLenum type, GLsizei stride, void const* pointer) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(type != GL_BYTE - && type != GL_SHORT - && type != GL_INT - && type != GL_FLOAT - && type != GL_DOUBLE, - GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE); - - void const* data_pointer = pointer; - if (m_array_buffer) { - size_t data_offset = reinterpret_cast(pointer); - data_pointer = m_array_buffer->offset_data(data_offset); - } - m_client_normal_pointer = { .size = 3, .type = type, .normalize = true, .stride = stride, .pointer = data_pointer }; -} - -void GLContext::gl_tex_coord_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(!(size == 1 || size == 2 || size == 3 || size == 4), GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(!(type == GL_SHORT || type == GL_INT || type == GL_FLOAT || type == GL_DOUBLE), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE); - - auto& tex_coord_pointer = m_client_tex_coord_pointer[m_client_active_texture]; - - void const* data_pointer = pointer; - if (m_array_buffer) { - size_t data_offset = reinterpret_cast(pointer); - data_pointer = m_array_buffer->offset_data(data_offset); - } - tex_coord_pointer = { .size = size, .type = type, .normalize = false, .stride = stride, .pointer = data_pointer }; -} - -void GLContext::gl_vertex(GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_vertex, x, y, z, w); - - GPU::Vertex vertex; - - vertex.position = { x, y, z, w }; - vertex.color = m_current_vertex_color; - for (size_t i = 0; i < m_device_info.num_texture_units; ++i) - vertex.tex_coords[i] = m_current_vertex_tex_coord[i]; - vertex.normal = m_current_vertex_normal; - - // Optimization: by pulling in the Vector size vs. capacity check, we can always perform an unchecked append - if (m_vertex_list.size() == m_vertex_list.capacity()) - m_vertex_list.grow_capacity(m_vertex_list.size() + 1); - m_vertex_list.unchecked_append(vertex); -} - -void GLContext::gl_vertex_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer) -{ - RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); - RETURN_WITH_ERROR_IF(!(size == 2 || size == 3 || size == 4), GL_INVALID_VALUE); - RETURN_WITH_ERROR_IF(!(type == GL_SHORT || type == GL_INT || type == GL_FLOAT || type == GL_DOUBLE), GL_INVALID_ENUM); - RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE); - - void const* data_pointer = pointer; - if (m_array_buffer) { - size_t data_offset = reinterpret_cast(pointer); - data_pointer = m_array_buffer->offset_data(data_offset); - } - m_client_vertex_pointer = { .size = size, .type = type, .normalize = false, .stride = stride, .pointer = data_pointer }; -} - -} diff --git a/Userland/Libraries/LibGLSL/AST.cpp b/Userland/Libraries/LibGLSL/AST.cpp deleted file mode 100644 index ba96ef71989..00000000000 --- a/Userland/Libraries/LibGLSL/AST.cpp +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * Copyright (c) 2023, Volodymyr V. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "AST.h" - -namespace GLSL { - -static ErrorOr print_indent(AK::Stream& output, int indent) -{ - for (int i = 0; i < indent * 2; ++i) - TRY(output.write_some(" "sv.bytes())); - return {}; -} - -ErrorOr ASTNode::dump(AK::Stream& output, size_t indent) const -{ - TRY(print_indent(output, indent)); - TRY(output.write_formatted("{}[{}:{}->{}:{}]\n", class_name(), start().line, start().column, end().line, end().column)); - return {}; -} - -ErrorOr TranslationUnit::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - for (auto const& child : m_declarations) { - TRY(child->dump(output, indent + 1)); - } - return {}; -} - -ErrorOr FunctionDeclaration::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - - TRY(m_return_type->dump(output, indent + 1)); - - if (!m_name.is_null()) { - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("{}\n", m_name->name())); - } - - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("(\n")); - - for (auto const& arg : m_parameters) { - TRY(arg->dump(output, indent + 1)); - } - - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted(")\n")); - - if (!m_definition.is_null()) { - TRY(m_definition->dump(output, indent + 1)); - } - - return {}; -} - -Vector> FunctionDeclaration::declarations() const -{ - Vector> declarations; - for (auto& arg : m_parameters) { - declarations.append(arg); - } - - if (m_definition) - declarations.extend(m_definition->declarations()); - - return declarations; -} - -ErrorOr Type::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - TRY(print_indent(output, indent + 1)); - - StringBuilder qualifiers_string; - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Const).has_value()) - qualifiers_string.append("const "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::In).has_value()) - qualifiers_string.append("in "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Out).has_value()) - qualifiers_string.append("out "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Inout).has_value()) - qualifiers_string.append("inout "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Centroid).has_value()) - qualifiers_string.append("centroid "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Patch).has_value()) - qualifiers_string.append("patch "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Sample).has_value()) - qualifiers_string.append("sample "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Uniform).has_value()) - qualifiers_string.append("uniform "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Buffer).has_value()) - qualifiers_string.append("buffer "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Shared).has_value()) - qualifiers_string.append("shared "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Coherent).has_value()) - qualifiers_string.append("coherent "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Volatile).has_value()) - qualifiers_string.append("volatile "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Restrict).has_value()) - qualifiers_string.append("restrict "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Readonly).has_value()) - qualifiers_string.append("readonly "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Writeonly).has_value()) - qualifiers_string.append("writeonly "sv); - if (m_storage_qualifiers.find_first_index(StorageTypeQualifier::Subroutine).has_value()) - qualifiers_string.append("subroutine "sv); - TRY(output.write_formatted("{}{}\n", qualifiers_string.string_view(), m_name->name())); - return {}; -} - -ErrorOr Parameter::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - if (!m_name.is_null()) { - TRY(print_indent(output, indent)); - TRY(output.write_formatted("{}\n", m_name->name())); - } - if (m_type) - TRY(m_type->dump(output, indent + 1)); - return {}; -} - -ErrorOr FunctionDefinition::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - TRY(print_indent(output, indent)); - TRY(output.write_formatted("{{\n")); - for (auto const& statement : m_statements) { - TRY(statement->dump(output, indent + 1)); - } - TRY(print_indent(output, indent)); - TRY(output.write_formatted("}}\n")); - return {}; -} - -Vector> FunctionDefinition::declarations() const -{ - Vector> declarations; - for (auto& statement : m_statements) { - declarations.extend(statement->declarations()); - } - return declarations; -} - -ErrorOr VariableDeclaration::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - if (m_type) - TRY(m_type->dump(output, indent + 1)); - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("{}\n", m_name->name())); - if (m_initial_value) - TRY(m_initial_value->dump(output, indent + 1)); - return {}; -} - -ErrorOr NumericLiteral::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("{}\n", m_value)); - return {}; -} - -ErrorOr BinaryExpression::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - - char const* op_string = nullptr; - switch (m_op) { - case BinaryOp::Addition: - op_string = "+"; - break; - case BinaryOp::Subtraction: - op_string = "-"; - break; - case BinaryOp::Multiplication: - op_string = "*"; - break; - case BinaryOp::Division: - op_string = "/"; - break; - case BinaryOp::Modulo: - op_string = "%"; - break; - case BinaryOp::GreaterThan: - op_string = ">"; - break; - case BinaryOp::GreaterThanEquals: - op_string = ">="; - break; - case BinaryOp::LessThan: - op_string = "<"; - break; - case BinaryOp::LessThanEquals: - op_string = "<="; - break; - case BinaryOp::BitwiseAnd: - op_string = "&"; - break; - case BinaryOp::BitwiseOr: - op_string = "|"; - break; - case BinaryOp::BitwiseXor: - op_string = "^"; - break; - case BinaryOp::LeftShift: - op_string = "<<"; - break; - case BinaryOp::RightShift: - op_string = ">>"; - break; - case BinaryOp::EqualsEquals: - op_string = "=="; - break; - case BinaryOp::NotEqual: - op_string = "!="; - break; - case BinaryOp::LogicalOr: - op_string = "||"; - break; - case BinaryOp::LogicalXor: - op_string = "^^"; - break; - case BinaryOp::LogicalAnd: - op_string = "&&"; - break; - case BinaryOp::Assignment: - op_string = "="; - break; - case BinaryOp::AdditionAssignment: - op_string = "+="; - break; - case BinaryOp::SubtractionAssignment: - op_string = "-="; - break; - case BinaryOp::MultiplicationAssignment: - op_string = "*="; - break; - case BinaryOp::DivisionAssignment: - op_string = "/="; - break; - case BinaryOp::ModuloAssignment: - op_string = "%="; - break; - case BinaryOp::AndAssignment: - op_string = "&="; - break; - case BinaryOp::OrAssignment: - op_string = "|="; - break; - case BinaryOp::XorAssignment: - op_string = "^="; - break; - case BinaryOp::LeftShiftAssignment: - op_string = "<<="; - break; - case BinaryOp::RightShiftAssignment: - op_string = ">>="; - break; - } - - TRY(m_lhs->dump(output, indent + 1)); - - TRY(print_indent(output, indent + 1)); - VERIFY(op_string); - TRY(output.write_formatted("{}\n", op_string)); - - TRY(m_rhs->dump(output, indent + 1)); - - return {}; -} - -ErrorOr FunctionCall::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - TRY(m_callee->dump(output, indent + 1)); - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("(\n")); - for (auto const& arg : m_arguments) { - TRY(arg->dump(output, indent + 1)); - } - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted(")\n")); - return {}; -} - -ErrorOr StringLiteral::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("{}\n", m_value)); - return {}; -} - -ErrorOr ReturnStatement::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - if (m_value) - TRY(m_value->dump(output, indent + 1)); - return {}; -} - -ErrorOr StructDeclaration::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("{}\n", m_name->name())); - for (auto& member : m_members) { - TRY(member->dump(output, indent + 1)); - } - return {}; -} -Vector> StructDeclaration::declarations() const -{ - Vector> declarations; - for (auto& member : m_members) - declarations.append(member); - return declarations; -} - -ErrorOr UnaryExpression::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - - char const* op_string = nullptr; - switch (m_op) { - case UnaryOp::BitwiseNot: - op_string = "~"; - break; - case UnaryOp::Not: - op_string = "!"; - break; - case UnaryOp::Plus: - op_string = "+"; - break; - case UnaryOp::Minus: - op_string = "-"; - break; - case UnaryOp::PlusPlus: - op_string = "++"; - break; - case UnaryOp::MinusMinus: - op_string = "--"; - break; - default: - op_string = ""; - } - - VERIFY(op_string); - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("{} {}\n", m_is_postfix ? "postfix"sv : "prefix"sv, op_string)); - TRY(m_lhs->dump(output, indent + 1)); - return {}; -} - -ErrorOr BooleanLiteral::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("{}\n", m_value ? "true" : "false")); - return {}; -} - -ErrorOr MemberExpression::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - TRY(m_object->dump(output, indent + 1)); - TRY(m_property->dump(output, indent + 1)); - return {}; -} - -ErrorOr ArrayElementExpression::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - TRY(m_array->dump(output, indent + 1)); - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("[\n")); - TRY(m_index->dump(output, indent + 1)); - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("]\n")); - return {}; -} - -ErrorOr BlockStatement::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - for (auto& statement : m_statements) { - TRY(statement->dump(output, indent + 1)); - } - return {}; -} - -ErrorOr ForStatement::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - if (m_init) { - TRY(print_indent(output, indent)); - TRY(output.write_formatted("Initializer:\n")); - TRY(m_init->dump(output, indent + 1)); - } - if (m_test) { - TRY(print_indent(output, indent)); - TRY(output.write_formatted("Test expression:\n")); - TRY(m_test->dump(output, indent + 1)); - } - if (m_update) { - TRY(print_indent(output, indent)); - TRY(output.write_formatted("Update expression:\n")); - TRY(m_update->dump(output, indent + 1)); - } - if (m_body) { - TRY(print_indent(output, indent)); - TRY(output.write_formatted("Body:\n")); - TRY(m_body->dump(output, indent + 1)); - } - return {}; -} - -Vector> Statement::declarations() const -{ - if (is_declaration()) { - Vector> vec; - auto const& decl = static_cast(*this); - vec.empend(const_cast(decl)); - return vec; - } - return {}; -} - -Vector> ForStatement::declarations() const -{ - Vector> declarations; - if (m_init) - declarations.extend(m_init->declarations()); - if (m_body) - declarations.extend(m_body->declarations()); - return declarations; -} - -Vector> BlockStatement::declarations() const -{ - Vector> declarations; - for (auto& statement : m_statements) { - declarations.extend(statement->declarations()); - } - return declarations; -} - -ErrorOr IfStatement::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - if (m_predicate) { - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("Predicate:\n")); - TRY(m_predicate->dump(output, indent + 1)); - } - if (m_then) { - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("Then:\n")); - TRY(m_then->dump(output, indent + 1)); - } - if (m_else) { - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("Else:\n")); - TRY(m_else->dump(output, indent + 1)); - } - return {}; -} - -Vector> IfStatement::declarations() const -{ - Vector> declarations; - if (m_predicate) - declarations.extend(m_predicate->declarations()); - if (m_then) - declarations.extend(m_then->declarations()); - if (m_else) - declarations.extend(m_else->declarations()); - return declarations; -} - -ErrorOr Name::dump(AK::Stream& output, size_t indent) const -{ - TRY(ASTNode::dump(output, indent)); - TRY(print_indent(output, indent + 1)); - TRY(output.write_formatted("{}\n", name())); - return {}; -} - -ErrorOr SizedName::dump(AK::Stream& output, size_t indent) const -{ - TRY(Name::dump(output, indent)); - TRY(print_indent(output, indent + 1)); - - StringBuilder dimension_info; - for (auto const& dim : m_dimensions) { - dimension_info.append('['); - dimension_info.append(dim); - dimension_info.append(']'); - } - - if (dimension_info.is_empty()) { - dimension_info.append("[]"sv); - } - TRY(output.write_formatted("{}\n", dimension_info.string_view())); - return {}; -} - -} diff --git a/Userland/Libraries/LibGLSL/AST.h b/Userland/Libraries/LibGLSL/AST.h deleted file mode 100644 index ce63f440097..00000000000 --- a/Userland/Libraries/LibGLSL/AST.h +++ /dev/null @@ -1,715 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * Copyright (c) 2023, Volodymyr V. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace GLSL { - -class ASTNode; -class TranslationUnit; -class Declaration; -class FunctionDefinition; -class Type; -class Parameter; -class Statement; -class Name; - -class ASTNode : public RefCounted { -public: - virtual ~ASTNode() = default; - virtual StringView class_name() const = 0; - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const; - - template - bool fast_is() const = delete; - - ASTNode const* parent() const { return m_parent; } - Position start() const - { - VERIFY(m_start.has_value()); - return m_start.value(); - } - Position end() const - { - VERIFY(m_end.has_value()); - return m_end.value(); - } - FlyString const& filename() const - { - return m_filename; - } - void set_end(Position const& end) { m_end = end; } - void set_parent(ASTNode const& parent) { m_parent = &parent; } - - virtual Vector> declarations() const { return {}; } - - virtual bool is_variable_or_parameter_declaration() const { return false; } - virtual bool is_function_call() const { return false; } - virtual bool is_type() const { return false; } - virtual bool is_declaration() const { return false; } - virtual bool is_name() const { return false; } - virtual bool is_member_expression() const { return true; } - virtual bool is_dummy_node() const { return false; } - -protected: - ASTNode(ASTNode const* parent, Optional start, Optional end, String const& filename) - : m_parent(parent) - , m_start(start) - , m_end(end) - , m_filename(filename) - { - } - -private: - ASTNode const* m_parent { nullptr }; - Optional m_start; - Optional m_end; - FlyString m_filename; -}; - -class TranslationUnit : public ASTNode { - -public: - virtual ~TranslationUnit() override = default; - virtual StringView class_name() const override { return "TranslationUnit"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - virtual Vector> declarations() const override { return m_declarations; } - - TranslationUnit(ASTNode const* parent, Optional start, Optional end, String const& filename) - : ASTNode(parent, start, end, filename) - { - } - - void set_declarations(Vector>&& declarations) { m_declarations = move(declarations); } - -private: - Vector> m_declarations; -}; - -class Statement : public ASTNode { -public: - virtual ~Statement() override = default; - virtual StringView class_name() const override { return "Statement"sv; } - - virtual Vector> declarations() const override; - -protected: - Statement(ASTNode const* parent, Optional start, Optional end, String const& filename) - : ASTNode(parent, start, end, filename) - { - } -}; - -class Declaration : public Statement { - -public: - virtual bool is_declaration() const override { return true; } - virtual bool is_variable_declaration() const { return false; } - virtual bool is_parameter() const { return false; } - virtual bool is_struct() const { return false; } - virtual bool is_function() const { return false; } - Name const* name() const { return m_name; } - void set_name(RefPtr name) { m_name = move(name); } - -protected: - Declaration(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Statement(parent, start, end, filename) - { - } - - RefPtr m_name; -}; - -class InvalidDeclaration : public Declaration { - -public: - virtual ~InvalidDeclaration() override = default; - virtual StringView class_name() const override { return "InvalidDeclaration"sv; } - InvalidDeclaration(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Declaration(parent, start, end, filename) - { - } -}; - -class FunctionDeclaration : public Declaration { -public: - virtual ~FunctionDeclaration() override = default; - virtual StringView class_name() const override { return "FunctionDeclaration"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - virtual bool is_function() const override { return true; } - RefPtr definition() { return m_definition; } - - FunctionDeclaration(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Declaration(parent, start, end, filename) - { - } - - virtual Vector> declarations() const override; - Type const* return_type() const { return m_return_type.ptr(); } - void set_return_type(RefPtr const& return_type) { m_return_type = return_type; } - Vector> const& parameters() const { return m_parameters; } - void set_parameters(Vector> const& parameters) { m_parameters = parameters; } - FunctionDefinition const* definition() const { return m_definition.ptr(); } - void set_definition(RefPtr&& definition) { m_definition = move(definition); } - -private: - RefPtr m_return_type; - Vector> m_parameters; - RefPtr m_definition; -}; - -class VariableOrParameterDeclaration : public Declaration { -public: - virtual ~VariableOrParameterDeclaration() override = default; - virtual bool is_variable_or_parameter_declaration() const override { return true; } - - void set_type(RefPtr&& type) { m_type = move(type); } - Type const* type() const { return m_type.ptr(); } - -protected: - VariableOrParameterDeclaration(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Declaration(parent, start, end, filename) - { - } - - RefPtr m_type; -}; - -class Parameter : public VariableOrParameterDeclaration { -public: - virtual ~Parameter() override = default; - virtual StringView class_name() const override { return "Parameter"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - virtual bool is_parameter() const override { return true; } - - Parameter(ASTNode const* parent, Optional start, Optional end, String const& filename, RefPtr name) - : VariableOrParameterDeclaration(parent, start, end, filename) - { - m_name = name; - } -}; - -enum class StorageTypeQualifier { - Const, - In, - Out, - Inout, - Centroid, - Patch, - Sample, - Uniform, - Buffer, - Shared, - Coherent, - Volatile, - Restrict, - Readonly, - Writeonly, - Subroutine, -}; - -class Type : public ASTNode { -public: - virtual ~Type() override = default; - virtual StringView class_name() const override { return "Type"sv; } - virtual bool is_type() const override { return true; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - - Type(ASTNode const* parent, Optional start, Optional end, String const& filename) - : ASTNode(parent, start, end, filename) - { - } - - Name const* name() const { return m_name.ptr(); } - void set_name(RefPtr&& name) { m_name = move(name); } - - Vector const& storage_qualifiers() const { return m_storage_qualifiers; } - void set_storage_qualifiers(Vector&& storage_qualifiers) { m_storage_qualifiers = move(storage_qualifiers); } - -private: - RefPtr m_name; - Vector m_storage_qualifiers; -}; - -class FunctionDefinition : public ASTNode { -public: - virtual ~FunctionDefinition() override = default; - virtual StringView class_name() const override { return "FunctionDefinition"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - - FunctionDefinition(ASTNode const* parent, Optional start, Optional end, String const& filename) - : ASTNode(parent, start, end, filename) - { - } - - virtual Vector> declarations() const override; - Vector> const& statements() { return m_statements; } - void add_statement(NonnullRefPtr&& statement) { m_statements.append(move(statement)); } - -private: - Vector> m_statements; -}; - -class InvalidStatement : public Statement { -public: - virtual ~InvalidStatement() override = default; - virtual StringView class_name() const override { return "InvalidStatement"sv; } - InvalidStatement(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Statement(parent, start, end, filename) - { - } -}; - -class Expression : public Statement { -public: - virtual ~Expression() override = default; - virtual StringView class_name() const override { return "Expression"sv; } - -protected: - Expression(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Statement(parent, start, end, filename) - { - } -}; - -class InvalidExpression : public Expression { -public: - virtual ~InvalidExpression() override = default; - virtual StringView class_name() const override { return "InvalidExpression"sv; } - InvalidExpression(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Expression(parent, start, end, filename) - { - } -}; - -class VariableDeclaration : public VariableOrParameterDeclaration { -public: - virtual ~VariableDeclaration() override = default; - virtual StringView class_name() const override { return "VariableDeclaration"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - - VariableDeclaration(ASTNode const* parent, Optional start, Optional end, String const& filename) - : VariableOrParameterDeclaration(parent, start, end, filename) - { - } - - virtual bool is_variable_declaration() const override { return true; } - - Expression const* initial_value() const { return m_initial_value; } - void set_initial_value(RefPtr&& initial_value) { m_initial_value = move(initial_value); } - -private: - RefPtr m_initial_value; -}; - -class Name : public Expression { -public: - virtual ~Name() override = default; - virtual StringView class_name() const override { return "Name"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - virtual bool is_name() const override { return true; } - virtual bool is_sized() const { return false; } - - Name(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Expression(parent, start, end, filename) - { - } - - StringView name() const { return m_name; } - void set_name(StringView name) { m_name = name; } - -private: - StringView m_name; -}; - -class SizedName : public Name { -public: - virtual ~SizedName() override = default; - virtual StringView class_name() const override { return "SizedName"sv; } - virtual bool is_sized() const override { return true; } - ErrorOr dump(AK::Stream&, size_t indent) const override; - - SizedName(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Name(parent, start, end, filename) - { - } - - void append_dimension(StringView dim) { m_dimensions.append(dim); } - -private: - Vector m_dimensions; -}; - -class NumericLiteral : public Expression { -public: - virtual ~NumericLiteral() override = default; - virtual StringView class_name() const override { return "NumericLiteral"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - - NumericLiteral(ASTNode const* parent, Optional start, Optional end, String const& filename, StringView value) - : Expression(parent, start, end, filename) - , m_value(value) - { - } - -private: - StringView m_value; -}; - -class BooleanLiteral : public Expression { -public: - virtual ~BooleanLiteral() override = default; - virtual StringView class_name() const override { return "BooleanLiteral"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - - BooleanLiteral(ASTNode const* parent, Optional start, Optional end, String const& filename, bool value) - : Expression(parent, start, end, filename) - , m_value(value) - { - } - -private: - bool m_value; -}; - -enum class BinaryOp { - Addition, - Subtraction, - Multiplication, - Division, - Modulo, - GreaterThan, - GreaterThanEquals, - LessThan, - LessThanEquals, - BitwiseAnd, - BitwiseOr, - BitwiseXor, - LeftShift, - RightShift, - EqualsEquals, - NotEqual, - LogicalOr, - LogicalXor, - LogicalAnd, - Assignment, - AdditionAssignment, - SubtractionAssignment, - MultiplicationAssignment, - DivisionAssignment, - ModuloAssignment, - AndAssignment, - OrAssignment, - XorAssignment, - LeftShiftAssignment, - RightShiftAssignment, -}; - -class BinaryExpression : public Expression { -public: - BinaryExpression(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~BinaryExpression() override = default; - virtual StringView class_name() const override { return "BinaryExpression"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - - BinaryOp op() const { return m_op; } - void set_op(BinaryOp op) { m_op = op; } - Expression const* lhs() const { return m_lhs.ptr(); } - void set_lhs(RefPtr&& e) { m_lhs = move(e); } - Expression const* rhs() const { return m_rhs.ptr(); } - void set_rhs(RefPtr&& e) { m_rhs = move(e); } - -private: - BinaryOp m_op; - RefPtr m_lhs; - RefPtr m_rhs; -}; - -class FunctionCall : public Expression { -public: - FunctionCall(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~FunctionCall() override = default; - virtual StringView class_name() const override { return "FunctionCall"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - virtual bool is_function_call() const override { return true; } - - Expression const* callee() const { return m_callee; } - void set_callee(RefPtr&& callee) { m_callee = move(callee); } - - void set_arguments(Vector>&& args) { m_arguments = move(args); } - Vector> const& arguments() const { return m_arguments; } - -private: - RefPtr m_callee; - Vector> m_arguments; -}; - -class StringLiteral final : public Expression { -public: - StringLiteral(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Expression(parent, start, end, filename) - { - } - - ~StringLiteral() override = default; - virtual StringView class_name() const override { return "StringLiteral"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - - String const& value() const { return m_value; } - void set_value(String value) { m_value = move(value); } - -private: - String m_value; -}; - -class ReturnStatement : public Statement { -public: - virtual ~ReturnStatement() override = default; - virtual StringView class_name() const override { return "ReturnStatement"sv; } - - ReturnStatement(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Statement(parent, start, end, filename) - { - } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - - Expression const* value() const { return m_value.ptr(); } - void set_value(RefPtr&& value) { m_value = move(value); } - -private: - RefPtr m_value; -}; - -class DiscardStatement : public Statement { -public: - virtual ~DiscardStatement() override = default; - virtual StringView class_name() const override { return "DiscardStatement"sv; } - - DiscardStatement(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Statement(parent, start, end, filename) - { - } -}; - -class StructDeclaration : public Declaration { -public: - virtual ~StructDeclaration() override = default; - virtual StringView class_name() const override { return "StructDeclaration"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - virtual bool is_struct() const override { return true; } - virtual Vector> declarations() const override; - - StructDeclaration(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Declaration(parent, start, end, filename) - { - } - - Vector> const& members() const { return m_members; } - void set_members(Vector>&& members) { m_members = move(members); } - -private: - Vector> m_members; -}; - -enum class UnaryOp { - BitwiseNot, - Not, - Plus, - Minus, - PlusPlus, - MinusMinus, -}; - -class UnaryExpression : public Expression { -public: - UnaryExpression(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~UnaryExpression() override = default; - virtual StringView class_name() const override { return "UnaryExpression"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - - UnaryOp op() const { return m_op; } - void set_op(UnaryOp op) { m_op = op; } - Expression const* lhs() const { return m_lhs.ptr(); } - void set_lhs(RefPtr&& e) { m_lhs = move(e); } - bool is_postfix() const { return m_is_postfix; } - void set_is_postfix(bool is_postfix) { m_is_postfix = is_postfix; } - -private: - UnaryOp m_op; - RefPtr m_lhs; - bool m_is_postfix = false; -}; - -class MemberExpression : public Expression { -public: - MemberExpression(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~MemberExpression() override = default; - virtual StringView class_name() const override { return "MemberExpression"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - virtual bool is_member_expression() const override { return true; } - - Expression const* object() const { return m_object.ptr(); } - void set_object(RefPtr&& object) { m_object = move(object); } - Expression const* property() const { return m_property.ptr(); } - void set_property(RefPtr&& property) { m_property = move(property); } - -private: - RefPtr m_object; - RefPtr m_property; -}; - -class ArrayElementExpression : public Expression { -public: - ArrayElementExpression(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Expression(parent, start, end, filename) - { - } - - virtual ~ArrayElementExpression() override = default; - virtual StringView class_name() const override { return "ArrayElementExpression"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - - Expression const* array() const { return m_array.ptr(); } - void set_array(RefPtr&& array) { m_array = move(array); } - Expression const* index() const { return m_index.ptr(); } - void set_index(RefPtr&& index) { m_index = move(index); } - -private: - RefPtr m_array; - RefPtr m_index; -}; - -class ForStatement : public Statement { -public: - ForStatement(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Statement(parent, start, end, filename) - { - } - - virtual ~ForStatement() override = default; - virtual StringView class_name() const override { return "ForStatement"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - - virtual Vector> declarations() const override; - - void set_init(RefPtr&& init) { m_init = move(init); } - void set_test(RefPtr&& test) { m_test = move(test); } - void set_update(RefPtr&& update) { m_update = move(update); } - void set_body(RefPtr&& body) { m_body = move(body); } - Statement const* body() const { return m_body.ptr(); } - -private: - RefPtr m_init; - RefPtr m_test; - RefPtr m_update; - RefPtr m_body; -}; - -class BlockStatement final : public Statement { -public: - BlockStatement(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Statement(parent, start, end, filename) - { - } - - virtual ~BlockStatement() override = default; - virtual StringView class_name() const override { return "BlockStatement"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - - virtual Vector> declarations() const override; - - void add_statement(NonnullRefPtr&& statement) { m_statements.append(move(statement)); } - -private: - Vector> m_statements; -}; - -class IfStatement : public Statement { -public: - IfStatement(ASTNode const* parent, Optional start, Optional end, String const& filename) - : Statement(parent, start, end, filename) - { - } - - virtual ~IfStatement() override = default; - virtual StringView class_name() const override { return "IfStatement"sv; } - virtual ErrorOr dump(AK::Stream&, size_t indent = 0) const override; - virtual Vector> declarations() const override; - - void set_predicate(RefPtr&& predicate) { m_predicate = move(predicate); } - void set_then_statement(RefPtr&& then) { m_then = move(then); } - void set_else_statement(RefPtr&& _else) { m_else = move(_else); } - - Statement const* then_statement() const { return m_then.ptr(); } - Statement const* else_statement() const { return m_else.ptr(); } - -private: - RefPtr m_predicate; - RefPtr m_then; - RefPtr m_else; -}; - -class DummyAstNode : public ASTNode { -public: - DummyAstNode(ASTNode const* parent, Optional start, Optional end, String const& filename) - : ASTNode(parent, start, end, filename) - { - } - virtual bool is_dummy_node() const override { return true; } - virtual StringView class_name() const override { return "DummyAstNode"sv; } - virtual ErrorOr dump(AK::Stream&, size_t = 0) const override { return {}; } -}; - -template<> -inline bool ASTNode::fast_is() const { return is_member_expression(); } -template<> -inline bool ASTNode::fast_is() const { return is_variable_or_parameter_declaration(); } -template<> -inline bool ASTNode::fast_is() const { return is_function_call(); } -template<> -inline bool ASTNode::fast_is() const { return is_type(); } -template<> -inline bool ASTNode::fast_is() const { return is_declaration(); } -template<> -inline bool ASTNode::fast_is() const { return is_name(); } -template<> -inline bool ASTNode::fast_is() const { return is_dummy_node(); } - -template<> -inline bool ASTNode::fast_is() const { return is_declaration() && verify_cast(*this).is_variable_declaration(); } -template<> -inline bool ASTNode::fast_is() const { return is_declaration() && verify_cast(*this).is_function(); } - -template<> -inline bool ASTNode::fast_is() const { return is_name() && verify_cast(*this).is_sized(); } -} diff --git a/Userland/Libraries/LibGLSL/CMakeLists.txt b/Userland/Libraries/LibGLSL/CMakeLists.txt deleted file mode 100644 index ec4a4daa739..00000000000 --- a/Userland/Libraries/LibGLSL/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -set(SOURCES - AST.cpp - Compiler.cpp - Lexer.cpp - Linker.cpp - Parser.cpp - Preprocessor.cpp - Token.cpp -) - -serenity_lib(LibGLSL glsl) -target_link_libraries(LibGLSL PRIVATE LibGPU) - -install(DIRECTORY Tests/ DESTINATION home/anon/Tests/glsl-tests) diff --git a/Userland/Libraries/LibGLSL/Compiler.cpp b/Userland/Libraries/LibGLSL/Compiler.cpp deleted file mode 100644 index def3d7fe619..00000000000 --- a/Userland/Libraries/LibGLSL/Compiler.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace GLSL { - -ErrorOr> Compiler::compile(Vector const&) -{ - // FIXME: implement this function - m_messages = {}; - return try_make(); -} - -} diff --git a/Userland/Libraries/LibGLSL/Compiler.h b/Userland/Libraries/LibGLSL/Compiler.h deleted file mode 100644 index b4d4c4be367..00000000000 --- a/Userland/Libraries/LibGLSL/Compiler.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace GLSL { - -class Compiler final { -public: - ErrorOr> compile(Vector const& sources); - - String messages() const { return m_messages; } - -private: - String m_messages; -}; - -} diff --git a/Userland/Libraries/LibGLSL/Lexer.cpp b/Userland/Libraries/LibGLSL/Lexer.cpp deleted file mode 100644 index a75523476e8..00000000000 --- a/Userland/Libraries/LibGLSL/Lexer.cpp +++ /dev/null @@ -1,819 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * Copyright (c) 2023, Volodymyr V. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Lexer.h" -#include -#include -#include -#include -#include - -namespace GLSL { - -Lexer::Lexer(StringView input, size_t start_line) - : m_input(input) - , m_previous_position { start_line, 0 } - , m_position { start_line, 0 } -{ -} - -char Lexer::peek(size_t offset) const -{ - if ((m_index + offset) >= m_input.length()) - return 0; - return m_input[m_index + offset]; -} - -char Lexer::consume() -{ - VERIFY(m_index < m_input.length()); - char ch = m_input[m_index++]; - m_previous_position = m_position; - if (ch == '\n') { - m_position.line++; - m_position.column = 0; - } else { - m_position.column++; - } - return ch; -} - -constexpr bool is_valid_first_character_of_identifier(char ch) -{ - return is_ascii_alpha(ch) || ch == '_' || ch == '$'; -} - -constexpr bool is_valid_nonfirst_character_of_identifier(char ch) -{ - return is_valid_first_character_of_identifier(ch) || is_ascii_digit(ch); -} - -// NOTE: some of these keywords are not used at the moment, however they are reserved for future use and should not be used as identifiers -constexpr Array s_known_keywords = { - "asm"sv, - "attribute"sv, - "break"sv, - "case"sv, - "cast"sv, - "centroid"sv, - "class"sv, - "common" - "partition"sv, - "active"sv, - "const"sv, - "continue"sv, - "default"sv, - "discard"sv, - "do"sv, - "else"sv, - "enum"sv, - "extern"sv, - "external"sv, - "false"sv, - "filter"sv, - "fixed"sv, - "flat"sv, - "for"sv, - "goto"sv, - "half"sv, - "highp"sv, - "if"sv, - "in"sv, - "inline"sv, - "inout"sv, - "input"sv, - "interface"sv, - "invariant"sv, - "layout"sv, - "lowp"sv, - "mediump"sv, - "namespace"sv, - "noinline"sv, - "noperspective"sv, - "out"sv, - "output"sv, - "packed"sv, - "patch"sv, - "precision"sv, - "public"sv, - "return"sv, - "row_major"sv, - "sample"sv, - "sizeof"sv, - "smooth"sv, - "static"sv, - "struct"sv, - "subroutine"sv, - "superp"sv, - "switch"sv, - "template"sv, - "this"sv, - "true"sv, - "typedef"sv, - "uniform"sv, - "union"sv, - "using"sv, - "varying"sv, - "volatile"sv, - "while"sv, -}; - -constexpr Array s_known_types = { - "bool"sv, - "bvec2"sv, - "bvec3"sv, - "bvec4"sv, - "dmat2"sv, - "dmat2x2"sv, - "dmat2x3"sv, - "dmat2x4"sv, - "dmat3"sv, - "dmat3x2"sv, - "dmat3x3"sv, - "dmat3x4"sv, - "dmat4"sv, - "dmat4x2"sv, - "dmat4x3"sv, - "dmat4x4"sv, - "double"sv, - "dvec2"sv, - "dvec3"sv, - "dvec4"sv, - "float"sv, - "fvec2"sv, - "fvec3"sv, - "fvec4"sv, - "hvec2"sv, - "hvec3"sv, - "hvec4"sv, - "iimage1D"sv, - "iimage1DArray"sv, - "iimage2D"sv, - "iimage2DArray"sv, - "iimage3D"sv, - "iimageBuffer"sv, - "iimageCube"sv, - "image1D"sv, - "image1DArray"sv, - "image1DArrayShadow"sv, - "image1DShadow"sv, - "image2D"sv, - "image2DArray"sv, - "image2DArrayShadow"sv, - "image2DShadow"sv, - "image3D"sv, - "imageBuffer"sv, - "imageCube"sv, - "int"sv, - "isampler1D"sv, - "isampler1DArray"sv, - "isampler2D"sv, - "isampler2DArray"sv, - "isampler2DMS"sv, - "isampler2DMSArray"sv, - "isampler2DRect"sv, - "isampler3D"sv, - "isamplerBuffer"sv, - "isamplerCube"sv, - "isamplerCubeArray"sv, - "ivec2"sv, - "ivec3"sv, - "ivec4"sv, - "long"sv, - "mat2"sv, - "mat2x2"sv, - "mat2x3"sv, - "mat2x4"sv, - "mat3"sv, - "mat3x2"sv, - "mat3x3"sv, - "mat3x4"sv, - "mat4"sv, - "mat4x2"sv, - "mat4x3"sv, - "mat4x4"sv, - "sampler1D"sv, - "sampler1DArray"sv, - "sampler1DArrayShadow"sv, - "sampler1DShadow"sv, - "sampler2D"sv, - "sampler2DArray"sv, - "sampler2DArrayShadow"sv, - "sampler2DMS"sv, - "sampler2DMSArray"sv, - "sampler2DRect"sv, - "sampler2DRectShadow"sv, - "sampler2DShadow"sv, - "sampler3D"sv, - "sampler3DRect"sv, - "samplerBuffer"sv, - "samplerCube"sv, - "samplerCubeArray"sv, - "samplerCubeArrayShadow"sv, - "samplerCubeShadow"sv, - "short"sv, - "uimage1D"sv, - "uimage1DArray"sv, - "uimage2D"sv, - "uimage2DArray"sv, - "uimage3D"sv, - "uimageBuffer"sv, - "uimageCube"sv, - "uint"sv, - "unsigned"sv, - "usampler1D"sv, - "usampler1DArray"sv, - "usampler2D"sv, - "usampler2DArray"sv, - "usampler2DMS"sv, - "usampler2DMSArray"sv, - "usampler2DRect"sv, - "usampler3D"sv, - "usamplerBuffer"sv, - "usamplerCube"sv, - "usamplerCubeArray"sv, - "uvec2"sv, - "uvec3"sv, - "uvec4"sv, - "vec2"sv, - "vec3"sv, - "vec4"sv, - "void"sv, -}; - -static bool is_keyword(StringView string) -{ - return AK::find(s_known_keywords.begin(), s_known_keywords.end(), string) != s_known_keywords.end(); -} - -static bool is_known_type(StringView string) -{ - return AK::find(s_known_types.begin(), s_known_types.end(), string) != s_known_types.end(); -} - -void Lexer::lex_impl(Function callback) -{ - size_t token_start_index = 0; - Position token_start_position; - - auto emit_single_char_token = [&](auto type) { - callback(Token(type, m_position, m_position, m_input.substring_view(m_index, 1))); - consume(); - }; - - auto begin_token = [&] { - token_start_index = m_index; - token_start_position = m_position; - }; - auto commit_token = [&](auto type) { - if (m_options.ignore_whitespace && type == Token::Type::Whitespace) - return; - callback(Token(type, token_start_position, m_previous_position, m_input.substring_view(token_start_index, m_index - token_start_index))); - }; - - auto emit_token_equals = [&](auto type, auto equals_type) { - if (peek(1) == '=') { - begin_token(); - consume(); - consume(); - commit_token(equals_type); - return; - } - emit_single_char_token(type); - }; - - auto match_escape_sequence = [&]() -> size_t { - switch (peek(1)) { - case '\'': - case '"': - case '?': - case '\\': - case 'a': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': - case 'v': - return 2; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': { - size_t octal_digits = 1; - for (size_t i = 0; i < 2; ++i) { - char next = peek(2 + i); - if (next < '0' || next > '7') - break; - ++octal_digits; - } - return 1 + octal_digits; - } - case 'x': { - size_t hex_digits = 0; - while (is_ascii_hex_digit(peek(2 + hex_digits))) - ++hex_digits; - return 2 + hex_digits; - } - case 'u': - case 'U': { - bool is_unicode = true; - size_t number_of_digits = peek(1) == 'u' ? 4 : 8; - for (size_t i = 0; i < number_of_digits; ++i) { - if (!is_ascii_hex_digit(peek(2 + i))) { - is_unicode = false; - break; - } - } - return is_unicode ? 2 + number_of_digits : 0; - } - default: - return 0; - } - }; - - auto match_string_prefix = [&](char quote) -> size_t { - if (peek() == quote) - return 1; - if (peek() == 'L' && peek(1) == quote) - return 2; - if (peek() == 'u') { - if (peek(1) == quote) - return 2; - if (peek(1) == '8' && peek(2) == quote) - return 3; - } - if (peek() == 'U' && peek(1) == quote) - return 2; - return 0; - }; - - while (m_index < m_input.length()) { - auto ch = peek(); - if (is_ascii_space(ch)) { - begin_token(); - while (is_ascii_space(peek())) - consume(); - commit_token(Token::Type::Whitespace); - continue; - } - if (ch == '(') { - emit_single_char_token(Token::Type::LeftParen); - continue; - } - if (ch == ')') { - emit_single_char_token(Token::Type::RightParen); - continue; - } - if (ch == '{') { - emit_single_char_token(Token::Type::LeftCurly); - continue; - } - if (ch == '}') { - emit_single_char_token(Token::Type::RightCurly); - continue; - } - if (ch == '[') { - emit_single_char_token(Token::Type::LeftBracket); - continue; - } - if (ch == ']') { - emit_single_char_token(Token::Type::RightBracket); - continue; - } - if (ch == '<') { - begin_token(); - consume(); - if (peek() == '<') { - consume(); - if (peek() == '=') { - consume(); - commit_token(Token::Type::LessLessEquals); - continue; - } - commit_token(Token::Type::LessLess); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::LessEquals); - continue; - } - commit_token(Token::Type::Less); - continue; - } - if (ch == '>') { - begin_token(); - consume(); - if (peek() == '>') { - consume(); - if (peek() == '=') { - consume(); - commit_token(Token::Type::GreaterGreaterEquals); - continue; - } - commit_token(Token::Type::GreaterGreater); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::GreaterEquals); - continue; - } - commit_token(Token::Type::Greater); - continue; - } - if (ch == ',') { - emit_single_char_token(Token::Type::Comma); - continue; - } - if (ch == '+') { - begin_token(); - consume(); - if (peek() == '+') { - consume(); - commit_token(Token::Type::PlusPlus); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::PlusEquals); - continue; - } - commit_token(Token::Type::Plus); - continue; - } - if (ch == '-') { - begin_token(); - consume(); - if (peek() == '-') { - consume(); - commit_token(Token::Type::MinusMinus); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::MinusEquals); - continue; - } - commit_token(Token::Type::Minus); - continue; - } - if (ch == '*') { - emit_token_equals(Token::Type::Asterisk, Token::Type::AsteriskEquals); - continue; - } - if (ch == '%') { - emit_token_equals(Token::Type::Percent, Token::Type::PercentEquals); - continue; - } - if (ch == '^') { - begin_token(); - consume(); - if (peek() == '^') { - consume(); - commit_token(Token::Type::CaretCaret); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::CaretEquals); - continue; - } - commit_token(Token::Type::Caret); - continue; - } - if (ch == '!') { - emit_token_equals(Token::Type::ExclamationMark, Token::Type::ExclamationMarkEquals); - continue; - } - if (ch == '=') { - emit_token_equals(Token::Type::Equals, Token::Type::EqualsEquals); - continue; - } - if (ch == '&') { - begin_token(); - consume(); - if (peek() == '&') { - consume(); - commit_token(Token::Type::AndAnd); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::AndEquals); - continue; - } - commit_token(Token::Type::And); - continue; - } - if (ch == '|') { - begin_token(); - consume(); - if (peek() == '|') { - consume(); - commit_token(Token::Type::PipePipe); - continue; - } - if (peek() == '=') { - consume(); - commit_token(Token::Type::PipeEquals); - continue; - } - commit_token(Token::Type::Pipe); - continue; - } - if (ch == '~') { - emit_single_char_token(Token::Type::Tilde); - continue; - } - if (ch == '?') { - emit_single_char_token(Token::Type::QuestionMark); - continue; - } - if (ch == ':') { - emit_single_char_token(Token::Type::Colon); - continue; - } - if (ch == ';') { - emit_single_char_token(Token::Type::Semicolon); - continue; - } - if (ch == '.') { - emit_single_char_token(Token::Type::Dot); - continue; - } - if (ch == '#') { - begin_token(); - consume(); - while (AK::is_ascii_space(peek())) - consume(); - - size_t directive_start = m_index; - if (is_valid_first_character_of_identifier(peek())) - while (peek() && is_valid_nonfirst_character_of_identifier(peek())) - consume(); - - auto directive = StringView(m_input.characters_without_null_termination() + directive_start, m_index - directive_start); - if (directive == "include"sv) { - commit_token(Token::Type::IncludeStatement); - - if (is_ascii_space(peek())) { - begin_token(); - do { - consume(); - } while (is_ascii_space(peek())); - commit_token(Token::Type::Whitespace); - } - - begin_token(); - if (peek() == '<' || peek() == '"') { - char closing = consume() == '<' ? '>' : '"'; - while (peek() && peek() != closing && peek() != '\n') - consume(); - - if (peek() && consume() == '\n') { - commit_token(Token::Type::IncludePath); - continue; - } - - commit_token(Token::Type::IncludePath); - begin_token(); - } - } else { - while (peek()) { - if (peek() == '\\' && peek(1) == '\n') { - consume(); - consume(); - } else if (peek() == '\n') { - break; - } else { - consume(); - } - } - - commit_token(Token::Type::PreprocessorStatement); - } - - continue; - } - if (ch == '/' && peek(1) == '/') { - while (peek() && peek() != '\n') - consume(); - continue; - } - if (ch == '/' && peek(1) == '*') { - consume(); - consume(); - bool comment_block_ends = false; - while (peek()) { - if (peek() == '*' && peek(1) == '/') { - comment_block_ends = true; - break; - } - - consume(); - } - - if (comment_block_ends) { - consume(); - consume(); - } - continue; - } - if (ch == '/') { - emit_token_equals(Token::Type::Slash, Token::Type::SlashEquals); - continue; - } - if (size_t prefix = match_string_prefix('"'); prefix > 0) { - begin_token(); - for (size_t i = 0; i < prefix; ++i) - consume(); - while (peek()) { - if (peek() == '\\') { - if (size_t escape = match_escape_sequence(); escape > 0) { - commit_token(Token::Type::DoubleQuotedString); - begin_token(); - for (size_t i = 0; i < escape; ++i) - consume(); - commit_token(Token::Type::EscapeSequence); - begin_token(); - continue; - } - } - - // If string is not terminated - stop before EOF - if (!peek(1)) - break; - - if (consume() == '"') - break; - } - commit_token(Token::Type::DoubleQuotedString); - continue; - } - if (size_t prefix = match_string_prefix('R'); prefix > 0 && peek(prefix) == '"') { - begin_token(); - for (size_t i = 0; i < prefix + 1; ++i) - consume(); - size_t prefix_start = m_index; - while (peek() && peek() != '(') - consume(); - StringView prefix_string = m_input.substring_view(prefix_start, m_index - prefix_start); - while (peek()) { - if (consume() == '"') { - VERIFY(m_index >= prefix_string.length() + 2); - VERIFY(m_input[m_index - 1] == '"'); - if (m_input[m_index - 1 - prefix_string.length() - 1] == ')') { - StringView suffix_string = m_input.substring_view(m_index - 1 - prefix_string.length(), prefix_string.length()); - if (prefix_string == suffix_string) - break; - } - } - } - commit_token(Token::Type::RawString); - continue; - } - if (size_t prefix = match_string_prefix('\''); prefix > 0) { - begin_token(); - for (size_t i = 0; i < prefix; ++i) - consume(); - while (peek()) { - if (peek() == '\\') { - if (size_t escape = match_escape_sequence(); escape > 0) { - commit_token(Token::Type::SingleQuotedString); - begin_token(); - for (size_t i = 0; i < escape; ++i) - consume(); - commit_token(Token::Type::EscapeSequence); - begin_token(); - continue; - } - } - - if (consume() == '\'') - break; - } - commit_token(Token::Type::SingleQuotedString); - continue; - } - if (is_ascii_digit(ch) || (ch == '.' && is_ascii_digit(peek(1)))) { - begin_token(); - consume(); - - auto type = ch == '.' ? Token::Type::Float : Token::Type::Integer; - bool is_hex = false; - bool is_binary = false; - - auto match_exponent = [&]() -> size_t { - char ch = peek(); - if (ch != 'e' && ch != 'E' && ch != 'p' && ch != 'P') - return 0; - - type = Token::Type::Float; - size_t length = 1; - ch = peek(length); - if (ch == '+' || ch == '-') { - ++length; - } - for (ch = peek(length); is_ascii_digit(ch); ch = peek(length)) { - ++length; - } - return length; - }; - - auto match_type_literal = [&]() -> size_t { - size_t length = 0; - for (;;) { - char ch = peek(length); - if ((ch == 'u' || ch == 'U') && type == Token::Type::Integer) { - ++length; - } else if ((ch == 'f' || ch == 'F') && !is_binary) { - type = Token::Type::Float; - ++length; - } else if (ch == 'l' || ch == 'L') { - ++length; - } else - return length; - } - }; - - if (peek() == 'b' || peek() == 'B') { - consume(); - is_binary = true; - for (char ch = peek(); ch == '0' || ch == '1' || (ch == '\'' && peek(1) != '\''); ch = peek()) { - consume(); - } - } else { - if (peek() == 'x' || peek() == 'X') { - consume(); - is_hex = true; - } - - for (char ch = peek(); (is_hex ? is_ascii_hex_digit(ch) : is_ascii_digit(ch)) || (ch == '\'' && peek(1) != '\'') || ch == '.'; ch = peek()) { - if (ch == '.') { - if (type == Token::Type::Integer) { - type = Token::Type::Float; - } else - break; - }; - consume(); - } - } - - if (!is_binary) { - size_t length = match_exponent(); - for (size_t i = 0; i < length; ++i) - consume(); - } - - size_t length = match_type_literal(); - for (size_t i = 0; i < length; ++i) - consume(); - - commit_token(type); - continue; - } - if (is_valid_first_character_of_identifier(ch)) { - begin_token(); - while (peek() && is_valid_nonfirst_character_of_identifier(peek())) - consume(); - auto token_view = StringView(m_input.characters_without_null_termination() + token_start_index, m_index - token_start_index); - if (is_keyword(token_view)) - commit_token(Token::Type::Keyword); - else if (is_known_type(token_view)) - commit_token(Token::Type::KnownType); - else - commit_token(Token::Type::Identifier); - continue; - } - - if (ch == '\\' && peek(1) == '\n') { - consume(); - consume(); - continue; - } - - dbgln("Unimplemented token character: {}", ch); - emit_single_char_token(Token::Type::Unknown); - } -} - -Vector Lexer::lex() -{ - Vector tokens; - lex_impl([&](auto token) { - tokens.append(move(token)); - }); - return tokens; -} - -} diff --git a/Userland/Libraries/LibGLSL/Lexer.h b/Userland/Libraries/LibGLSL/Lexer.h deleted file mode 100644 index 9d9451ce562..00000000000 --- a/Userland/Libraries/LibGLSL/Lexer.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace GLSL { - -class Lexer { -public: - explicit Lexer(StringView, size_t start_line = 0); - - Vector lex(); - template - void lex_iterable(Callback); - - void set_ignore_whitespace(bool value) { m_options.ignore_whitespace = value; } - -private: - char peek(size_t offset = 0) const; - char consume(); - void lex_impl(Function); - - StringView m_input; - size_t m_index { 0 }; - Position m_previous_position { 0, 0 }; - Position m_position { 0, 0 }; - - struct Options { - bool ignore_whitespace { false }; - } m_options; -}; - -template -void Lexer::lex_iterable(Callback callback) -{ - return lex_impl(move(callback)); -} - -} diff --git a/Userland/Libraries/LibGLSL/LinkedShader.h b/Userland/Libraries/LibGLSL/LinkedShader.h deleted file mode 100644 index 65d485be73f..00000000000 --- a/Userland/Libraries/LibGLSL/LinkedShader.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace GLSL { - -// FIXME: Implement this class - -class LinkedShader final { -public: - LinkedShader(const GPU::IR::Shader& intermediate_shader_representation) - : m_intermediate_shader_representation { intermediate_shader_representation } - { - } - - GPU::IR::Shader const& intermediate_shader_representation() const { return m_intermediate_shader_representation; } - -private: - GPU::IR::Shader m_intermediate_shader_representation; -}; - -} diff --git a/Userland/Libraries/LibGLSL/Linker.cpp b/Userland/Libraries/LibGLSL/Linker.cpp deleted file mode 100644 index 3503b880521..00000000000 --- a/Userland/Libraries/LibGLSL/Linker.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace GLSL { - -ErrorOr> Linker::link(Vector const&) -{ - // FIXME: implement this function - m_messages = {}; - - GPU::IR::Shader shader; - - auto input_name = "input0"_string; - auto output_name = "output0"_string; - TRY(shader.inputs.try_append({ move(input_name), GPU::IR::StorageType::Vector4 })); - TRY(shader.outputs.try_append({ move(output_name), GPU::IR::StorageType::Vector4 })); - GPU::IR::Instruction instruction { - GPU::IR::Opcode::Move, - { { GPU::IR::StorageLocation::Input, 0 } }, - { GPU::IR::StorageLocation::Output, 0 } - }; - TRY(shader.instructions.try_append(instruction)); - - return try_make(shader); -} - -} diff --git a/Userland/Libraries/LibGLSL/Linker.h b/Userland/Libraries/LibGLSL/Linker.h deleted file mode 100644 index 90ac686969c..00000000000 --- a/Userland/Libraries/LibGLSL/Linker.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace GLSL { - -class Linker final { -public: - ErrorOr> link(Vector const&); - - String messages() const { return m_messages; } - -private: - String m_messages; -}; - -} diff --git a/Userland/Libraries/LibGLSL/ObjectFile.h b/Userland/Libraries/LibGLSL/ObjectFile.h deleted file mode 100644 index da29541ac83..00000000000 --- a/Userland/Libraries/LibGLSL/ObjectFile.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -namespace GLSL { - -// FIXME: Implement this class - -class ObjectFile final { -}; - -} diff --git a/Userland/Libraries/LibGLSL/Parser.cpp b/Userland/Libraries/LibGLSL/Parser.cpp deleted file mode 100644 index aa3275883a1..00000000000 --- a/Userland/Libraries/LibGLSL/Parser.cpp +++ /dev/null @@ -1,1142 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * Copyright (c) 2023, Volodymyr V. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Parser.h" -#include "AST.h" -#include - -namespace GLSL { - -Parser::Parser(Vector tokens, String const& filename) - : m_filename(move(filename)) - , m_tokens(move(tokens)) -{ -} - -ErrorOr> Parser::parse() -{ - if (m_tokens.is_empty()) - return create_root_ast_node({}, {}); - auto unit = create_root_ast_node(m_tokens.first().start(), m_tokens.last().end()); - unit->set_declarations(TRY(parse_declarations_in_translation_unit(*unit))); - return unit; -} - -bool Parser::eof() const -{ - return m_state.token_index >= m_tokens.size(); -} - -void Parser::print_tokens() const -{ - for (auto& token : m_tokens) { - outln("{}", token.to_string()); - } -} - -ErrorOr> Parser::match_declaration_in_translation_unit() -{ - if (TRY(match_variable_declaration())) - return DeclarationType::Variable; - if (TRY(match_function_declaration())) - return DeclarationType::Function; - if (TRY(match_struct_declaration())) - return DeclarationType::Struct; - return Optional(); -} - -ErrorOr Parser::match_struct_declaration() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (!match_keyword("struct"sv)) - return false; - TRY(consume(Token::Type::Keyword)); - - if (!match(Token::Type::Identifier)) - return false; - TRY(consume(Token::Type::Identifier)); - - return match(Token::Type::LeftCurly); -} - -ErrorOr Parser::match_function_declaration() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (!TRY(match_type())) - return false; - - VERIFY(m_root_node); - (void)parse_type(get_dummy_node()); - - if (!TRY(match_name())) - return false; - - (void)parse_name(get_dummy_node()); - - if (!peek(Token::Type::LeftParen).has_value()) - return false; - TRY(consume()); - - while (TRY(consume()).type() != Token::Type::RightParen && !eof()) - ; - - if (peek(Token::Type::Semicolon).has_value() || peek(Token::Type::LeftCurly).has_value()) - return true; - - return false; -} - -ErrorOr Parser::match_variable_declaration() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (!TRY(match_type())) { - return false; - } - - VERIFY(m_root_node); - (void)parse_type(get_dummy_node()); - - // Identifier - if (!TRY(match_name())) - return false; - - (void)TRY(parse_name(get_dummy_node())); - - while (!eof() && (peek().type() == Token::Type::LeftBracket)) { - TRY(consume(Token::Type::LeftBracket)); - - if (match(Token::Type::Integer)) { - TRY(consume(Token::Type::Integer)); - } - if (!match(Token::Type::RightBracket)) { - TRY(error("No closing right bracket"sv)); - return false; - } - TRY(consume(Token::Type::RightBracket)); - } - - if (match(Token::Type::Equals)) { - TRY(consume(Token::Type::Equals)); - if (!TRY(match_expression())) { - TRY(error("initial value of variable is not an expression"sv)); - return false; - } - return true; - } - - return match(Token::Type::Semicolon); -} - -ErrorOr Parser::match_block_statement() -{ - return peek().type() == Token::Type::LeftCurly; -} - -ErrorOr Parser::match_expression() -{ - return TRY(match_name()) - || match_unary_op() - || match(Token::Type::LeftParen) - || TRY(match_boolean_literal()) - || TRY(match_numeric_literal()) - || TRY(match_string_literal()); -} - -ErrorOr Parser::match_name() -{ - auto type = peek().type(); - return type == Token::Type::Identifier || type == Token::Type::KnownType; -} - -ErrorOr Parser::match_string_literal() -{ - return match(Token::Type::DoubleQuotedString) || match(Token::Type::SingleQuotedString); -} - -ErrorOr Parser::match_numeric_literal() -{ - return match(Token::Type::Float) || match(Token::Type::Integer); -} - -ErrorOr Parser::match_boolean_literal() -{ - auto token = peek(); - if (token.type() != Token::Type::Keyword) - return false; - auto text = token.text(); - return text == "true" || text == "false"; -} - -ErrorOr Parser::match_type() -{ - save_state(); - ScopeGuard state_guard = [this] { load_state(); }; - - if (match_storage_qualifier()) - TRY(consume_storage_qualifier()); - - if (!TRY(match_name())) - return false; - - return true; -} - -ErrorOr>> Parser::parse_declarations_in_translation_unit(ASTNode const& parent) -{ - Vector> declarations; - while (!eof()) { - auto declaration = TRY(parse_single_declaration_in_translation_unit(parent)); - if (declaration) { - declarations.append(declaration.release_nonnull()); - } else { - TRY(error("unexpected token"sv)); - TRY(consume()); - } - } - return declarations; -} - -ErrorOr> Parser::parse_single_declaration_in_translation_unit(ASTNode const& parent) -{ - while (!eof()) { - if (match_preprocessor()) { - TRY(consume_preprocessor()); - continue; - } - - auto declaration = TRY(match_declaration_in_translation_unit()); - if (declaration.has_value()) { - return parse_declaration(parent, declaration.value()); - } - return nullptr; - } - return nullptr; -} - -ErrorOr> Parser::parse_declaration(ASTNode const& parent, DeclarationType declaration_type) -{ - switch (declaration_type) { - case DeclarationType::Function: - return parse_function_declaration(parent); - case DeclarationType::Variable: - return parse_variable_declaration(parent); - case DeclarationType::Struct: - return parse_struct_declaration(parent); - default: - TRY(error("unexpected declaration type"sv)); - return create_ast_node(parent, position(), position()); - } -} - -ErrorOr> Parser::parse_struct_declaration(ASTNode const& parent) -{ - TRY(consume_keyword("struct"sv)); - - auto decl = create_ast_node(parent, position(), {}); - decl->set_name(TRY(parse_name(*decl))); - - TRY(consume(Token::Type::LeftCurly)); - while (!eof() && peek().type() != Token::Type::RightCurly) { - decl->set_members(TRY(parse_struct_members(*decl))); - } - TRY(consume(Token::Type::RightCurly)); - - TRY(consume(Token::Type::Semicolon)); - decl->set_end(position()); - - return decl; -} - -ErrorOr>> Parser::parse_struct_members(StructDeclaration& parent) -{ - Vector> members; - while (!eof() && peek().type() != Token::Type::RightCurly) { - auto member = TRY(parse_variable_declaration(parent)); - members.append(move(member)); - } - return members; -} - -ErrorOr> Parser::parse_function_declaration(ASTNode const& parent) -{ - auto func = create_ast_node(parent, position(), {}); - - func->set_return_type(TRY(parse_type(*func))); - func->set_name(TRY(parse_name(*func))); - - TRY(consume(Token::Type::LeftParen)); - func->set_parameters(TRY(parse_parameter_list(*func))); - TRY(consume(Token::Type::RightParen)); - - RefPtr body; - Position func_end {}; - if (peek(Token::Type::LeftCurly).has_value()) { - body = TRY(parse_function_definition(*func)); - func_end = body->end(); - } else { - func_end = position(); - TRY(consume(Token::Type::Semicolon)); - } - - func->set_definition(move(body)); - func->set_end(func_end); - return func; -} - -ErrorOr>> Parser::parse_parameter_list(ASTNode const& parent) -{ - Vector> parameters; - while (peek().type() != Token::Type::RightParen && !eof()) { - auto type = TRY(parse_type(parent)); - - RefPtr name; - if (TRY(match_name())) - name = TRY(parse_name(parent)); - - auto param = create_ast_node(parent, type->start(), !name.is_null() ? name->end() : type->end(), name); - const_cast(*type).set_parent(*param.ptr()); - - param->set_type(move(type)); - parameters.append(move(param)); - - if (peek(Token::Type::Comma).has_value()) - TRY(consume(Token::Type::Comma)); - } - return parameters; -} - -ErrorOr> Parser::parse_function_definition(ASTNode const& parent) -{ - auto func = create_ast_node(parent, position(), {}); - - TRY(consume(Token::Type::LeftCurly)); - while (!eof() && peek().type() != Token::Type::RightCurly) { - func->add_statement(TRY(parse_statement(func))); - } - func->set_end(position()); - TRY(consume(Token::Type::RightCurly)); - - return func; -} - -ErrorOr> Parser::parse_variable_declaration(ASTNode const& parent, bool expect_semicolon) -{ - auto var = create_ast_node(parent, position(), {}); - if (!TRY(match_variable_declaration())) { - TRY(error("unexpected token for variable type"sv)); - var->set_end(position()); - return var; - } - var->set_type(TRY(parse_type(var))); - auto name = TRY(parse_name(*var, true)); - RefPtr initial_value; - - if (match(Token::Type::Equals)) { - TRY(consume(Token::Type::Equals)); - initial_value = TRY(parse_expression(var)); - } - - if (expect_semicolon) - TRY(consume(Token::Type::Semicolon)); - - var->set_end(position()); - var->set_name(name); - var->set_initial_value(move(initial_value)); - - return var; -} - -ErrorOr> Parser::parse_statement(ASTNode const& parent) -{ - bool should_consume_semicolon = true; - RefPtr result; - - if (TRY(match_block_statement())) { - should_consume_semicolon = false; - result = TRY(parse_block_statement(parent)); - } else if (TRY(match_variable_declaration())) { - result = TRY(parse_variable_declaration(parent, false)); - } else if (TRY(match_expression())) { - result = TRY(parse_expression(parent)); - } else if (match_keyword("return"sv)) { - result = TRY(parse_return_statement(parent)); - } else if (match_keyword("discard"sv)) { - auto start = position(); - TRY(consume()); - result = create_ast_node(parent, start, position()); - } else if (match_keyword("for"sv)) { - should_consume_semicolon = false; - result = TRY(parse_for_statement(parent)); - } else if (match_keyword("if"sv)) { - should_consume_semicolon = false; - result = TRY(parse_if_statement(parent)); - } else { - TRY(error("unexpected statement type"sv)); - should_consume_semicolon = false; - TRY(consume()); - return create_ast_node(parent, position(), position()); - } - - if (should_consume_semicolon) - TRY(consume(Token::Type::Semicolon)); - return result.release_nonnull(); -} - -ErrorOr> Parser::parse_block_statement(ASTNode const& parent) -{ - auto block_statement = create_ast_node(parent, position(), {}); - - TRY(consume(Token::Type::LeftCurly)); - while (!eof() && peek().type() != Token::Type::RightCurly) { - block_statement->add_statement(TRY(parse_statement(*block_statement))); - } - TRY(consume(Token::Type::RightCurly)); - - block_statement->set_end(position()); - return block_statement; -} - -ErrorOr> Parser::parse_if_statement(ASTNode const& parent) -{ - auto if_statement = create_ast_node(parent, position(), {}); - TRY(consume_keyword("if"sv)); - TRY(consume(Token::Type::LeftParen)); - if_statement->set_predicate(TRY(parse_expression(*if_statement))); - TRY(consume(Token::Type::RightParen)); - if_statement->set_then_statement(TRY(parse_statement(*if_statement))); - if (match_keyword("else"sv)) { - TRY(consume(Token::Type::Keyword)); - if_statement->set_else_statement(TRY(parse_statement(*if_statement))); - if_statement->set_end(if_statement->else_statement()->end()); - } else { - if_statement->set_end(if_statement->then_statement()->end()); - } - return if_statement; -} - -ErrorOr> Parser::parse_for_statement(ASTNode const& parent) -{ - auto for_statement = create_ast_node(parent, position(), {}); - TRY(consume_keyword("for"sv)); - TRY(consume(Token::Type::LeftParen)); - if (peek().type() != Token::Type::Semicolon) - for_statement->set_init(TRY(parse_variable_declaration(*for_statement, false))); - TRY(consume(Token::Type::Semicolon)); - - if (peek().type() != Token::Type::Semicolon) - for_statement->set_test(TRY(parse_expression(*for_statement))); - TRY(consume(Token::Type::Semicolon)); - - if (peek().type() != Token::Type::RightParen) - for_statement->set_update(TRY(parse_expression(*for_statement))); - TRY(consume(Token::Type::RightParen)); - - for_statement->set_body(TRY(parse_statement(*for_statement))); - - for_statement->set_end(for_statement->body()->end()); - return for_statement; -} - -ErrorOr> Parser::parse_return_statement(ASTNode const& parent) -{ - auto return_statement = create_ast_node(parent, position(), {}); - TRY(consume_keyword("return"sv)); - if (!peek(Token::Type::Semicolon).has_value()) { - return_statement->set_value(TRY(parse_expression(*return_statement))); - } - return_statement->set_end(position()); - return return_statement; -} - -HashMap s_operator_precedence = { - { BinaryOp::Assignment, 1 }, - { BinaryOp::AdditionAssignment, 1 }, - { BinaryOp::SubtractionAssignment, 1 }, - { BinaryOp::MultiplicationAssignment, 1 }, - { BinaryOp::DivisionAssignment, 1 }, - { BinaryOp::ModuloAssignment, 1 }, - { BinaryOp::AndAssignment, 1 }, - { BinaryOp::XorAssignment, 1 }, - { BinaryOp::OrAssignment, 1 }, - { BinaryOp::LeftShiftAssignment, 1 }, - { BinaryOp::RightShiftAssignment, 1 }, - { BinaryOp::LogicalOr, 2 }, - { BinaryOp::LogicalXor, 3 }, - { BinaryOp::LogicalAnd, 4 }, - { BinaryOp::BitwiseOr, 5 }, - { BinaryOp::BitwiseXor, 6 }, - { BinaryOp::BitwiseAnd, 7 }, - { BinaryOp::EqualsEquals, 8 }, - { BinaryOp::NotEqual, 8 }, - { BinaryOp::LessThan, 9 }, - { BinaryOp::LessThanEquals, 9 }, - { BinaryOp::GreaterThan, 9 }, - { BinaryOp::GreaterThanEquals, 9 }, - { BinaryOp::LeftShift, 10 }, - { BinaryOp::RightShift, 10 }, - { BinaryOp::Addition, 11 }, - { BinaryOp::Subtraction, 11 }, - { BinaryOp::Multiplication, 12 }, - { BinaryOp::Division, 12 }, - { BinaryOp::Modulo, 12 }, -}; - -HashMap Parser::s_operator_associativity = { - { BinaryOp::Assignment, Associativity::RightToLeft }, - { BinaryOp::AdditionAssignment, Associativity::RightToLeft }, - { BinaryOp::SubtractionAssignment, Associativity::RightToLeft }, - { BinaryOp::MultiplicationAssignment, Associativity::RightToLeft }, - { BinaryOp::DivisionAssignment, Associativity::RightToLeft }, - { BinaryOp::ModuloAssignment, Associativity::RightToLeft }, - { BinaryOp::AndAssignment, Associativity::RightToLeft }, - { BinaryOp::XorAssignment, Associativity::RightToLeft }, - { BinaryOp::OrAssignment, Associativity::RightToLeft }, - { BinaryOp::LeftShiftAssignment, Associativity::RightToLeft }, - { BinaryOp::RightShiftAssignment, Associativity::RightToLeft }, - { BinaryOp::LogicalOr, Associativity::LeftToRight }, - { BinaryOp::LogicalXor, Associativity::LeftToRight }, - { BinaryOp::LogicalAnd, Associativity::LeftToRight }, - { BinaryOp::BitwiseOr, Associativity::LeftToRight }, - { BinaryOp::BitwiseXor, Associativity::LeftToRight }, - { BinaryOp::BitwiseAnd, Associativity::LeftToRight }, - { BinaryOp::EqualsEquals, Associativity::LeftToRight }, - { BinaryOp::NotEqual, Associativity::LeftToRight }, - { BinaryOp::LessThan, Associativity::LeftToRight }, - { BinaryOp::LessThanEquals, Associativity::LeftToRight }, - { BinaryOp::GreaterThan, Associativity::LeftToRight }, - { BinaryOp::GreaterThanEquals, Associativity::LeftToRight }, - { BinaryOp::LeftShift, Associativity::LeftToRight }, - { BinaryOp::RightShift, Associativity::LeftToRight }, - { BinaryOp::Addition, Associativity::LeftToRight }, - { BinaryOp::Subtraction, Associativity::LeftToRight }, - { BinaryOp::Multiplication, Associativity::LeftToRight }, - { BinaryOp::Division, Associativity::LeftToRight }, - { BinaryOp::Modulo, Associativity::LeftToRight }, -}; - -ErrorOr> Parser::parse_expression(ASTNode const& parent, int min_precedence, Associativity associativity) -{ - auto start_pos = position(); - - auto lhs = TRY(parse_unary_expression(get_dummy_node())); - - while (match_binary_op()) { - auto op = TRY(peek_binary_op()); - auto maybe_op_precedence = s_operator_precedence.get(op); - VERIFY(maybe_op_precedence.has_value()); - - auto op_precedence = maybe_op_precedence.value(); - if (op_precedence < min_precedence || (op_precedence == min_precedence && associativity == Associativity::LeftToRight)) - break; - TRY(consume()); - - auto maybe_op_associativity = s_operator_associativity.get(op); - VERIFY(maybe_op_associativity.has_value()); - auto op_associativity = maybe_op_associativity.value(); - - auto expr = create_ast_node(parent, start_pos, {}); - const_cast(*lhs).set_parent(expr); - expr->set_lhs(move(lhs)); - expr->set_op(op); - expr->set_rhs(TRY(parse_expression(expr, op_precedence, op_associativity))); - - expr->set_end(position()); - - lhs = move(expr); - } - - return lhs; -} - -// NOTE: this function should parse everything with precedence of prefix increment and above, e.g. ++/--/!/~, function call, member expressions and expressions in parentheses -ErrorOr> Parser::parse_unary_expression(const GLSL::ASTNode& parent) -{ - if (match(Token::Type::LeftParen)) { - TRY(consume(Token::Type::LeftParen)); - auto expr = TRY(parse_expression(parent)); - TRY(consume(Token::Type::RightParen)); - - return expr; - } - - if (TRY(match_boolean_literal())) - return parse_boolean_literal(parent); - - if (TRY(match_numeric_literal())) - return parse_numeric_literal(parent); - - if (TRY(match_string_literal())) - return parse_string_literal(parent); - - if (TRY(match_name())) { - NonnullRefPtr lhs = TRY(parse_name(parent)); - - while (true) { - if (match(Token::Type::LeftParen)) { - TRY(consume(Token::Type::LeftParen)); - auto expr = create_ast_node(parent, lhs->start(), {}); - auto args = TRY(parse_function_call_args(expr)); - - const_cast(*lhs).set_parent(expr); - expr->set_callee(move(lhs)); - expr->set_arguments(move(args)); - - TRY(consume(Token::Type::RightParen)); - expr->set_end(position()); - - lhs = move(expr); - } else if (match(Token::Type::Dot)) { - TRY(consume(Token::Type::Dot)); - - auto expr = create_ast_node(parent, lhs->start(), {}); - auto rhs = TRY(parse_name(expr)); - - const_cast(*lhs).set_parent(expr); - expr->set_object(move(lhs)); - expr->set_property(move(rhs)); - expr->set_end(position()); - - lhs = move(expr); - } else if (match(Token::Type::LeftBracket)) { - TRY(consume(Token::Type::LeftBracket)); - - auto expr = create_ast_node(parent, lhs->start(), {}); - auto index = TRY(parse_expression(expr)); - - TRY(consume(Token::Type::RightBracket)); - - const_cast(*lhs).set_parent(expr); - expr->set_array(move(lhs)); - expr->set_index(move(index)); - expr->set_end(position()); - - lhs = move(expr); - } else if (match(Token::Type::PlusPlus) || match(Token::Type::MinusMinus)) { - auto op = TRY(consume_unary_op()); - - auto expr = create_ast_node(parent, lhs->start(), position()); - - const_cast(*lhs).set_parent(expr); - expr->set_lhs(move(lhs)); - expr->set_op(op); - expr->set_is_postfix(true); - - lhs = move(expr); - } else { - break; - } - } - - return lhs; - } - - if (match_unary_op()) { - auto expr = create_ast_node(parent, position(), {}); - auto op = TRY(consume_unary_op()); - - auto lhs = TRY(parse_unary_expression(expr)); - expr->set_lhs(move(lhs)); - expr->set_op(op); - expr->set_end(position()); - - return expr; - } - - TRY(error(TRY(String::formatted("unable to parse unary expression starting with {}", TRY(peek().type_as_string()))))); - return create_ast_node(parent, position(), position()); -} - -ErrorOr>> Parser::parse_function_call_args(ASTNode const& parent) -{ - Vector> result; - while (!match(Token::Type::RightParen)) { - auto arg = TRY(parse_expression(parent)); - result.append(move(arg)); - - if (!match(Token::Type::RightParen)) - TRY(consume(Token::Type::Comma)); - } - return result; -} - -ErrorOr> Parser::parse_boolean_literal(ASTNode const& parent) -{ - auto token = TRY(consume(Token::Type::Keyword)); - auto text = token.text(); - bool value = (text == "true"); - return create_ast_node(parent, token.start(), token.end(), value); -} - -ErrorOr> Parser::parse_numeric_literal(GLSL::ASTNode const& parent) -{ - auto token = TRY(consume()); - auto text = token.text(); - return create_ast_node(parent, token.start(), token.end(), text); -} - -ErrorOr> Parser::parse_string_literal(ASTNode const& parent) -{ - Optional start_token_index; - Optional end_token_index; - while (!eof()) { - auto token = peek(); - if (token.type() != Token::Type::DoubleQuotedString && token.type() != Token::Type::SingleQuotedString && token.type() != Token::Type::EscapeSequence) { - VERIFY(start_token_index.has_value()); - end_token_index = m_state.token_index - 1; - break; - } - if (!start_token_index.has_value()) - start_token_index = m_state.token_index; - TRY(consume()); - } - - // String was not terminated - if (!end_token_index.has_value()) { - end_token_index = m_tokens.size() - 1; - } - - VERIFY(start_token_index.has_value()); - VERIFY(end_token_index.has_value()); - - Token start_token = m_tokens[start_token_index.value()]; - Token end_token = m_tokens[end_token_index.value()]; - - auto text = TRY(text_in_range(start_token.start(), end_token.end())); - auto string_literal = create_ast_node(parent, start_token.start(), end_token.end()); - string_literal->set_value(move(text)); - return string_literal; -} - -ErrorOr> Parser::parse_name(ASTNode const& parent, bool allow_sized_name) -{ - NonnullRefPtr name_node = create_ast_node(parent, position(), {}); - - if (peek().type() == Token::Type::Identifier || peek().type() == Token::Type::KnownType) { - auto token = TRY(consume()); - name_node->set_name(token.text()); - name_node->set_end(position()); - } else { - TRY(error("expected keyword or identifier while trying to parse name"sv)); - name_node->set_end(position()); - return name_node; - } - - if (peek().type() == Token::Type::LeftBracket && allow_sized_name) { - NonnullRefPtr sized_name = create_ast_node(parent, name_node->start(), {}); - sized_name->set_name(name_node->name()); - - while (peek().type() == Token::Type::LeftBracket) { - TRY(consume(Token::Type::LeftBracket)); - - StringView size = "0"sv; - if (peek().type() == Token::Type::Integer) - size = TRY(consume(Token::Type::Integer)).text(); - sized_name->append_dimension(size); - - TRY(consume(Token::Type::RightBracket)); - } - name_node->set_end(position()); - name_node = sized_name; - } - - name_node->set_end(previous_token_end()); - return name_node; -} - -ErrorOr> Parser::parse_type(ASTNode const& parent) -{ - auto type = create_ast_node(parent, position(), {}); - - Vector storage_qualifiers; - while (match_storage_qualifier()) { - storage_qualifiers.append(TRY(consume_storage_qualifier())); - } - type->set_storage_qualifiers(move(storage_qualifiers)); - - if (match_keyword("struct"sv)) { - TRY(consume(Token::Type::Keyword)); // Consume struct prefix - } - - if (!TRY(match_name())) { - type->set_end(position()); - TRY(error(TRY(String::formatted("expected name instead of: {}", peek().text())))); - return type; - } - type->set_name(TRY(parse_name(*type))); - - type->set_end(previous_token_end()); - - return type; -} - -bool Parser::match_unary_op() -{ - return match(Token::Type::Plus) - || match(Token::Type::Minus) - || match(Token::Type::PlusPlus) - || match(Token::Type::MinusMinus) - || match(Token::Type::ExclamationMark) - || match(Token::Type::Tilde); -} - -ErrorOr Parser::consume_unary_op() -{ - switch (TRY(consume()).type()) { - case Token::Type::Plus: - return UnaryOp::Plus; - case Token::Type::Minus: - return UnaryOp::Minus; - case Token::Type::PlusPlus: - return UnaryOp::PlusPlus; - case Token::Type::MinusMinus: - return UnaryOp::MinusMinus; - case Token::Type::ExclamationMark: - return UnaryOp::Not; - case Token::Type::Tilde: - return UnaryOp::BitwiseNot; - default: - VERIFY_NOT_REACHED(); - } -} - -bool Parser::match_binary_op() -{ - return match(Token::Type::Plus) - || match(Token::Type::Minus) - || match(Token::Type::Asterisk) - || match(Token::Type::Slash) - || match(Token::Type::Percent) - || match(Token::Type::And) - || match(Token::Type::Pipe) - || match(Token::Type::Caret) - || match(Token::Type::AndAnd) - || match(Token::Type::PipePipe) - || match(Token::Type::CaretCaret) - || match(Token::Type::LessLess) - || match(Token::Type::GreaterGreater) - || match(Token::Type::Less) - || match(Token::Type::LessEquals) - || match(Token::Type::Greater) - || match(Token::Type::GreaterEquals) - || match(Token::Type::EqualsEquals) - || match(Token::Type::ExclamationMarkEquals) - || match(Token::Type::Equals) - || match(Token::Type::PlusEquals) - || match(Token::Type::MinusEquals) - || match(Token::Type::AsteriskEquals) - || match(Token::Type::SlashEquals) - || match(Token::Type::PercentEquals) - || match(Token::Type::LessLessEquals) - || match(Token::Type::GreaterGreaterEquals) - || match(Token::Type::AndEquals) - || match(Token::Type::PipeEquals) - || match(Token::Type::CaretEquals); -} - -ErrorOr Parser::peek_binary_op() -{ - switch (peek().type()) { - case Token::Type::Plus: - return BinaryOp::Addition; - case Token::Type::Minus: - return BinaryOp::Subtraction; - case Token::Type::Asterisk: - return BinaryOp::Multiplication; - case Token::Type::Slash: - return BinaryOp::Division; - case Token::Type::Percent: - return BinaryOp::Modulo; - case Token::Type::And: - return BinaryOp::BitwiseAnd; - case Token::Type::Pipe: - return BinaryOp::BitwiseOr; - case Token::Type::Caret: - return BinaryOp::BitwiseXor; - case Token::Type::AndAnd: - return BinaryOp::LogicalAnd; - case Token::Type::PipePipe: - return BinaryOp::LogicalOr; - case Token::Type::CaretCaret: - return BinaryOp::LogicalXor; - case Token::Type::LessLess: - return BinaryOp::LeftShift; - case Token::Type::GreaterGreater: - return BinaryOp::RightShift; - case Token::Type::Less: - return BinaryOp::LessThan; - case Token::Type::LessEquals: - return BinaryOp::LessThanEquals; - case Token::Type::Greater: - return BinaryOp::GreaterThan; - case Token::Type::GreaterEquals: - return BinaryOp::GreaterThanEquals; - case Token::Type::EqualsEquals: - return BinaryOp::EqualsEquals; - case Token::Type::ExclamationMarkEquals: - return BinaryOp::NotEqual; - case Token::Type::Equals: - return BinaryOp::Assignment; - case Token::Type::PlusEquals: - return BinaryOp::AdditionAssignment; - case Token::Type::MinusEquals: - return BinaryOp::SubtractionAssignment; - case Token::Type::AsteriskEquals: - return BinaryOp::MultiplicationAssignment; - case Token::Type::SlashEquals: - return BinaryOp::DivisionAssignment; - case Token::Type::PercentEquals: - return BinaryOp::ModuloAssignment; - case Token::Type::LessLessEquals: - return BinaryOp::LeftShiftAssignment; - case Token::Type::GreaterGreaterEquals: - return BinaryOp::RightShiftAssignment; - case Token::Type::AndEquals: - return BinaryOp::AndAssignment; - case Token::Type::PipeEquals: - return BinaryOp::OrAssignment; - case Token::Type::CaretEquals: - return BinaryOp::XorAssignment; - default: - VERIFY_NOT_REACHED(); - } -} - -bool Parser::match_storage_qualifier() -{ - return match_keyword("const"sv) - || match_keyword("in"sv) - || match_keyword("out"sv) - || match_keyword("inout"sv) - || match_keyword("centroid"sv) - || match_keyword("patch"sv) - || match_keyword("sample"sv) - || match_keyword("uniform"sv) - || match_keyword("buffer"sv) - || match_keyword("shared"sv) - || match_keyword("coherent"sv) - || match_keyword("volatile"sv) - || match_keyword("restrict"sv) - || match_keyword("readonly"sv) - || match_keyword("writeonly"sv) - || match_keyword("subroutine"sv); -} - -ErrorOr Parser::consume_storage_qualifier() -{ - VERIFY(peek().type() == Token::Type::Keyword); - auto keyword = MUST(consume()).text(); - if (keyword == "buffer") - return StorageTypeQualifier::Buffer; - if (keyword == "centroid") - return StorageTypeQualifier::Centroid; - if (keyword == "coherent") - return StorageTypeQualifier::Coherent; - if (keyword == "const") - return StorageTypeQualifier::Const; - if (keyword == "in") - return StorageTypeQualifier::In; - if (keyword == "inout") - return StorageTypeQualifier::Inout; - if (keyword == "out") - return StorageTypeQualifier::Out; - if (keyword == "patch") - return StorageTypeQualifier::Patch; - if (keyword == "readonly") - return StorageTypeQualifier::Readonly; - if (keyword == "restrict") - return StorageTypeQualifier::Restrict; - if (keyword == "sample") - return StorageTypeQualifier::Sample; - if (keyword == "shared") - return StorageTypeQualifier::Shared; - if (keyword == "subroutine") - return StorageTypeQualifier::Subroutine; - if (keyword == "uniform") - return StorageTypeQualifier::Uniform; - if (keyword == "volatile") - return StorageTypeQualifier::Volatile; - if (keyword == "writeonly") - return StorageTypeQualifier::Writeonly; - VERIFY_NOT_REACHED(); -} - -Token Parser::peek(size_t offset) const -{ - if (m_state.token_index + offset >= m_tokens.size()) - return { Token::Type::EOF_TOKEN, position(), position(), {} }; - return m_tokens[m_state.token_index + offset]; -} - -Optional Parser::peek(Token::Type type) const -{ - auto token = peek(); - if (token.type() == type) - return token; - return {}; -} - -bool Parser::match(Token::Type type) -{ - return peek().type() == type; -} - -bool Parser::match_keyword(StringView keyword) -{ - auto token = peek(); - if (token.type() != Token::Type::Keyword) { - return false; - } - if (token.text() != keyword) { - return false; - } - return true; -} - -bool Parser::match_preprocessor() -{ - return match(Token::Type::PreprocessorStatement) || match(Token::Type::IncludeStatement); -} - -ErrorOr Parser::consume() -{ - if (eof()) { - TRY(error("GLSL Parser: out of tokens"sv)); - return Token { Token::Type::EOF_TOKEN, position(), position(), {} }; - } - return m_tokens[m_state.token_index++]; -} - -ErrorOr Parser::consume(Token::Type type) -{ - auto token = TRY(consume()); - if (token.type() != type) - TRY(error(TRY(String::formatted("expected {} at {}:{}, found: {}", Token::type_to_string(type), token.start().line, token.start().column, Token::type_to_string(token.type()))))); - return token; -} - -ErrorOr Parser::consume_keyword(StringView keyword) -{ - auto token = TRY(consume()); - if (token.type() != Token::Type::Keyword) { - TRY(error(TRY(String::formatted("unexpected token: {}, expected Keyword", TRY(token.to_string()))))); - return token; - } - if (token.text() != keyword) { - TRY(error(TRY(String::formatted("unexpected keyword: {}, expected {}", token.text(), keyword)))); - return token; - } - return token; -} - -ErrorOr Parser::consume_preprocessor() -{ - switch (peek().type()) { - case Token::Type::PreprocessorStatement: - TRY(consume()); - break; - case Token::Type::IncludeStatement: - TRY(consume()); - TRY(consume(Token::Type::IncludePath)); - break; - default: - TRY(error("unexpected token while parsing preprocessor statement"sv)); - TRY(consume()); - } - return {}; -} - -Position Parser::position() const -{ - if (m_tokens.is_empty()) - return {}; - - if (eof()) - return m_tokens.last().end(); - - return peek().start(); -} - -Position Parser::previous_token_end() const -{ - if (m_state.token_index < 1) - return {}; - return m_tokens[m_state.token_index - 1].end(); -} - -Optional Parser::index_of_token_at(Position pos) const -{ - for (size_t token_index = 0; token_index < m_tokens.size(); ++token_index) { - auto token = m_tokens[token_index]; - if (token.start() > pos || token.end() < pos) - continue; - return token_index; - } - return {}; -} - -Vector Parser::tokens_in_range(Position start, Position end) const -{ - auto start_token_index = index_of_token_at(start); - auto end_node_index = index_of_token_at(end); - VERIFY(start_token_index.has_value()); - VERIFY(end_node_index.has_value()); - - Vector tokens; - for (size_t i = start_token_index.value(); i <= end_node_index.value(); ++i) { - tokens.append(m_tokens[i]); - } - return tokens; -} - -ErrorOr Parser::text_in_range(Position start, Position end) const -{ - StringBuilder builder; - for (auto token : tokens_in_range(start, end)) { - builder.append(token.text()); - } - return builder.to_string(); -} - -ErrorOr Parser::error(StringView message) -{ - if (!m_saved_states.is_empty()) - return {}; - - if (message.is_null() || message.is_empty()) - message = ""sv; - String formatted_message; - if (m_state.token_index >= m_tokens.size()) { - formatted_message = TRY(String::formatted("GLSL Parsed error on EOF.{}", message)); - } else { - formatted_message = TRY(String::formatted("GLSL Parser error: {}. token: {} ({}:{})", - message, - m_state.token_index < m_tokens.size() ? m_tokens[m_state.token_index].text() : "EOF"sv, - m_tokens[m_state.token_index].start().line, - m_tokens[m_state.token_index].start().column)); - } - - m_errors.append(formatted_message); - return {}; -} - -void Parser::save_state() -{ - m_saved_states.append(m_state); -} - -void Parser::load_state() -{ - m_state = m_saved_states.take_last(); -} - -} diff --git a/Userland/Libraries/LibGLSL/Parser.h b/Userland/Libraries/LibGLSL/Parser.h deleted file mode 100644 index cdfee2a97da..00000000000 --- a/Userland/Libraries/LibGLSL/Parser.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * Copyright (c) 2023, Volodymyr V. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace GLSL { - -class Parser final { - AK_MAKE_NONCOPYABLE(Parser); - -public: - explicit Parser(Vector tokens, String const& filename); - ~Parser() = default; - - ErrorOr> parse(); - bool eof() const; - - RefPtr root_node() const { return m_root_node; } - void print_tokens() const; - Vector const& tokens() const { return m_tokens; } - Vector const& errors() const { return m_errors; } - -private: - enum class DeclarationType { - Function, - Variable, - Struct, - }; - ErrorOr> match_declaration_in_translation_unit(); - - ErrorOr match_struct_declaration(); - ErrorOr match_function_declaration(); - ErrorOr match_variable_declaration(); - - ErrorOr match_block_statement(); - - ErrorOr match_expression(); - ErrorOr match_name(); - ErrorOr match_string_literal(); - ErrorOr match_numeric_literal(); - ErrorOr match_boolean_literal(); - - ErrorOr match_type(); - - ErrorOr>> parse_declarations_in_translation_unit(ASTNode const& parent); - ErrorOr> parse_single_declaration_in_translation_unit(ASTNode const& parent); - ErrorOr> parse_declaration(ASTNode const& parent, DeclarationType); - ErrorOr> parse_struct_declaration(ASTNode const& parent); - ErrorOr>> parse_struct_members(StructDeclaration& parent); - ErrorOr> parse_function_declaration(ASTNode const& parent); - ErrorOr>> parse_parameter_list(ASTNode const& parent); - ErrorOr> parse_function_definition(ASTNode const& parent); - ErrorOr> parse_variable_declaration(ASTNode const& parent, bool expect_semicolon = true); - - ErrorOr> parse_statement(ASTNode const& parent); - ErrorOr> parse_block_statement(ASTNode const& parent); - ErrorOr> parse_if_statement(ASTNode const& parent); - ErrorOr> parse_for_statement(ASTNode const& parent); - ErrorOr> parse_return_statement(ASTNode const& parent); - - enum class Associativity { - LeftToRight, - RightToLeft - }; - static HashMap s_operator_associativity; - - ErrorOr> parse_expression(ASTNode const& parent, int min_precedence = 0, Associativity associativity = Associativity::LeftToRight); - ErrorOr> parse_unary_expression(ASTNode const& parent); - ErrorOr>> parse_function_call_args(ASTNode const& parent); - ErrorOr> parse_boolean_literal(ASTNode const& parent); - ErrorOr> parse_numeric_literal(ASTNode const& parent); - ErrorOr> parse_string_literal(ASTNode const& parent); - ErrorOr> parse_name(ASTNode const& parent, bool allow_sized_name = false); - - ErrorOr> parse_type(ASTNode const& parent); - - bool match_unary_op(); - ErrorOr consume_unary_op(); - bool match_binary_op(); - ErrorOr peek_binary_op(); - bool match_storage_qualifier(); - ErrorOr consume_storage_qualifier(); - - Token peek(size_t offset = 0) const; - Optional peek(Token::Type) const; - - bool match(Token::Type); - bool match_keyword(StringView); - bool match_preprocessor(); - - ErrorOr consume(); - ErrorOr consume(Token::Type); - ErrorOr consume_keyword(StringView); - ErrorOr consume_preprocessor(); - - Position position() const; - Position previous_token_end() const; - Optional index_of_token_at(Position pos) const; - Vector tokens_in_range(Position start, Position end) const; - ErrorOr text_in_range(Position start, Position end) const; - - ErrorOr error(StringView message = {}); - - template - NonnullRefPtr - create_ast_node(ASTNode const& parent, Position const& start, Optional end, Args&&... args) - { - auto node = adopt_ref(*new T(&parent, start, end, m_filename, forward(args)...)); - return node; - } - - NonnullRefPtr - create_root_ast_node(Position const& start, Position end) - { - auto node = adopt_ref(*new TranslationUnit(nullptr, start, end, m_filename)); - m_root_node = node; - return node; - } - - DummyAstNode& get_dummy_node() - { - static NonnullRefPtr dummy = adopt_ref(*new DummyAstNode(nullptr, {}, {}, {})); - return dummy; - } - - struct State { - size_t token_index { 0 }; - }; - - void save_state(); - void load_state(); - - State m_state; - Vector m_saved_states; - - String m_filename; - Vector m_tokens; - RefPtr m_root_node; - Vector m_errors; -}; - -} diff --git a/Userland/Libraries/LibGLSL/Preprocessor.cpp b/Userland/Libraries/LibGLSL/Preprocessor.cpp deleted file mode 100644 index 8ffad9018af..00000000000 --- a/Userland/Libraries/LibGLSL/Preprocessor.cpp +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * Copyright (c) 2023, Volodymyr V. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Preprocessor.h" -#include -#include -#include -#include -#include - -namespace GLSL { -Preprocessor::Preprocessor(String filename, String program) - : m_filename(move(filename)) - , m_program(move(program)) -{ -} - -ErrorOr> Preprocessor::process_and_lex() -{ - Lexer lexer { m_program }; - lexer.set_ignore_whitespace(true); - auto tokens = lexer.lex(); - - m_unprocessed_tokens = tokens; - - for (size_t token_index = 0; token_index < tokens.size(); ++token_index) { - auto& token = tokens[token_index]; - m_current_line = token.start().line; - if (token.type() == Token::Type::PreprocessorStatement) { - TRY(handle_preprocessor_statement(token.text())); - m_processed_tokens.append(tokens[token_index]); - continue; - } - - if (m_state != State::Normal) - continue; - - if (token.type() == Token::Type::IncludeStatement) { - if (token_index >= tokens.size() - 1 || tokens[token_index + 1].type() != Token::Type::IncludePath) - continue; - handle_include_statement(tokens[token_index + 1].text()); - if (m_options.keep_include_statements) { - m_processed_tokens.append(tokens[token_index]); - m_processed_tokens.append(tokens[token_index + 1]); - } - ++token_index; // Also skip IncludePath token - continue; - } - - if (token.type() == Token::Type::Identifier) { - if (auto defined_value = m_definitions.find(token.text()); defined_value != m_definitions.end()) { - auto last_substituted_token_index = TRY(do_substitution(tokens, token_index, defined_value->value)); - token_index = last_substituted_token_index; - continue; - } - } - - m_processed_tokens.append(token); - } - - return m_processed_tokens; -} - -static void consume_whitespace(GenericLexer& lexer) -{ - auto ignore_line = [&] { - for (;;) { - if (lexer.consume_specific("\\\n"sv)) { - lexer.ignore(2); - } else { - lexer.ignore_until('\n'); - lexer.ignore(); - break; - } - } - }; - for (;;) { - if (lexer.consume_specific("//"sv)) { - ignore_line(); - } else if (lexer.consume_specific("/*"sv)) { - lexer.ignore_until("*/"); - lexer.ignore(2); - } else if (lexer.next_is("\\\n"sv)) { - lexer.ignore(2); - } else if (lexer.is_eof() || !lexer.next_is(isspace)) { - break; - } else { - lexer.ignore(); - } - } -} - -ErrorOr Preprocessor::handle_preprocessor_statement(StringView line) -{ - GenericLexer lexer(line); - - consume_whitespace(lexer); - lexer.consume_specific('#'); - consume_whitespace(lexer); - auto keyword = lexer.consume_until(' '); - lexer.ignore(); - if (keyword.is_empty() || keyword.is_null() || keyword.is_whitespace()) - return {}; - - return TRY(handle_preprocessor_keyword(keyword, lexer)); -} - -void Preprocessor::handle_include_statement(StringView include_path) -{ - m_included_paths.append(include_path); - if (definitions_in_header_callback) { - for (auto& def : definitions_in_header_callback(include_path)) - m_definitions.set(def.key, def.value); - } -} - -ErrorOr Preprocessor::handle_preprocessor_keyword(StringView keyword, GenericLexer& line_lexer) -{ - if (keyword == "include") { - // Should have called 'handle_include_statement'. - VERIFY_NOT_REACHED(); - } - - if (keyword == "else") { - if (m_options.ignore_invalid_statements && m_current_depth == 0) - return {}; - VERIFY(m_current_depth > 0); - if (m_depths_of_not_taken_branches.contains_slow(m_current_depth - 1)) { - m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth - 1; }); - m_state = State::Normal; - } - if (m_depths_of_taken_branches.contains_slow(m_current_depth - 1)) { - m_state = State::SkipElseBranch; - } - return {}; - } - - if (keyword == "endif") { - if (m_options.ignore_invalid_statements && m_current_depth == 0) - return {}; - VERIFY(m_current_depth > 0); - --m_current_depth; - if (m_depths_of_not_taken_branches.contains_slow(m_current_depth)) { - m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth; }); - } - if (m_depths_of_taken_branches.contains_slow(m_current_depth)) { - m_depths_of_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth; }); - } - m_state = State::Normal; - return {}; - } - - if (keyword == "define") { - if (m_state == State::Normal) { - auto definition = TRY(create_definition(line_lexer.consume_all())); - if (definition.has_value()) - m_definitions.set(definition->key, *definition); - } - return {}; - } - if (keyword == "undef") { - if (m_state == State::Normal) { - auto key = line_lexer.consume_until(' '); - line_lexer.consume_all(); - m_definitions.remove(key); - } - return {}; - } - if (keyword == "ifdef") { - ++m_current_depth; - if (m_state == State::Normal) { - auto key = line_lexer.consume_until(' '); - line_lexer.ignore(); - if (m_definitions.contains(key)) { - m_depths_of_taken_branches.append(m_current_depth - 1); - return {}; - } else { - m_depths_of_not_taken_branches.append(m_current_depth - 1); - m_state = State::SkipIfBranch; - return {}; - } - } - return {}; - } - if (keyword == "ifndef") { - ++m_current_depth; - if (m_state == State::Normal) { - auto key = line_lexer.consume_until(' '); - line_lexer.ignore(); - if (!m_definitions.contains(key)) { - m_depths_of_taken_branches.append(m_current_depth - 1); - return {}; - } else { - m_depths_of_not_taken_branches.append(m_current_depth - 1); - m_state = State::SkipIfBranch; - return {}; - } - } - return {}; - } - if (keyword == "if") { - ++m_current_depth; - if (m_state == State::Normal) { - // FIXME: Implement #if logic - // We currently always take #if branches. - m_depths_of_taken_branches.append(m_current_depth - 1); - } - return {}; - } - - if (keyword == "elif") { - if (m_options.ignore_invalid_statements && m_current_depth == 0) - return {}; - VERIFY(m_current_depth > 0); - // FIXME: Evaluate the elif expression - // We currently always treat the expression in #elif as true. - if (m_depths_of_not_taken_branches.contains_slow(m_current_depth - 1) /* && should_take*/) { - m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth - 1; }); - m_state = State::Normal; - } - if (m_depths_of_taken_branches.contains_slow(m_current_depth - 1)) { - m_state = State::SkipElseBranch; - } - return {}; - } - if (keyword == "pragma") { - line_lexer.consume_all(); - return {}; - } - if (keyword == "error") { - line_lexer.consume_all(); - return {}; - } - - if (!m_options.ignore_unsupported_keywords) { - dbgln("Unsupported preprocessor keyword: {}", keyword); - VERIFY_NOT_REACHED(); - } - return {}; -} - -ErrorOr Preprocessor::do_substitution(Vector const& tokens, size_t token_index, Definition const& defined_value) -{ - if (defined_value.value.is_empty()) - return token_index; - - Substitution sub; - sub.defined_value = defined_value; - - auto macro_call = parse_macro_call(tokens, token_index); - - if (!macro_call.has_value()) - return token_index; - - Vector original_tokens; - for (size_t i = token_index; i <= macro_call->end_token_index; ++i) { - original_tokens.append(tokens[i]); - } - VERIFY(!original_tokens.is_empty()); - - auto processed_value = TRY(evaluate_macro_call(*macro_call, defined_value)); - m_substitutions.append({ original_tokens, defined_value, processed_value }); - - Lexer lexer(processed_value); - lexer.lex_iterable([&](auto token) { - if (token.type() == Token::Type::Whitespace) - return; - token.set_start(original_tokens.first().start()); - token.set_end(original_tokens.first().end()); - m_processed_tokens.append(token); - }); - return macro_call->end_token_index; -} - -Optional Preprocessor::parse_macro_call(Vector const& tokens, size_t token_index) -{ - auto name = tokens[token_index]; - ++token_index; - - if (token_index >= tokens.size() || tokens[token_index].type() != Token::Type::LeftParen) - return MacroCall { name, {}, token_index - 1 }; - ++token_index; - - Vector arguments; - Optional current_argument; - - size_t paren_depth = 1; - for (; token_index < tokens.size(); ++token_index) { - auto& token = tokens[token_index]; - if (token.type() == Token::Type::LeftParen) - ++paren_depth; - if (token.type() == Token::Type::RightParen) - --paren_depth; - - if (paren_depth == 0) { - if (current_argument.has_value()) - arguments.append(*current_argument); - break; - } - - if (paren_depth == 1 && token.type() == Token::Type::Comma) { - if (current_argument.has_value()) - arguments.append(*current_argument); - current_argument = {}; - } else { - if (!current_argument.has_value()) - current_argument = MacroCall::Argument {}; - current_argument->tokens.append(token); - } - } - - if (token_index >= tokens.size()) - return {}; - - return MacroCall { name, move(arguments), token_index }; -} - -ErrorOr> Preprocessor::create_definition(StringView line) -{ - Lexer lexer { line }; - lexer.set_ignore_whitespace(true); - auto tokens = lexer.lex(); - if (tokens.is_empty()) - return Optional {}; - - if (tokens.first().type() != Token::Type::Identifier) - return Optional {}; - - Definition definition; - definition.filename = m_filename; - definition.line = m_current_line; - - definition.key = tokens.first().text(); - - if (tokens.size() == 1) - return definition; - - size_t token_index = 1; - // Parse macro parameters (if any) - if (tokens[token_index].type() == Token::Type::LeftParen) { - ++token_index; - while (token_index < tokens.size() && tokens[token_index].type() != Token::Type::RightParen) { - auto param = tokens[token_index]; - if (param.type() != Token::Type::Identifier) - return Optional {}; - - if (token_index + 1 >= tokens.size()) - return Optional {}; - - ++token_index; - - if (tokens[token_index].type() == Token::Type::Comma) - ++token_index; - else if (tokens[token_index].type() != Token::Type::RightParen) - return Optional {}; - - definition.parameters.empend(param.text()); - } - if (token_index >= tokens.size()) - return Optional {}; - ++token_index; - } - - if (token_index < tokens.size()) - definition.value = TRY(remove_escaped_newlines(line.substring_view(tokens[token_index].start().column))); - - return definition; -} - -ErrorOr Preprocessor::remove_escaped_newlines(StringView value) -{ - static constexpr auto escaped_newline = "\\\n"sv; - AK::StringBuilder processed_value; - GenericLexer lexer { value }; - while (!lexer.is_eof()) { - processed_value.append(lexer.consume_until(escaped_newline)); - lexer.ignore(escaped_newline.length()); - } - return processed_value.to_string(); -} - -ErrorOr Preprocessor::evaluate_macro_call(MacroCall const& macro_call, Definition const& definition) -{ - if (macro_call.arguments.size() != definition.parameters.size()) { - dbgln("mismatch in # of arguments for macro call: {}", macro_call.name.text()); - return String {}; - } - - Lexer lexer { definition.value }; - StringBuilder processed_value; - lexer.lex_iterable([&](auto token) { - if (token.type() != Token::Type::Identifier) { - processed_value.append(token.text()); - return; - } - - auto param_index = definition.parameters.find_first_index(token.text()); - if (!param_index.has_value()) { - processed_value.append(token.text()); - return; - } - - auto& argument = macro_call.arguments[*param_index]; - for (auto& arg_token : argument.tokens) { - processed_value.append(arg_token.text()); - } - }); - - return processed_value.to_string(); -} - -}; diff --git a/Userland/Libraries/LibGLSL/Preprocessor.h b/Userland/Libraries/LibGLSL/Preprocessor.h deleted file mode 100644 index 4fad48ddd0e..00000000000 --- a/Userland/Libraries/LibGLSL/Preprocessor.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * Copyright (c) 2023, Volodymyr V. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace GLSL { - -class Preprocessor { - -public: - explicit Preprocessor(String filename, String program); - ErrorOr> process_and_lex(); - Vector included_paths() const { return m_included_paths; } - - struct Definition { - StringView key; - Vector parameters; - String value; - FlyString filename; - size_t line { 0 }; - size_t column { 0 }; - }; - using Definitions = HashMap; - - struct Substitution { - Vector original_tokens; - Definition defined_value; - String processed_value; - }; - - Definitions const& definitions() const { return m_definitions; } - Vector const& substitutions() const { return m_substitutions; } - - void set_ignore_unsupported_keywords(bool ignore) { m_options.ignore_unsupported_keywords = ignore; } - void set_ignore_invalid_statements(bool ignore) { m_options.ignore_invalid_statements = ignore; } - void set_keep_include_statements(bool keep) { m_options.keep_include_statements = keep; } - - Function definitions_in_header_callback { nullptr }; - - Vector const& unprocessed_tokens() const { return m_unprocessed_tokens; } - -private: - ErrorOr handle_preprocessor_statement(StringView); - void handle_include_statement(StringView); - ErrorOr handle_preprocessor_keyword(StringView keyword, GenericLexer& line_lexer); - ErrorOr remove_escaped_newlines(StringView value); - - ErrorOr do_substitution(Vector const& tokens, size_t token_index, Definition const&); - ErrorOr> create_definition(StringView line); - - struct MacroCall { - Token name; - struct Argument { - Vector tokens; - }; - Vector arguments; - size_t end_token_index { 0 }; - }; - Optional parse_macro_call(Vector const& tokens, size_t token_index); - ErrorOr evaluate_macro_call(MacroCall const&, Definition const&); - - String m_filename; - String m_program; - - Vector m_unprocessed_tokens; - Vector m_processed_tokens; - Definitions m_definitions; - Vector m_substitutions; - - size_t m_current_line { 0 }; - size_t m_current_depth { 0 }; - Vector m_depths_of_taken_branches; - Vector m_depths_of_not_taken_branches; - - enum class State { - Normal, - SkipIfBranch, - SkipElseBranch - }; - State m_state { State::Normal }; - - Vector m_included_paths; - - struct Options { - bool ignore_unsupported_keywords { false }; - bool ignore_invalid_statements { false }; - bool keep_include_statements { false }; - } m_options; -}; -} diff --git a/Userland/Libraries/LibGLSL/Tests/parser/discard.ast b/Userland/Libraries/LibGLSL/Tests/parser/discard.ast deleted file mode 100644 index 40b6b049568..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/discard.ast +++ /dev/null @@ -1,11 +0,0 @@ -TranslationUnit[0:0->3:0] - FunctionDeclaration[0:0->3:0] - Type[0:0->0:3] - void - foo - ( - ) - FunctionDefinition[1:0->3:0] - { - DiscardStatement[2:4->2:11] - } diff --git a/Userland/Libraries/LibGLSL/Tests/parser/discard.glsl b/Userland/Libraries/LibGLSL/Tests/parser/discard.glsl deleted file mode 100644 index d45f744afec..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/discard.glsl +++ /dev/null @@ -1,5 +0,0 @@ -void foo() -{ - discard; -} - diff --git a/Userland/Libraries/LibGLSL/Tests/parser/expression.ast b/Userland/Libraries/LibGLSL/Tests/parser/expression.ast deleted file mode 100644 index 7f0b8fa60b1..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/expression.ast +++ /dev/null @@ -1,63 +0,0 @@ -TranslationUnit[0:0->3:0] - FunctionDeclaration[0:0->3:0] - Type[0:0->0:3] - void - foo - ( - ) - FunctionDefinition[1:0->3:0] - { - VariableDeclaration[2:4->2:66] - Type[2:4->2:6] - int - a - BinaryExpression[2:12->2:66] - BinaryExpression[2:12->2:57] - BinaryExpression[2:12->2:48] - BinaryExpression[2:12->2:36] - BinaryExpression[2:12->2:22] - NumericLiteral[2:12->2:12] - 1 - + - BinaryExpression[2:16->2:22] - NumericLiteral[2:16->2:16] - 2 - * - NumericLiteral[2:20->2:20] - 3 - + - BinaryExpression[2:24->2:36] - BinaryExpression[2:25->2:30] - NumericLiteral[2:25->2:25] - 4 - - - NumericLiteral[2:29->2:29] - 2 - / - NumericLiteral[2:34->2:34] - 2 - + - FunctionCall[2:38->2:48] - Name[2:38->2:40] - max - ( - NumericLiteral[2:42->2:42] - 7 - NumericLiteral[2:45->2:45] - 8 - ) - - - MemberExpression[2:50->2:57] - Name[2:50->2:52] - bar - Name[2:54->2:55] - xy - + - ArrayElementExpression[2:59->2:66] - Name[2:59->2:61] - abc - [ - NumericLiteral[2:63->2:64] - 13 - ] - } diff --git a/Userland/Libraries/LibGLSL/Tests/parser/expression.glsl b/Userland/Libraries/LibGLSL/Tests/parser/expression.glsl deleted file mode 100644 index dd1d0125aea..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/expression.glsl +++ /dev/null @@ -1,5 +0,0 @@ -void foo() -{ - int a = 1 + 2 * 3 + (4 - 2) / 2 + max(7, 8) - bar.xy + abc[13]; -} - diff --git a/Userland/Libraries/LibGLSL/Tests/parser/for-statement.ast b/Userland/Libraries/LibGLSL/Tests/parser/for-statement.ast deleted file mode 100644 index 8550eda3a98..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/for-statement.ast +++ /dev/null @@ -1,37 +0,0 @@ -TranslationUnit[0:0->5:0] - FunctionDeclaration[0:0->5:0] - Type[0:0->0:3] - void - main - ( - ) - FunctionDefinition[1:0->5:0] - { - VariableDeclaration[2:4->2:13] - Type[2:4->2:6] - int - b - NumericLiteral[2:12->2:12] - 0 - ForStatement[3:4->4:11] - Initializer: - VariableDeclaration[3:9->3:18] - Type[3:9->3:11] - int - a - NumericLiteral[3:17->3:17] - 0 - Test expression: - BooleanLiteral[3:20->3:23] - true - Update expression: - UnaryExpression[3:26->3:29] - postfix ++ - Name[3:26->3:26] - a - Body: - UnaryExpression[4:8->4:11] - postfix ++ - Name[4:8->4:8] - b - } diff --git a/Userland/Libraries/LibGLSL/Tests/parser/for-statement.glsl b/Userland/Libraries/LibGLSL/Tests/parser/for-statement.glsl deleted file mode 100644 index c4407621ca4..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/for-statement.glsl +++ /dev/null @@ -1,7 +0,0 @@ -void main() -{ - int b = 0; - for (int a = 0; true; a++) - b++; -} - diff --git a/Userland/Libraries/LibGLSL/Tests/parser/function-declaration.ast b/Userland/Libraries/LibGLSL/Tests/parser/function-declaration.ast deleted file mode 100644 index 1a4146188a9..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/function-declaration.ast +++ /dev/null @@ -1,15 +0,0 @@ -TranslationUnit[0:0->0:24] - FunctionDeclaration[0:0->0:24] - Type[0:0->0:2] - int - main - ( - Parameter[0:9->0:13] - a - Type[0:9->0:11] - int - Parameter[0:16->0:22] - b - Type[0:16->0:20] - float - ) diff --git a/Userland/Libraries/LibGLSL/Tests/parser/function-declaration.glsl b/Userland/Libraries/LibGLSL/Tests/parser/function-declaration.glsl deleted file mode 100644 index 8faf42093ad..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/function-declaration.glsl +++ /dev/null @@ -1,2 +0,0 @@ -int main(int a, float b); - diff --git a/Userland/Libraries/LibGLSL/Tests/parser/function-definition.ast b/Userland/Libraries/LibGLSL/Tests/parser/function-definition.ast deleted file mode 100644 index 95ea1ed6aee..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/function-definition.ast +++ /dev/null @@ -1,13 +0,0 @@ -TranslationUnit[0:0->3:0] - FunctionDeclaration[0:0->3:0] - Type[0:0->0:2] - int - main - ( - ) - FunctionDefinition[1:0->3:0] - { - ReturnStatement[2:1->2:9] - NumericLiteral[2:8->2:8] - 1 - } diff --git a/Userland/Libraries/LibGLSL/Tests/parser/function-definition.glsl b/Userland/Libraries/LibGLSL/Tests/parser/function-definition.glsl deleted file mode 100644 index 89e00ff1cca..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/function-definition.glsl +++ /dev/null @@ -1,5 +0,0 @@ -int main() -{ - return 1; -} - diff --git a/Userland/Libraries/LibGLSL/Tests/parser/if-else.ast b/Userland/Libraries/LibGLSL/Tests/parser/if-else.ast deleted file mode 100644 index b3b6cc9abfc..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/if-else.ast +++ /dev/null @@ -1,26 +0,0 @@ -TranslationUnit[0:0->6:0] - FunctionDeclaration[0:0->6:0] - Type[0:0->0:3] - bool - foo - ( - ) - FunctionDefinition[1:0->6:0] - { - IfStatement[2:4->5:20] - Predicate: - BinaryExpression[2:8->2:14] - NumericLiteral[2:8->2:8] - 1 - == - NumericLiteral[2:13->2:13] - 2 - Then: - ReturnStatement[3:8->3:19] - BooleanLiteral[3:15->3:18] - true - Else: - ReturnStatement[5:8->5:20] - BooleanLiteral[5:15->5:19] - false - } diff --git a/Userland/Libraries/LibGLSL/Tests/parser/if-else.glsl b/Userland/Libraries/LibGLSL/Tests/parser/if-else.glsl deleted file mode 100644 index 17daeeeef75..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/if-else.glsl +++ /dev/null @@ -1,8 +0,0 @@ -bool foo() -{ - if (1 == 2) - return true; - else - return false; -} - diff --git a/Userland/Libraries/LibGLSL/Tests/parser/return.ast b/Userland/Libraries/LibGLSL/Tests/parser/return.ast deleted file mode 100644 index 03b525274dc..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/return.ast +++ /dev/null @@ -1,23 +0,0 @@ -TranslationUnit[0:0->8:0] - FunctionDeclaration[0:0->3:0] - Type[0:0->0:3] - void - foo - ( - ) - FunctionDefinition[1:0->3:0] - { - ReturnStatement[2:4->2:10] - } - FunctionDeclaration[5:0->8:0] - Type[5:0->5:2] - int - bar - ( - ) - FunctionDefinition[6:0->8:0] - { - ReturnStatement[7:4->7:12] - NumericLiteral[7:11->7:11] - 3 - } diff --git a/Userland/Libraries/LibGLSL/Tests/parser/return.glsl b/Userland/Libraries/LibGLSL/Tests/parser/return.glsl deleted file mode 100644 index 6ce3d51f0f1..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/return.glsl +++ /dev/null @@ -1,10 +0,0 @@ -void foo() -{ - return; -} - -int bar() -{ - return 3; -} - diff --git a/Userland/Libraries/LibGLSL/Tests/parser/struct.ast b/Userland/Libraries/LibGLSL/Tests/parser/struct.ast deleted file mode 100644 index dccb9c19f76..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/struct.ast +++ /dev/null @@ -1,7 +0,0 @@ -TranslationUnit[0:0->3:1] - StructDeclaration[0:7->3:1] - foo - VariableDeclaration[2:4->3:0] - Type[2:4->2:6] - int - bar diff --git a/Userland/Libraries/LibGLSL/Tests/parser/struct.glsl b/Userland/Libraries/LibGLSL/Tests/parser/struct.glsl deleted file mode 100644 index b2bd8f21fac..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/struct.glsl +++ /dev/null @@ -1,5 +0,0 @@ -struct foo -{ - int bar; -}; - diff --git a/Userland/Libraries/LibGLSL/Tests/parser/unary-expression.ast b/Userland/Libraries/LibGLSL/Tests/parser/unary-expression.ast deleted file mode 100644 index 9b15b206311..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/unary-expression.ast +++ /dev/null @@ -1,32 +0,0 @@ -TranslationUnit[0:0->4:0] - FunctionDeclaration[0:0->4:0] - Type[0:0->0:3] - void - foo - ( - ) - FunctionDefinition[1:0->4:0] - { - VariableDeclaration[2:4->2:13] - Type[2:4->2:6] - int - a - NumericLiteral[2:12->2:12] - 7 - VariableDeclaration[3:4->3:22] - Type[3:4->3:6] - int - b - UnaryExpression[3:12->3:22] - prefix ~ - UnaryExpression[3:14->3:21] - prefix ! - UnaryExpression[3:15->3:21] - prefix ~ - UnaryExpression[3:16->3:21] - prefix ++ - UnaryExpression[3:18->3:21] - postfix ++ - Name[3:18->3:18] - a - } diff --git a/Userland/Libraries/LibGLSL/Tests/parser/unary-expression.glsl b/Userland/Libraries/LibGLSL/Tests/parser/unary-expression.glsl deleted file mode 100644 index a6029f62356..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/unary-expression.glsl +++ /dev/null @@ -1,6 +0,0 @@ -void foo() -{ - int a = 7; - int b = ~(!~++a++); -} - diff --git a/Userland/Libraries/LibGLSL/Tests/parser/variable-declaration.ast b/Userland/Libraries/LibGLSL/Tests/parser/variable-declaration.ast deleted file mode 100644 index 1bc106a3b04..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/variable-declaration.ast +++ /dev/null @@ -1,13 +0,0 @@ -TranslationUnit[0:0->2:16] - VariableDeclaration[0:0->1:0] - Type[0:0->0:11] - uniform vec3 - u_Color - VariableDeclaration[1:0->2:0] - Type[1:0->1:6] - in vec3 - i_VertexColor - VariableDeclaration[2:0->2:16] - Type[2:0->2:7] - out vec4 - o_Color diff --git a/Userland/Libraries/LibGLSL/Tests/parser/variable-declaration.glsl b/Userland/Libraries/LibGLSL/Tests/parser/variable-declaration.glsl deleted file mode 100644 index 74c57103564..00000000000 --- a/Userland/Libraries/LibGLSL/Tests/parser/variable-declaration.glsl +++ /dev/null @@ -1,4 +0,0 @@ -uniform vec3 u_Color; -in vec3 i_VertexColor; -out vec4 o_Color; - diff --git a/Userland/Libraries/LibGLSL/Token.cpp b/Userland/Libraries/LibGLSL/Token.cpp deleted file mode 100644 index fe5d31ad699..00000000000 --- a/Userland/Libraries/LibGLSL/Token.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2023, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Token.h" -#include - -namespace GLSL { - -bool Position::operator<(Position const& other) const -{ - return line < other.line || (line == other.line && column < other.column); -} - -bool Position::operator>(Position const& other) const -{ - return !(*this < other) && !(*this == other); -} - -bool Position::operator==(Position const& other) const -{ - return line == other.line && column == other.column; -} - -bool Position::operator<=(Position const& other) const -{ - return !(*this > other); -} - -ErrorOr Token::to_string() const -{ - return String::formatted("{} {}:{}-{}:{} ({})", type_to_string(m_type), start().line, start().column, end().line, end().column, text()); -} - -ErrorOr Token::type_as_string() const -{ - auto str = type_to_string(m_type); - auto view = StringView(str, strlen(str)); - return String::from_utf8(view); -} - -} diff --git a/Userland/Libraries/LibGLSL/Token.h b/Userland/Libraries/LibGLSL/Token.h deleted file mode 100644 index b0ca01d2ec4..00000000000 --- a/Userland/Libraries/LibGLSL/Token.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2023, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace GLSL { - -#define FOR_EACH_TOKEN_TYPE \ - __TOKEN(Unknown) \ - __TOKEN(Whitespace) \ - __TOKEN(PreprocessorStatement) \ - __TOKEN(IncludeStatement) \ - __TOKEN(IncludePath) \ - __TOKEN(LeftParen) \ - __TOKEN(RightParen) \ - __TOKEN(LeftCurly) \ - __TOKEN(RightCurly) \ - __TOKEN(LeftBracket) \ - __TOKEN(RightBracket) \ - __TOKEN(Less) \ - __TOKEN(Greater) \ - __TOKEN(LessEquals) \ - __TOKEN(GreaterEquals) \ - __TOKEN(LessLess) \ - __TOKEN(GreaterGreater) \ - __TOKEN(LessLessEquals) \ - __TOKEN(GreaterGreaterEquals) \ - __TOKEN(Comma) \ - __TOKEN(Plus) \ - __TOKEN(PlusPlus) \ - __TOKEN(PlusEquals) \ - __TOKEN(Minus) \ - __TOKEN(MinusMinus) \ - __TOKEN(MinusEquals) \ - __TOKEN(Asterisk) \ - __TOKEN(AsteriskEquals) \ - __TOKEN(Slash) \ - __TOKEN(SlashEquals) \ - __TOKEN(Percent) \ - __TOKEN(PercentEquals) \ - __TOKEN(Caret) \ - __TOKEN(CaretCaret) \ - __TOKEN(CaretEquals) \ - __TOKEN(ExclamationMark) \ - __TOKEN(ExclamationMarkEquals) \ - __TOKEN(Equals) \ - __TOKEN(EqualsEquals) \ - __TOKEN(And) \ - __TOKEN(AndAnd) \ - __TOKEN(AndEquals) \ - __TOKEN(Pipe) \ - __TOKEN(PipePipe) \ - __TOKEN(PipeEquals) \ - __TOKEN(Tilde) \ - __TOKEN(QuestionMark) \ - __TOKEN(Colon) \ - __TOKEN(Semicolon) \ - __TOKEN(Dot) \ - __TOKEN(DoubleQuotedString) \ - __TOKEN(SingleQuotedString) \ - __TOKEN(RawString) \ - __TOKEN(EscapeSequence) \ - __TOKEN(Integer) \ - __TOKEN(Float) \ - __TOKEN(Keyword) \ - __TOKEN(KnownType) \ - __TOKEN(Identifier) \ - __TOKEN(EOF_TOKEN) - -struct Position { - size_t line { 0 }; - size_t column { 0 }; - - bool operator<(Position const&) const; - bool operator<=(Position const&) const; - bool operator>(Position const&) const; - bool operator==(Position const&) const; -}; - -struct Token { - enum class Type { -#define __TOKEN(x) x, - FOR_EACH_TOKEN_TYPE -#undef __TOKEN - }; - - Token(Type type, Position const& start, Position const& end, StringView text) - : m_type(type) - , m_start(start) - , m_end(end) - , m_text(text) - { - } - - static char const* type_to_string(Type t) - { - switch (t) { -#define __TOKEN(x) \ - case Type::x: \ - return #x; - FOR_EACH_TOKEN_TYPE -#undef __TOKEN - } - VERIFY_NOT_REACHED(); - } - - ErrorOr to_string() const; - ErrorOr type_as_string() const; - - Position const& start() const { return m_start; } - Position const& end() const { return m_end; } - - void set_start(Position const& other) { m_start = other; } - void set_end(Position const& other) { m_end = other; } - Type type() const { return m_type; } - StringView text() const { return m_text; } - -private: - Type m_type { Type::Unknown }; - Position m_start; - Position m_end; - StringView m_text; -}; - -} - -#undef FOR_EACH_TOKEN_TYPE diff --git a/Userland/Libraries/LibGPU/CMakeLists.txt b/Userland/Libraries/LibGPU/CMakeLists.txt deleted file mode 100644 index 352154434dd..00000000000 --- a/Userland/Libraries/LibGPU/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -set(SOURCES - Driver.cpp - Image.cpp -) - -serenity_lib(LibGPU gpu) -target_link_libraries(LibGPU PRIVATE ${CMAKE_DL_LIBS}) - -add_dependencies(LibGPU LibSoftGPU) - -if (SERENITYOS) - add_dependencies(LibGPU LibVirtGPU) -endif() diff --git a/Userland/Libraries/LibGPU/Config.h b/Userland/Libraries/LibGPU/Config.h deleted file mode 100644 index 30bebd41a1f..00000000000 --- a/Userland/Libraries/LibGPU/Config.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace GPU { - -// FIXME: These 3 types were originally introduced in LibSoftGPU and are currently needed by the device interface. -// Once we refactor the interface these should move back into LibSoftGPU. -using ColorType = u32; // BGRA:8888 -using DepthType = float; -using StencilType = u8; - -// FIXME: This constant was originally introduced in LibSoftGPU and is currently used in the Vertex struct. -// Once we refactor the interface this should move back into LibSoftGPU. -static constexpr int NUM_TEXTURE_UNITS = 2; - -} diff --git a/Userland/Libraries/LibGPU/Device.h b/Userland/Libraries/LibGPU/Device.h deleted file mode 100644 index ae70cd36048..00000000000 --- a/Userland/Libraries/LibGPU/Device.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace GPU { - -class Device { -public: - virtual ~Device() = default; - - virtual DeviceInfo info() const = 0; - - virtual void draw_primitives(PrimitiveType, Vector& vertices) = 0; - virtual void resize(Gfx::IntSize min_size) = 0; - virtual void clear_color(FloatVector4 const&) = 0; - virtual void clear_depth(DepthType) = 0; - virtual void clear_stencil(StencilType) = 0; - virtual void blit_from_color_buffer(Gfx::Bitmap& target) = 0; - virtual void blit_from_color_buffer(NonnullRefPtr, u32 level, Vector2 input_size, Vector2 input_offset, Vector3 output_offset) = 0; - virtual void blit_from_color_buffer(void*, Vector2 offset, GPU::ImageDataLayout const&) = 0; - virtual void blit_from_depth_buffer(void*, Vector2 offset, GPU::ImageDataLayout const&) = 0; - virtual void blit_from_depth_buffer(NonnullRefPtr, u32 level, Vector2 input_size, Vector2 input_offset, Vector3 output_offset) = 0; - virtual void blit_to_color_buffer_at_raster_position(void const*, GPU::ImageDataLayout const&) = 0; - virtual void blit_to_depth_buffer_at_raster_position(void const*, GPU::ImageDataLayout const&) = 0; - virtual void set_options(RasterizerOptions const&) = 0; - virtual void set_light_model_params(LightModelParameters const&) = 0; - virtual RasterizerOptions options() const = 0; - virtual LightModelParameters light_model() const = 0; - - virtual NonnullRefPtr create_image(PixelFormat const&, u32 width, u32 height, u32 depth, u32 max_levels) = 0; - virtual ErrorOr> create_shader(IR::Shader const&) = 0; - - virtual void set_model_view_transform(FloatMatrix4x4 const&) = 0; - virtual void set_projection_transform(FloatMatrix4x4 const&) = 0; - virtual void set_sampler_config(unsigned, SamplerConfig const&) = 0; - virtual void set_light_state(unsigned, Light const&) = 0; - virtual void set_material_state(Face, Material const&) = 0; - virtual void set_stencil_configuration(Face, StencilConfiguration const&) = 0; - virtual void set_texture_unit_configuration(TextureUnitIndex, TextureUnitConfiguration const&) = 0; - virtual void set_clip_planes(Vector const&) = 0; - - virtual RasterPosition raster_position() const = 0; - virtual void set_raster_position(RasterPosition const& raster_position) = 0; - virtual void set_raster_position(FloatVector4 const& position) = 0; - - virtual void bind_fragment_shader(RefPtr) = 0; -}; - -} - -typedef GPU::Device* (*serenity_gpu_create_device_t)(Gfx::IntSize size); - -extern "C" GPU::Device* serenity_gpu_create_device(Gfx::IntSize size); diff --git a/Userland/Libraries/LibGPU/DeviceInfo.h b/Userland/Libraries/LibGPU/DeviceInfo.h deleted file mode 100644 index c5d23ce6a63..00000000000 --- a/Userland/Libraries/LibGPU/DeviceInfo.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2021, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace GPU { - -struct DeviceInfo final { - ByteString vendor_name; - ByteString device_name; - unsigned num_texture_units; - unsigned num_lights; - unsigned max_clip_planes; - unsigned max_texture_size; - float max_texture_lod_bias; - u8 stencil_bits; - bool supports_npot_textures; - bool supports_texture_clamp_to_edge; - bool supports_texture_env_add; -}; - -} diff --git a/Userland/Libraries/LibGPU/Driver.cpp b/Userland/Libraries/LibGPU/Driver.cpp deleted file mode 100644 index ad2bf9cdba9..00000000000 --- a/Userland/Libraries/LibGPU/Driver.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * Copyright (c) 2023, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -namespace GPU { - -// FIXME: Think of a better way to configure these paths. Maybe use ConfigServer? -static HashMap const s_driver_path_map { -#if defined(AK_OS_SERENITY) - { "softgpu"sv, "libsoftgpu.so.serenity" }, - { "virtgpu"sv, "libvirtgpu.so.serenity" }, -#elif defined(AK_OS_MACOS) - { "softgpu"sv, "liblagom-softgpu.dylib" }, -#else - { "softgpu"sv, "liblagom-softgpu.so.0" }, -#endif -}; - -static HashMap> s_loaded_drivers; - -ErrorOr> Driver::try_create(StringView driver_name) -{ - // Check if the library for this driver is already loaded - auto already_loaded_driver = s_loaded_drivers.find(driver_name); - if (already_loaded_driver != s_loaded_drivers.end() && !already_loaded_driver->value.is_null()) - return *already_loaded_driver->value; - - // Nope, we need to load the library - auto it = s_driver_path_map.find(driver_name); - if (it == s_driver_path_map.end()) - return Error::from_string_literal("The requested GPU driver was not found in the list of allowed driver libraries"); - - auto lib = dlopen(it->value, RTLD_NOW); - if (!lib) - return Error::from_string_literal("The library for the requested GPU driver could not be opened"); - - auto serenity_gpu_create_device = reinterpret_cast(dlsym(lib, "serenity_gpu_create_device")); - if (!serenity_gpu_create_device) { - dlclose(lib); - return Error::from_string_literal("The library for the requested GPU driver does not contain serenity_gpu_create_device()"); - } - - auto driver = adopt_ref(*new Driver(lib, serenity_gpu_create_device)); - - s_loaded_drivers.set(driver_name, driver->make_weak_ptr()); - - return driver; -} - -Driver::~Driver() -{ - dlclose(m_dlopen_result); -} - -ErrorOr> Driver::try_create_device(Gfx::IntSize size) -{ - auto device_or_null = m_serenity_gpu_create_device(size); - if (!device_or_null) - return Error::from_string_literal("Could not create GPU device"); - - return adopt_own(*device_or_null); -} - -} diff --git a/Userland/Libraries/LibGPU/Driver.h b/Userland/Libraries/LibGPU/Driver.h deleted file mode 100644 index c2197e167a5..00000000000 --- a/Userland/Libraries/LibGPU/Driver.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace GPU { - -class Driver final - : public RefCounted - , public Weakable { -public: - static ErrorOr> try_create(StringView driver_name); - ~Driver(); - - ErrorOr> try_create_device(Gfx::IntSize size); - -private: - Driver(void* dlopen_result, serenity_gpu_create_device_t device_creation_function) - : m_dlopen_result { dlopen_result } - , m_serenity_gpu_create_device { device_creation_function } - { - VERIFY(dlopen_result); - VERIFY(device_creation_function); - } - - void* const m_dlopen_result { nullptr }; - serenity_gpu_create_device_t m_serenity_gpu_create_device { nullptr }; -}; - -} diff --git a/Userland/Libraries/LibGPU/Enums.h b/Userland/Libraries/LibGPU/Enums.h deleted file mode 100644 index f6d131cab6d..00000000000 --- a/Userland/Libraries/LibGPU/Enums.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2024, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace GPU { - -enum class AlphaTestFunction { - Never, - Always, - Less, - LessOrEqual, - Equal, - NotEqual, - GreaterOrEqual, - Greater, -}; - -enum class BlendEquation { - Add, - Subtract, - ReverseSubtract, - Min, - Max, -}; - -enum class BlendFactor { - Zero, - One, - SrcColor, - OneMinusSrcColor, - DstColor, - OneMinusDstColor, - SrcAlpha, - OneMinusSrcAlpha, - DstAlpha, - OneMinusDstAlpha, - ConstantColor, - OneMinusConstantColor, - ConstantAlpha, - OneMinusConstantAlpha, - SrcAlphaSaturate, -}; - -enum class ColorControl { - SingleColor, - SeparateSpecularColor, -}; - -enum class ColorMaterialFace { - Front, - Back, - FrontAndBack, -}; - -enum class ColorMaterialMode { - Ambient, - AmbientAndDiffuse, - Diffuse, - Emissive, - Specular, -}; - -enum class DepthTestFunction { - Never, - Always, - Less, - LessOrEqual, - Equal, - NotEqual, - GreaterOrEqual, - Greater, -}; - -enum Face { - Front = 0, - Back = 1, -}; - -enum FogMode { - Linear, - Exp, - Exp2 -}; - -enum class PolygonMode { - Point, - Line, - Fill, -}; - -enum class WindingOrder { - Clockwise, - CounterClockwise, -}; - -enum class PrimitiveType { - Lines, - LineLoop, - LineStrip, - Points, - TriangleFan, - Triangles, - TriangleStrip, - Quads, -}; - -enum StencilOperation { - Decrement, - DecrementWrap, - Increment, - IncrementWrap, - Invert, - Keep, - Replace, - Zero, -}; - -enum StencilTestFunction { - Always, - Equal, - Greater, - GreaterOrEqual, - Less, - LessOrEqual, - Never, - NotEqual, -}; - -enum TexCoordGenerationCoordinate : u8 { - None = 0x0, - S = 0x1, - T = 0x2, - R = 0x4, - Q = 0x8, - All = 0xF, -}; - -enum class TexCoordGenerationMode { - ObjectLinear, - EyeLinear, - SphereMap, - ReflectionMap, - NormalMap, -}; - -} diff --git a/Userland/Libraries/LibGPU/IR.h b/Userland/Libraries/LibGPU/IR.h deleted file mode 100644 index c983ce50684..00000000000 --- a/Userland/Libraries/LibGPU/IR.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace GPU::IR { - -enum class Opcode { - Move, -}; - -enum class StorageLocation { - Constant, - Uniform, - Input, - Output, - Temporary, -}; - -enum class StorageType { - Float, - Vector2, - Vector3, - Vector4, - Matrix3x3, - Matrix4x4, -}; - -struct StorageReference final { - StorageLocation location; - size_t index; -}; - -struct Instruction final { - Opcode operation; - Vector arguments; - StorageReference result; -}; - -struct Constant final { - StorageType type; - union { - float float_values[16]; - }; -}; - -struct Uniform final { - String name; - StorageType type; -}; - -struct Input final { - String name; - StorageType type; -}; - -struct Output final { - String name; - StorageType type; -}; - -struct Temporary final { - StorageType type; -}; - -struct Shader final { - Vector constants; - Vector uniforms; - Vector inputs; - Vector outputs; - Vector temporaries; - Vector instructions; -}; - -} diff --git a/Userland/Libraries/LibGPU/Image.cpp b/Userland/Libraries/LibGPU/Image.cpp deleted file mode 100644 index eab7f30efa1..00000000000 --- a/Userland/Libraries/LibGPU/Image.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace GPU { - -Image::Image(void const* ownership_token, GPU::PixelFormat const& pixel_format, u32 width, u32 height, u32 depth, u32 max_levels) - : m_ownership_token { ownership_token } - , m_pixel_format { pixel_format } -{ - VERIFY(width > 0); - VERIFY(height > 0); - VERIFY(depth > 0); - VERIFY(max_levels > 0); - - u32 number_of_levels_in_full_chain = max(max(AK::log2(width), AK::log2(height)), AK::log2(depth)) + 1; - m_mipmap_sizes.resize(min(max_levels, number_of_levels_in_full_chain)); - - for (u32 level = 0; level < m_mipmap_sizes.size(); ++level) { - m_mipmap_sizes[level] = { width, height, depth }; - width = max(width / 2, 1); - height = max(height / 2, 1); - depth = max(depth / 2, 1); - } -} - -} diff --git a/Userland/Libraries/LibGPU/Image.h b/Userland/Libraries/LibGPU/Image.h deleted file mode 100644 index 25096990d3b..00000000000 --- a/Userland/Libraries/LibGPU/Image.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace GPU { - -class Image : public RefCounted { -public: - Image(void const* ownership_token, PixelFormat const&, u32 width, u32 height, u32 depth, u32 max_levels); - virtual ~Image() { } - - u32 width_at_level(u32 level) const { return m_mipmap_sizes[level].x(); } - u32 height_at_level(u32 level) const { return m_mipmap_sizes[level].y(); } - u32 depth_at_level(u32 level) const { return m_mipmap_sizes[level].z(); } - u32 number_of_levels() const { return m_mipmap_sizes.size(); } - - PixelFormat pixel_format() const { return m_pixel_format; } - - virtual void regenerate_mipmaps() = 0; - - virtual void write_texels(u32 level, Vector3 const& output_offset, void const* input_data, ImageDataLayout const&) = 0; - virtual void read_texels(u32 level, Vector3 const& input_offset, void* output_data, ImageDataLayout const&) const = 0; - virtual void copy_texels(Image const& source, u32 source_level, Vector3 const& source_offset, Vector3 const& size, u32 destination_level, Vector3 const& destination_offset) = 0; - - void const* ownership_token() const { return m_ownership_token; } - bool has_same_ownership_token(Image const& other) const { return other.ownership_token() == ownership_token(); } - -private: - void const* const m_ownership_token { nullptr }; - Vector> m_mipmap_sizes; - PixelFormat m_pixel_format; -}; - -} diff --git a/Userland/Libraries/LibGPU/ImageDataLayout.h b/Userland/Libraries/LibGPU/ImageDataLayout.h deleted file mode 100644 index 1a3604bef79..00000000000 --- a/Userland/Libraries/LibGPU/ImageDataLayout.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace GPU { - -// Order of bytes within a single component -enum class ComponentBytesOrder { - Normal, - Reversed, -}; - -struct PackingSpecification final { - u32 depth_stride { 0 }; - u32 row_stride { 0 }; - u8 byte_alignment { 1 }; - ComponentBytesOrder component_bytes_order { ComponentBytesOrder::Normal }; -}; - -// Full dimensions of the image -struct DimensionSpecification final { - u32 width; - u32 height; - u32 depth; -}; - -// Subselection (source or target) within the image -struct ImageSelection final { - i32 offset_x { 0 }; - i32 offset_y { 0 }; - i32 offset_z { 0 }; - u32 width; - u32 height; - u32 depth; -}; - -struct ImageDataLayout final { - PixelType pixel_type; - PackingSpecification packing {}; - DimensionSpecification dimensions; - ImageSelection selection; -}; - -} diff --git a/Userland/Libraries/LibGPU/ImageFormat.h b/Userland/Libraries/LibGPU/ImageFormat.h deleted file mode 100644 index 7dc85da9b79..00000000000 --- a/Userland/Libraries/LibGPU/ImageFormat.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace GPU { - -// The pixel data's representation -enum class PixelFormat { - Alpha, - BGR, - BGRA, - Blue, - ColorIndex, - DepthComponent, - Green, - Intensity, - Luminance, - LuminanceAlpha, - Red, - RGB, - RGBA, - StencilIndex, -}; - -// Bit width assigned to individual components within a single pixel's value -enum class PixelComponentBits { - AllBits, - B1_5_5_5, - B2_3_3, - B2_10_10_10, - B3_3_2, - B4_4_4_4, - B5_5_5_1, - B5_6_5, - B8_8_8_8, - B10_10_10_2, -}; - -// The base data type used as pixel storage -enum class PixelDataType { - Bitmap, - Byte, - Float, - HalfFloat, - Int, - Short, - UnsignedByte, - UnsignedInt, - UnsignedShort, -}; - -// Order of components within a single pixel -enum class ComponentsOrder { - Normal, - Reversed, -}; - -struct PixelType final { - PixelFormat format; - PixelComponentBits bits; - PixelDataType data_type; - ComponentsOrder components_order { ComponentsOrder::Normal }; -}; - -static constexpr int number_of_components(PixelFormat format) -{ - switch (format) { - case PixelFormat::Alpha: - case PixelFormat::Blue: - case PixelFormat::ColorIndex: - case PixelFormat::DepthComponent: - case PixelFormat::Green: - case PixelFormat::Intensity: - case PixelFormat::Luminance: - case PixelFormat::Red: - case PixelFormat::StencilIndex: - return 1; - case PixelFormat::LuminanceAlpha: - return 2; - case PixelFormat::BGR: - case PixelFormat::RGB: - return 3; - case PixelFormat::BGRA: - case PixelFormat::RGBA: - return 4; - } - VERIFY_NOT_REACHED(); -} - -static constexpr int number_of_components(PixelComponentBits bits) -{ - switch (bits) { - case PixelComponentBits::AllBits: - return 1; - case PixelComponentBits::B2_3_3: - case PixelComponentBits::B3_3_2: - case PixelComponentBits::B5_6_5: - return 3; - case PixelComponentBits::B1_5_5_5: - case PixelComponentBits::B2_10_10_10: - case PixelComponentBits::B4_4_4_4: - case PixelComponentBits::B5_5_5_1: - case PixelComponentBits::B8_8_8_8: - case PixelComponentBits::B10_10_10_2: - return 4; - } - VERIFY_NOT_REACHED(); -} - -static constexpr Array pixel_component_bitfield_lengths(PixelComponentBits bits) -{ - switch (bits) { - case PixelComponentBits::AllBits: - VERIFY_NOT_REACHED(); - case PixelComponentBits::B1_5_5_5: - return { 1, 5, 5, 5 }; - case PixelComponentBits::B2_3_3: - return { 2, 3, 3 }; - case PixelComponentBits::B2_10_10_10: - return { 2, 10, 10, 10 }; - case PixelComponentBits::B3_3_2: - return { 3, 3, 2 }; - case PixelComponentBits::B4_4_4_4: - return { 4, 4, 4, 4 }; - case PixelComponentBits::B5_5_5_1: - return { 5, 5, 5, 1 }; - case PixelComponentBits::B5_6_5: - return { 5, 6, 5 }; - case PixelComponentBits::B8_8_8_8: - return { 8, 8, 8, 8 }; - case PixelComponentBits::B10_10_10_2: - return { 10, 10, 10, 2 }; - } - VERIFY_NOT_REACHED(); -} - -static constexpr size_t pixel_data_type_size_in_bytes(PixelDataType data_type) -{ - switch (data_type) { - case PixelDataType::Bitmap: - return sizeof(u8); - case PixelDataType::Byte: - return sizeof(u8); - case PixelDataType::Float: - return sizeof(float); - case PixelDataType::HalfFloat: - return sizeof(float) / 2; - case PixelDataType::Int: - return sizeof(i32); - case PixelDataType::Short: - return sizeof(i16); - case PixelDataType::UnsignedByte: - return sizeof(u8); - case PixelDataType::UnsignedInt: - return sizeof(u32); - case PixelDataType::UnsignedShort: - return sizeof(u16); - } - VERIFY_NOT_REACHED(); -} - -static constexpr u8 pixel_size_in_bytes(PixelType pixel_type) -{ - auto component_size_in_bytes = pixel_data_type_size_in_bytes(pixel_type.data_type); - if (pixel_type.bits == PixelComponentBits::AllBits) - return component_size_in_bytes * number_of_components(pixel_type.format); - return component_size_in_bytes; -} - -} diff --git a/Userland/Libraries/LibGPU/Light.h b/Userland/Libraries/LibGPU/Light.h deleted file mode 100644 index 83509b73c94..00000000000 --- a/Userland/Libraries/LibGPU/Light.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2022, Jesse Buhagiar - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace GPU { - -struct Light { - bool is_enabled { false }; - - // According to the OpenGL 1.5 specification, page 56, all of the parameters - // for the following data members (positions, colors, and reals) are all - // floating point. - Vector4 ambient_intensity { 0.0f, 0.0f, 0.0f, 1.0f }; - Vector4 diffuse_intensity { 0.0f, 0.0f, 0.0f, 1.0f }; - Vector4 specular_intensity { 0.0f, 0.0f, 0.0f, 1.0f }; - Vector4 position { 0.0f, 0.0f, 1.0f, 0.0f }; - Vector3 spotlight_direction { 0.0f, 0.0f, -1.0f }; - - float spotlight_exponent { 0.0f }; - float spotlight_cutoff_angle { 180.0f }; - float constant_attenuation { 1.0f }; // This is referred to `k0i` in the OpenGL spec - float linear_attenuation { 0.0f }; // This is referred to `k1i` in the OpenGL spec - float quadratic_attenuation { 0.0f }; // This is referred to `k2i` in the OpenGL spec -}; - -} diff --git a/Userland/Libraries/LibGPU/LightModelParameters.h b/Userland/Libraries/LibGPU/LightModelParameters.h deleted file mode 100644 index 344b9a2af14..00000000000 --- a/Userland/Libraries/LibGPU/LightModelParameters.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2022, Jesse Buhagiar - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace GPU { - -struct LightModelParameters { - FloatVector4 scene_ambient_color { 0.2f, 0.2f, 0.2f, 1.0f }; - bool viewer_at_infinity { false }; - GPU::ColorControl color_control { GPU::ColorControl::SingleColor }; - bool two_sided_lighting { false }; -}; - -} diff --git a/Userland/Libraries/LibGPU/Material.h b/Userland/Libraries/LibGPU/Material.h deleted file mode 100644 index d0c2dc07dbe..00000000000 --- a/Userland/Libraries/LibGPU/Material.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2022, Jesse Buhagiar - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace GPU { - -struct Material { - FloatVector4 ambient { 0.2f, 0.2f, 0.2f, 1.0f }; - FloatVector4 diffuse { 0.8f, 0.8f, 0.8f, 1.0f }; - FloatVector4 specular { 0.0f, 0.0f, 0.0f, 1.0f }; - FloatVector4 emissive { 0.0f, 0.0f, 0.0f, 1.0f }; - float shininess { 0.0f }; - float ambient_color_index { 0.0f }; - float diffuse_color_index { 1.0f }; - float specular_color_index { 1.0f }; -}; - -} diff --git a/Userland/Libraries/LibGPU/RasterPosition.h b/Userland/Libraries/LibGPU/RasterPosition.h deleted file mode 100644 index 6d2b11362e0..00000000000 --- a/Userland/Libraries/LibGPU/RasterPosition.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2022, Jelle Raaijmakers - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace GPU { - -struct RasterPosition { - FloatVector4 window_coordinates { 0.0f, 0.0f, 0.0f, 1.0f }; - float eye_coordinate_distance { 0.0f }; - bool valid { true }; - FloatVector4 color_rgba { 1.0f, 1.0f, 1.0f, 1.0f }; - float color_index { 1.0f }; - FloatVector4 texture_coordinates { 0.0f, 0.0f, 0.0f, 1.0f }; -}; - -} diff --git a/Userland/Libraries/LibGPU/RasterizerOptions.h b/Userland/Libraries/LibGPU/RasterizerOptions.h deleted file mode 100644 index a9e24f678b9..00000000000 --- a/Userland/Libraries/LibGPU/RasterizerOptions.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2021, Stephan Unverwerth - * Copyright (c) 2022-2024, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace GPU { - -struct RasterizerOptions { - bool shade_smooth { true }; - bool enable_stencil_test { false }; - bool enable_depth_test { false }; - bool enable_depth_write { true }; - bool enable_alpha_test { false }; - AlphaTestFunction alpha_test_func { AlphaTestFunction::Always }; - float alpha_test_ref_value { 0 }; - bool enable_blending { false }; - FloatVector4 blend_color { 0.f, 0.f, 0.f, 0.f }; - BlendEquation blend_equation_rgb { BlendEquation::Add }; - BlendEquation blend_equation_alpha { BlendEquation::Add }; - BlendFactor blend_source_factor { BlendFactor::One }; - BlendFactor blend_destination_factor { BlendFactor::One }; - u32 color_mask { 0xffffffff }; - float depth_min { 0.f }; - float depth_max { 1.f }; - DepthTestFunction depth_func { DepthTestFunction::Less }; - PolygonMode polygon_mode { PolygonMode::Fill }; - FloatVector4 fog_color { 0.0f, 0.0f, 0.0f, 0.0f }; - float fog_density { 1.0f }; - FogMode fog_mode { FogMode::Exp }; - bool fog_enabled { false }; - float fog_start { 0.0f }; - float fog_end { 1.0f }; - bool line_smooth { false }; - float line_width { 1.f }; - bool point_smooth { false }; - float point_size { 1.f }; - bool scissor_enabled { false }; - bool normalization_enabled { false }; - Gfx::IntRect scissor_box; - bool enable_color_write { true }; - float depth_offset_factor { 0 }; - float depth_offset_constant { 0 }; - bool depth_offset_enabled { false }; - bool enable_culling { false }; - WindingOrder front_face { WindingOrder::CounterClockwise }; - bool cull_back { true }; - bool cull_front { false }; - Gfx::IntRect viewport; - bool lighting_enabled { false }; - bool color_material_enabled { false }; - ColorMaterialFace color_material_face { ColorMaterialFace::FrontAndBack }; - ColorMaterialMode color_material_mode { ColorMaterialMode::AmbientAndDiffuse }; -}; - -} diff --git a/Userland/Libraries/LibGPU/SamplerConfig.h b/Userland/Libraries/LibGPU/SamplerConfig.h deleted file mode 100644 index d842a229ae0..00000000000 --- a/Userland/Libraries/LibGPU/SamplerConfig.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace GPU { - -enum class TextureFilter { - Nearest, - Linear, -}; - -enum class MipMapFilter { - None, - Nearest, - Linear, -}; - -enum class TextureWrapMode { - Repeat, - MirroredRepeat, - Clamp, - ClampToBorder, - ClampToEdge, -}; - -enum class TextureEnvMode { - Add, - Blend, - Combine, - Decal, - Modulate, - Replace, -}; - -enum class TextureCombinator { - Add, - AddSigned, - Dot3RGB, - Dot3RGBA, - Interpolate, - Modulate, - Replace, - Subtract, -}; - -enum class TextureOperand { - OneMinusSourceAlpha, - OneMinusSourceColor, - SourceAlpha, - SourceColor, -}; - -enum class TextureSource { - Constant, - Previous, - PrimaryColor, - Texture, - TextureStage, -}; - -struct FixedFunctionTextureEnvironment final { - TextureCombinator alpha_combinator { TextureCombinator::Modulate }; - Array alpha_operand { TextureOperand::SourceAlpha, TextureOperand::SourceAlpha, TextureOperand::SourceAlpha }; - float alpha_scale { 1.f }; - Array alpha_source { TextureSource::Texture, TextureSource::Previous, TextureSource::Constant }; - u8 alpha_source_texture_stage { 0 }; - FloatVector4 color { 0.f, 0.f, 0.f, 0.f }; - TextureEnvMode env_mode { TextureEnvMode::Modulate }; - TextureCombinator rgb_combinator { TextureCombinator::Modulate }; - Array rgb_operand { TextureOperand::SourceColor, TextureOperand::SourceColor, TextureOperand::SourceAlpha }; - float rgb_scale { 1.f }; - Array rgb_source { TextureSource::Texture, TextureSource::Previous, TextureSource::Constant }; - u8 rgb_source_texture_stage { 0 }; -}; - -struct SamplerConfig final { - RefPtr bound_image; - float level_of_detail_bias { 0.f }; - MipMapFilter mipmap_filter { MipMapFilter::Nearest }; - TextureFilter texture_mag_filter { TextureFilter::Linear }; - TextureFilter texture_min_filter { TextureFilter::Linear }; - TextureWrapMode texture_wrap_u { TextureWrapMode::Repeat }; - TextureWrapMode texture_wrap_v { TextureWrapMode::Repeat }; - TextureWrapMode texture_wrap_w { TextureWrapMode::Repeat }; - FloatVector4 border_color { 0.f, 0.f, 0.f, 1.f }; - FixedFunctionTextureEnvironment fixed_function_texture_environment {}; -}; - -} diff --git a/Userland/Libraries/LibGPU/Shader.h b/Userland/Libraries/LibGPU/Shader.h deleted file mode 100644 index c96a8d0dea9..00000000000 --- a/Userland/Libraries/LibGPU/Shader.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2022, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace GPU { - -class Shader : public RefCounted { -public: - Shader(void const* ownership_token) - : m_ownership_token { ownership_token } - { - } - - virtual ~Shader() = default; - - void const* ownership_token() const { return m_ownership_token; } - bool has_same_ownership_token(Shader const& other) const { return other.ownership_token() == ownership_token(); } - -private: - void const* const m_ownership_token { nullptr }; -}; - -} diff --git a/Userland/Libraries/LibGPU/StencilConfiguration.h b/Userland/Libraries/LibGPU/StencilConfiguration.h deleted file mode 100644 index b68b2d6ba12..00000000000 --- a/Userland/Libraries/LibGPU/StencilConfiguration.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace GPU { - -struct StencilConfiguration { - StencilTestFunction test_function; - StencilType reference_value; - StencilType test_mask; - - StencilOperation on_stencil_test_fail; - StencilOperation on_depth_test_fail; - StencilOperation on_pass; - StencilType write_mask; -}; - -} diff --git a/Userland/Libraries/LibGPU/TextureUnitConfiguration.h b/Userland/Libraries/LibGPU/TextureUnitConfiguration.h deleted file mode 100644 index 686dba5e5df..00000000000 --- a/Userland/Libraries/LibGPU/TextureUnitConfiguration.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2022, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace GPU { - -typedef u8 TextureUnitIndex; - -struct TexCoordGeneration { - bool enabled; - TexCoordGenerationMode mode; - FloatVector4 coefficients; -}; - -struct TextureUnitConfiguration { - bool enabled { false }; - FloatMatrix4x4 transformation_matrix { FloatMatrix4x4::identity() }; - u8 tex_coord_generation_enabled; - TexCoordGeneration tex_coord_generation[4]; -}; - -} diff --git a/Userland/Libraries/LibGPU/Vertex.h b/Userland/Libraries/LibGPU/Vertex.h deleted file mode 100644 index e11e1eebc66..00000000000 --- a/Userland/Libraries/LibGPU/Vertex.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2021, Jesse Buhagiar - * Copyright (c) 2021, Stephan Unverwerth - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace GPU { - -struct Vertex { - FloatVector4 position; - FloatVector4 eye_coordinates; - FloatVector4 clip_coordinates; - FloatVector4 window_coordinates; - FloatVector4 color; - Array tex_coords; - FloatVector3 normal; -}; - -} diff --git a/Userland/Libraries/LibGUI/AboutDialog.cpp b/Userland/Libraries/LibGUI/AboutDialog.cpp deleted file mode 100644 index 30cb85d9555..00000000000 --- a/Userland/Libraries/LibGUI/AboutDialog.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * Copyright (c) 2022, the SerenityOS developers. - * Copyright (c) 2023, Sam Atkins - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace GUI { - -NonnullRefPtr AboutDialog::create(String const& name, String version, RefPtr icon, Window* parent_window) -{ - auto dialog = adopt_ref(*new AboutDialog(name, version, icon, parent_window)); - dialog->set_title(ByteString::formatted("About {}", name)); - - auto widget = AboutDialogWidget::try_create().release_value_but_fixme_should_propagate_errors(); - dialog->set_main_widget(widget); - - auto icon_wrapper = widget->find_descendant_of_type_named("icon_wrapper"); - if (icon) { - icon_wrapper->set_visible(true); - auto icon_image = widget->find_descendant_of_type_named("icon"); - icon_image->set_bitmap(icon); - } else { - icon_wrapper->set_visible(false); - } - - widget->find_descendant_of_type_named("name")->set_text(name); - // If we are displaying a dialog for an application, insert 'SerenityOS' below the application name - widget->find_descendant_of_type_named("serenity_os")->set_visible(name != "SerenityOS"); - widget->find_descendant_of_type_named("version")->set_text(version); - - auto ok_button = widget->find_descendant_of_type_named("ok_button"); - ok_button->on_click = [dialog](auto) { - dialog->done(ExecResult::OK); - }; - - return dialog; -} - -AboutDialog::AboutDialog(String const& name, String version, RefPtr icon, Window* parent_window) - : Dialog(parent_window) - , m_name(name) - , m_version_string(move(version)) - , m_icon(move(icon)) -{ - resize(413, 204); - set_resizable(false); - - if (parent_window) - set_icon(parent_window->icon()); -} - -void AboutDialog::show(String name, String version, RefPtr icon, Window* parent_window, RefPtr window_icon) -{ - auto dialog = AboutDialog::create(move(name), move(version), move(icon), parent_window); - if (window_icon) - dialog->set_icon(window_icon); - dialog->exec(); -} - -} diff --git a/Userland/Libraries/LibGUI/AboutDialog.gml b/Userland/Libraries/LibGUI/AboutDialog.gml deleted file mode 100644 index 05417c7ab71..00000000000 --- a/Userland/Libraries/LibGUI/AboutDialog.gml +++ /dev/null @@ -1,83 +0,0 @@ -@GUI::AboutDialogWidget { - fill_with_background_color: true - layout: @GUI::VerticalBoxLayout { - spacing: 0 - } - - @GUI::ImageWidget { - name: "brand_banner" - bitmap: "/res/graphics/brand-banner.png" - } - - @GUI::Widget { - name: "content_container" - layout: @GUI::HorizontalBoxLayout {} - - @GUI::Widget { - name: "left_container" - fixed_width: 60 - layout: @GUI::VerticalBoxLayout { - margins: [12, 0, 0] - } - - @GUI::Widget { - name: "icon_wrapper" - fixed_size: [32, 48] - layout: @GUI::VerticalBoxLayout {} - - @GUI::ImageWidget { - name: "icon" - } - } - } - - @GUI::Widget { - name: "right_container" - layout: @GUI::VerticalBoxLayout { - margins: [12, 4, 4, 0] - } - - @GUI::Label { - name: "name" - text_alignment: "CenterLeft" - fixed_height: 14 - font_weight: "Bold" - } - - @GUI::Label { - name: "serenity_os" - text_alignment: "CenterLeft" - fixed_height: 14 - text: "SerenityOS" - } - - @GUI::Label { - name: "version" - text_alignment: "CenterLeft" - fixed_height: 14 - } - - @GUI::Label { - name: "copyright" - text_alignment: "CenterLeft" - fixed_height: 14 - text: "Copyright © the SerenityOS developers, 2018-2024" - } - - @GUI::Layout::Spacer {} - - @GUI::Widget { - name: "button_container" - fixed_height: 22 - layout: @GUI::HorizontalBoxLayout {} - - @GUI::Layout::Spacer {} - - @GUI::DialogButton { - name: "ok_button" - text: "OK" - } - } - } - } -} diff --git a/Userland/Libraries/LibGUI/AboutDialog.h b/Userland/Libraries/LibGUI/AboutDialog.h deleted file mode 100644 index 7e2336c987b..00000000000 --- a/Userland/Libraries/LibGUI/AboutDialog.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2018-2023, Andreas Kling - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace GUI { - -class AboutDialog final : public Dialog { - C_OBJECT_ABSTRACT(AboutDialog) -public: - [[nodiscard]] static NonnullRefPtr create(String const& name, String version, RefPtr icon = nullptr, Window* parent_window = nullptr); - virtual ~AboutDialog() override = default; - - static void show(String name, String version, RefPtr icon = nullptr, Window* parent_window = nullptr, RefPtr window_icon = nullptr); - -private: - AboutDialog(String const& name, String version, RefPtr icon = nullptr, Window* parent_window = nullptr); - - String m_name; - String m_version_string; - RefPtr m_icon; -}; -} diff --git a/Userland/Libraries/LibGUI/AboutDialogWidget.h b/Userland/Libraries/LibGUI/AboutDialogWidget.h deleted file mode 100644 index 527a96681ec..00000000000 --- a/Userland/Libraries/LibGUI/AboutDialogWidget.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2024, Aarushi Chauhan . - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace GUI { - -class AboutDialogWidget : public GUI::Widget { - C_OBJECT_ABSTRACT(AboutDialogWidget) -public: - static ErrorOr> try_create(); - virtual ~AboutDialogWidget() override = default; - -private: - AboutDialogWidget() = default; -}; - -} diff --git a/Userland/Libraries/LibGUI/AbstractButton.cpp b/Userland/Libraries/LibGUI/AbstractButton.cpp deleted file mode 100644 index 18b0c7d8d67..00000000000 --- a/Userland/Libraries/LibGUI/AbstractButton.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2018-2021, Andreas Kling - * Copyright (c) 2022, the SerenityOS developers. - * Copyright (c) 2022, networkException - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include - -namespace GUI { - -AbstractButton::AbstractButton(String text) -{ - set_text(move(text)); - - set_focus_policy(GUI::FocusPolicy::StrongFocus); - set_background_role(Gfx::ColorRole::Button); - set_foreground_role(Gfx::ColorRole::ButtonText); - - m_auto_repeat_timer = add(); - m_auto_repeat_timer->on_timeout = [this] { - click(); - }; - - REGISTER_STRING_PROPERTY("text", text, set_text); - REGISTER_BOOL_PROPERTY("checked", is_checked, set_checked); - REGISTER_BOOL_PROPERTY("checkable", is_checkable, set_checkable); - REGISTER_BOOL_PROPERTY("exclusive", is_exclusive, set_exclusive); -} - -void AbstractButton::set_text(String text) -{ - if (m_text == text) - return; - m_text = move(text); - update(); -} - -void AbstractButton::set_checked(bool checked, AllowCallback allow_callback) -{ - if (m_checked == checked) - return; - m_checked = checked; - - if (is_exclusive() && checked && parent_widget()) { - bool sibling_had_focus = false; - parent_widget()->for_each_child_of_type([&](auto& sibling) { - if (!sibling.is_exclusive()) - return IterationDecision::Continue; - if (window() && window()->focused_widget() == &sibling) - sibling_had_focus = true; - if (!sibling.is_checked()) - return IterationDecision::Continue; - sibling.m_checked = false; - sibling.update(); - if (sibling.on_checked) - sibling.on_checked(false); - return IterationDecision::Continue; - }); - m_checked = true; - if (sibling_had_focus) - set_focus(true); - } - - if (is_exclusive() && parent_widget()) { - // In a group of exclusive checkable buttons, only the currently checked button is focusable. - parent_widget()->for_each_child_of_type([&](auto& button) { - if (button.is_exclusive() && button.is_checkable()) - button.set_focus_policy(button.is_checked() ? GUI::FocusPolicy::StrongFocus : GUI::FocusPolicy::NoFocus); - return IterationDecision::Continue; - }); - } - - update(); - if (on_checked && allow_callback == AllowCallback::Yes) - on_checked(checked); -} - -void AbstractButton::set_checkable(bool checkable) -{ - if (m_checkable == checkable) - return; - m_checkable = checkable; - update(); -} - -void AbstractButton::mousemove_event(MouseEvent& event) -{ - bool is_over = rect().contains(event.position()); - m_hovered = is_over; - if (event.buttons() & m_pressed_mouse_button) { - bool being_pressed = is_over; - if (being_pressed != m_being_pressed) { - m_being_pressed = being_pressed; - if (m_auto_repeat_interval) { - if (!m_being_pressed) - m_auto_repeat_timer->stop(); - else - m_auto_repeat_timer->start(m_auto_repeat_interval); - } - update(); - } - } - Widget::mousemove_event(event); -} - -void AbstractButton::mousedown_event(MouseEvent& event) -{ - if (event.button() & m_allowed_mouse_buttons_for_pressing) { - m_being_pressed = true; - m_pressed_mouse_button = event.button(); - repaint(); - - if (m_auto_repeat_interval) { - click(); - m_auto_repeat_timer->start(m_auto_repeat_interval); - } - event.accept(); - } - Widget::mousedown_event(event); -} - -void AbstractButton::mouseup_event(MouseEvent& event) -{ - if (event.button() == m_pressed_mouse_button && m_being_pressed) { - bool was_auto_repeating = m_auto_repeat_timer->is_active(); - m_auto_repeat_timer->stop(); - m_was_being_pressed = m_being_pressed; - ScopeGuard update_was_being_pressed { [this] { m_was_being_pressed = m_being_pressed; } }; - m_being_pressed = false; - m_pressed_mouse_button = MouseButton::None; - if (!is_checkable() || is_checked()) - repaint(); - if (m_was_being_pressed && !was_auto_repeating) { - switch (event.button()) { - case MouseButton::Primary: - click(event.modifiers()); - break; - case MouseButton::Middle: - middle_mouse_click(event.modifiers()); - break; - default: - VERIFY_NOT_REACHED(); - } - } - } - Widget::mouseup_event(event); -} - -void AbstractButton::doubleclick_event(GUI::MouseEvent& event) -{ - double_click(event.modifiers()); - Widget::doubleclick_event(event); -} - -void AbstractButton::enter_event(Core::Event&) -{ - m_hovered = true; - update(); -} - -void AbstractButton::leave_event(Core::Event& event) -{ - m_hovered = false; - if (m_being_keyboard_pressed) - m_being_keyboard_pressed = m_being_pressed = false; - update(); - event.accept(); - Widget::leave_event(event); -} - -void AbstractButton::focusout_event(GUI::FocusEvent& event) -{ - if (m_being_keyboard_pressed) { - m_being_pressed = m_being_keyboard_pressed = false; - event.accept(); - update(); - } - Widget::focusout_event(event); -} - -void AbstractButton::keydown_event(KeyEvent& event) -{ - if (event.key() == KeyCode::Key_Return || event.key() == KeyCode::Key_Space) { - m_being_pressed = m_being_keyboard_pressed = true; - update(); - event.accept(); - return; - } else if (m_being_pressed && event.key() == KeyCode::Key_Escape) { - m_being_pressed = m_being_keyboard_pressed = false; - update(); - event.accept(); - return; - } - - // Arrow keys switch the currently checked option within an exclusive group of checkable buttons. - if (event.is_arrow_key() && !event.modifiers() && is_exclusive() && is_checkable() && parent_widget()) { - event.accept(); - Vector exclusive_siblings; - size_t this_index = 0; - parent_widget()->for_each_child_of_type([&](auto& sibling) { - if (&sibling == this) { - VERIFY(is_enabled()); - this_index = exclusive_siblings.size(); - } - if (sibling.is_exclusive() && sibling.is_checkable() && sibling.is_enabled()) - exclusive_siblings.append(sibling); - return IterationDecision::Continue; - }); - if (exclusive_siblings.size() <= 1) - return; - size_t new_checked_index; - if (event.key() == KeyCode::Key_Left || event.key() == KeyCode::Key_Up) - new_checked_index = this_index == 0 ? exclusive_siblings.size() - 1 : this_index - 1; - else - new_checked_index = this_index == exclusive_siblings.size() - 1 ? 0 : this_index + 1; - exclusive_siblings[new_checked_index].click(); - return; - } - Widget::keydown_event(event); -} - -void AbstractButton::keyup_event(KeyEvent& event) -{ - bool was_being_pressed = m_being_pressed; - if (was_being_pressed && (event.key() == KeyCode::Key_Return || event.key() == KeyCode::Key_Space)) { - m_being_pressed = m_being_keyboard_pressed = false; - click(event.modifiers()); - update(); - event.accept(); - return; - } - Widget::keyup_event(event); -} - -void AbstractButton::paint_text(Painter& painter, Gfx::IntRect const& rect, Gfx::Font const& font, Gfx::TextAlignment text_alignment, Gfx::TextWrapping text_wrapping) -{ - auto clipped_rect = rect.intersected(this->rect()); - - if (!is_enabled()) { - painter.draw_text(clipped_rect.translated(1, 1), text(), font, text_alignment, palette().disabled_text_back(), Gfx::TextElision::Right, text_wrapping); - painter.draw_text(clipped_rect, text(), font, text_alignment, palette().disabled_text_front(), Gfx::TextElision::Right, text_wrapping); - return; - } - - if (text().is_empty()) - return; - painter.draw_text(clipped_rect, text(), font, text_alignment, palette().color(foreground_role()), Gfx::TextElision::Right, text_wrapping); -} - -void AbstractButton::change_event(Event& event) -{ - if (event.type() == Event::Type::EnabledChange) { - if (m_auto_repeat_timer->is_active()) - m_auto_repeat_timer->stop(); - if (!is_enabled()) { - bool was_being_pressed = m_being_pressed; - m_being_pressed = false; - if (was_being_pressed) - update(); - } - } - Widget::change_event(event); -} - -} diff --git a/Userland/Libraries/LibGUI/AbstractButton.h b/Userland/Libraries/LibGUI/AbstractButton.h deleted file mode 100644 index 65acce8894a..00000000000 --- a/Userland/Libraries/LibGUI/AbstractButton.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace GUI { - -class AbstractButton : public Widget { - C_OBJECT_ABSTRACT(AbstractButton); - -public: - virtual ~AbstractButton() override = default; - - Function on_checked; - - virtual void set_text(String); - String const& text() const { return m_text; } - - bool is_exclusive() const { return m_exclusive; } - void set_exclusive(bool b) { m_exclusive = b; } - - bool is_checked() const { return m_checked; } - void set_checked(bool, AllowCallback = AllowCallback::Yes); - - bool is_checkable() const { return m_checkable; } - void set_checkable(bool); - - bool is_hovered() const { return m_hovered; } - bool is_being_pressed() const { return m_being_pressed; } - bool was_being_pressed() const { return m_was_being_pressed; } - - unsigned allowed_mouse_buttons_for_pressing() const { return m_allowed_mouse_buttons_for_pressing; } - void set_allowed_mouse_buttons_for_pressing(unsigned allowed_buttons) { m_allowed_mouse_buttons_for_pressing = allowed_buttons; } - - virtual void click(unsigned modifiers = 0) = 0; - virtual void double_click(unsigned) { } - virtual void middle_mouse_click(unsigned) { } - virtual bool is_uncheckable() const { return true; } - - int auto_repeat_interval() const { return m_auto_repeat_interval; } - void set_auto_repeat_interval(int interval) { m_auto_repeat_interval = interval; } - -protected: - explicit AbstractButton(String = {}); - - virtual void mousedown_event(MouseEvent&) override; - virtual void mousemove_event(MouseEvent&) override; - virtual void mouseup_event(MouseEvent&) override; - virtual void doubleclick_event(GUI::MouseEvent&) override; - virtual void keydown_event(KeyEvent&) override; - virtual void keyup_event(KeyEvent&) override; - virtual void enter_event(Core::Event&) override; - virtual void leave_event(Core::Event&) override; - virtual void focusout_event(GUI::FocusEvent&) override; - virtual void change_event(Event&) override; - - void paint_text(Painter&, Gfx::IntRect const&, Gfx::Font const&, Gfx::TextAlignment, Gfx::TextWrapping = Gfx::TextWrapping::DontWrap); - -private: - String m_text; - bool m_checked { false }; - bool m_checkable { false }; - bool m_hovered { false }; - bool m_being_pressed { false }; - bool m_was_being_pressed { false }; - bool m_being_keyboard_pressed { false }; - bool m_exclusive { false }; - - MouseButton m_pressed_mouse_button { MouseButton::None }; - unsigned m_allowed_mouse_buttons_for_pressing { MouseButton::Primary }; - - int m_auto_repeat_interval { 0 }; - RefPtr m_auto_repeat_timer; -}; - -} diff --git a/Userland/Libraries/LibGUI/AbstractScrollableWidget.cpp b/Userland/Libraries/LibGUI/AbstractScrollableWidget.cpp deleted file mode 100644 index 13c95de2514..00000000000 --- a/Userland/Libraries/LibGUI/AbstractScrollableWidget.cpp +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (c) 2018-2021, Andreas Kling - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace GUI { - -AbstractScrollableWidget::AbstractScrollableWidget() -{ - REGISTER_READONLY_SIZE_PROPERTY("min_content_size", min_content_size); - - m_vertical_scrollbar = add(*this, Orientation::Vertical); - m_vertical_scrollbar->set_step(4); - m_vertical_scrollbar->on_change = [this](int) { - did_scroll(); - update(); - }; - - m_horizontal_scrollbar = add(*this, Orientation::Horizontal); - m_horizontal_scrollbar->set_step(4); - m_horizontal_scrollbar->set_page_step(30); - m_horizontal_scrollbar->on_change = [this](int) { - did_scroll(); - update(); - }; - - m_corner_widget = add(); - m_corner_widget->set_fill_with_background_color(true); - - m_automatic_scrolling_timer = add(); - m_automatic_scrolling_timer->set_interval(50); - m_automatic_scrolling_timer->on_timeout = [this] { - automatic_scrolling_timer_did_fire(); - }; -} - -void AbstractScrollableWidget::set_banner_widget(Widget* widget) -{ - if (m_banner_widget == widget) - return; - if (m_banner_widget) - remove_child(*m_banner_widget); - if (!widget) - return; - - m_banner_widget = widget; - add_child(*m_banner_widget); -} - -void AbstractScrollableWidget::handle_wheel_event(MouseEvent& event, Widget& event_source) -{ - if (!m_scrollbars_enabled) { - event.ignore(); - return; - } - - int wheel_delta_x { 0 }; - bool vertical_scroll_hijacked { false }; - - if (event.shift() || &event_source == m_horizontal_scrollbar.ptr()) { - wheel_delta_x = event.wheel_delta_y(); - vertical_scroll_hijacked = true; - } - - if (event.wheel_delta_x() != 0) { - wheel_delta_x = event.wheel_delta_x(); - } - - if (wheel_delta_x != 0) { - // FIXME: The wheel delta multiplier should probably come from... somewhere? - horizontal_scrollbar().increase_slider_by(wheel_delta_x * 60); - } - - if (!vertical_scroll_hijacked && event.wheel_delta_y() != 0) { - vertical_scrollbar().increase_slider_by(event.wheel_delta_y() * 20); - } -} - -void AbstractScrollableWidget::mousewheel_event(MouseEvent& event) -{ - handle_wheel_event(event, *this); -} - -void AbstractScrollableWidget::custom_layout() -{ - auto inner_rect = frame_inner_rect_for_size(size()); - int height_wanted_by_banner_widget = m_banner_widget && m_banner_widget->is_visible() ? m_banner_widget->effective_min_size().height().as_int() : 0; - int height_wanted_by_horizontal_scrollbar = m_horizontal_scrollbar->is_visible() ? m_horizontal_scrollbar->effective_min_size().height().as_int() : 0; - int width_wanted_by_vertical_scrollbar = m_vertical_scrollbar->is_visible() ? m_vertical_scrollbar->effective_min_size().width().as_int() : 0; - - if (m_banner_widget && m_banner_widget->is_visible()) { - m_banner_widget->set_relative_rect( - inner_rect.left(), - inner_rect.top(), - inner_rect.width(), - height_wanted_by_banner_widget); - } - - { - int vertical_scrollbar_width = m_vertical_scrollbar->effective_min_size().width().as_int(); - m_vertical_scrollbar->set_relative_rect( - inner_rect.right() - vertical_scrollbar_width, - inner_rect.top() + height_wanted_by_banner_widget, - vertical_scrollbar_width, - inner_rect.height() - height_wanted_by_horizontal_scrollbar - height_wanted_by_banner_widget); - } - - { - int horizontal_scrollbar_height = m_horizontal_scrollbar->effective_min_size().height().as_int(); - m_horizontal_scrollbar->set_relative_rect( - inner_rect.left(), - inner_rect.bottom() - horizontal_scrollbar_height, - inner_rect.width() - width_wanted_by_vertical_scrollbar, - horizontal_scrollbar_height); - } - - m_corner_widget->set_visible(m_vertical_scrollbar->is_visible() && m_horizontal_scrollbar->is_visible()); - if (m_corner_widget->is_visible()) { - Gfx::IntRect corner_rect { m_horizontal_scrollbar->relative_rect().right(), m_vertical_scrollbar->relative_rect().bottom(), width_occupied_by_vertical_scrollbar(), height_occupied_by_horizontal_scrollbar() }; - m_corner_widget->set_relative_rect(corner_rect); - } -} - -void AbstractScrollableWidget::resize_event(ResizeEvent& event) -{ - Frame::resize_event(event); - update_scrollbar_visibility(); - update_scrollbar_ranges(); -} - -Gfx::IntSize AbstractScrollableWidget::available_size() const -{ - auto inner_size = Widget::content_size(); - int available_width = max(inner_size.width() - m_size_occupied_by_fixed_elements.width(), 0); - int available_height = max(inner_size.height() - m_size_occupied_by_fixed_elements.height(), 0); - return { available_width, available_height }; -} - -Gfx::IntSize AbstractScrollableWidget::excess_size() const -{ - auto available_size = this->available_size(); - int excess_height = max(0, m_content_size.height() - available_size.height()); - int excess_width = max(0, m_content_size.width() - available_size.width()); - return { excess_width, excess_height }; -} - -void AbstractScrollableWidget::set_should_hide_unnecessary_scrollbars(bool should_hide_unnecessary_scrollbars) -{ - if (m_should_hide_unnecessary_scrollbars == should_hide_unnecessary_scrollbars) - return; - - m_should_hide_unnecessary_scrollbars = should_hide_unnecessary_scrollbars; - if (should_hide_unnecessary_scrollbars) { - update_scrollbar_ranges(); - } else { - m_horizontal_scrollbar->set_visible(m_scrollbars_enabled); - m_vertical_scrollbar->set_visible(m_scrollbars_enabled); - } -} - -void AbstractScrollableWidget::update_scrollbar_ranges() -{ - m_horizontal_scrollbar->set_range(0, excess_size().width()); - m_horizontal_scrollbar->set_page_step(visible_content_rect().width() - m_horizontal_scrollbar->step()); - - m_vertical_scrollbar->set_range(0, excess_size().height()); - m_vertical_scrollbar->set_page_step(visible_content_rect().height() - m_vertical_scrollbar->step()); - update_scrollbar_visibility(); -} - -void AbstractScrollableWidget::update_scrollbar_visibility() -{ - if (!m_scrollbars_enabled) { - m_horizontal_scrollbar->set_visible(false); - m_vertical_scrollbar->set_visible(false); - return; - } - if (should_hide_unnecessary_scrollbars()) { - // If there has not been a min_size set, the content_size can be used as a substitute - auto effective_min_content_size = m_min_content_size; - if (m_min_content_size == Gfx::IntSize {}) - effective_min_content_size = m_content_size; - int horizontal_buffer = rect().width() - 2 * frame_thickness() - effective_min_content_size.width(); - int vertical_buffer = rect().height() - 2 * frame_thickness() - effective_min_content_size.height() - height_occupied_by_banner_widget(); - bool horizontal_scrollbar_should_be_visible = false, vertical_scrollbar_should_be_visible = false; - vertical_scrollbar_should_be_visible = vertical_buffer < 0; - if (vertical_scrollbar_should_be_visible) - horizontal_buffer -= m_vertical_scrollbar->width(); - horizontal_scrollbar_should_be_visible = horizontal_buffer < 0; - if (horizontal_scrollbar_should_be_visible) - vertical_buffer -= m_horizontal_scrollbar->height(); - vertical_scrollbar_should_be_visible = vertical_buffer < 0; - m_horizontal_scrollbar->set_visible(horizontal_scrollbar_should_be_visible); - m_vertical_scrollbar->set_visible(vertical_scrollbar_should_be_visible); - } -} - -void AbstractScrollableWidget::set_content_size(Gfx::IntSize size) -{ - if (m_content_size == size) - return; - m_content_size = size; - update_scrollbar_ranges(); -} - -void AbstractScrollableWidget::set_min_content_size(Gfx::IntSize min_size) -{ - if (m_min_content_size == min_size) - return; - m_min_content_size = min_size; - update_scrollbar_ranges(); -} - -void AbstractScrollableWidget::set_size_occupied_by_fixed_elements(Gfx::IntSize size) -{ - if (m_size_occupied_by_fixed_elements == size) - return; - m_size_occupied_by_fixed_elements = size; - update_scrollbar_ranges(); -} - -int AbstractScrollableWidget::height_occupied_by_banner_widget() const -{ - return m_banner_widget && m_banner_widget->is_visible() ? m_banner_widget->height() : 0; -} - -int AbstractScrollableWidget::height_occupied_by_horizontal_scrollbar() const -{ - return m_horizontal_scrollbar->is_visible() ? m_horizontal_scrollbar->height() : 0; -} - -int AbstractScrollableWidget::width_occupied_by_vertical_scrollbar() const -{ - return m_vertical_scrollbar->is_visible() ? m_vertical_scrollbar->width() : 0; -} - -Margins AbstractScrollableWidget::content_margins() const -{ - return Frame::content_margins() + Margins { height_occupied_by_banner_widget(), width_occupied_by_vertical_scrollbar(), height_occupied_by_horizontal_scrollbar(), 0 }; -} - -Gfx::IntRect AbstractScrollableWidget::visible_content_rect() const -{ - auto inner_size = Widget::content_size(); - Gfx::IntRect rect { - m_horizontal_scrollbar->value(), - m_vertical_scrollbar->value(), - min(m_content_size.width(), inner_size.width() - m_size_occupied_by_fixed_elements.width()), - min(m_content_size.height(), inner_size.height() - m_size_occupied_by_fixed_elements.height()) - }; - if (rect.is_empty()) - return {}; - return rect; -} - -void AbstractScrollableWidget::scroll_into_view(Gfx::IntRect const& rect, Orientation orientation) -{ - if (orientation == Orientation::Vertical) - return scroll_into_view(rect, false, true); - return scroll_into_view(rect, true, false); -} - -void AbstractScrollableWidget::scroll_into_view(Gfx::IntRect const& rect, bool scroll_horizontally, bool scroll_vertically) -{ - auto visible_content_rect = this->visible_content_rect(); - if (visible_content_rect.contains(rect)) - return; - - if (scroll_vertically) { - if (rect.top() < visible_content_rect.top()) - m_vertical_scrollbar->set_value(rect.top()); - else if (rect.top() > visible_content_rect.top() && rect.bottom() > visible_content_rect.bottom()) - m_vertical_scrollbar->set_value(rect.bottom() - visible_content_rect.height()); - } - if (scroll_horizontally) { - if (rect.left() < visible_content_rect.left()) - m_horizontal_scrollbar->set_value(rect.left()); - else if (rect.left() > visible_content_rect.left() && rect.right() > visible_content_rect.right()) - m_horizontal_scrollbar->set_value(rect.right() - visible_content_rect.width()); - } -} - -void AbstractScrollableWidget::set_scrollbars_enabled(bool scrollbars_enabled) -{ - if (m_scrollbars_enabled == scrollbars_enabled) - return; - m_scrollbars_enabled = scrollbars_enabled; - m_vertical_scrollbar->set_visible(m_scrollbars_enabled); - m_horizontal_scrollbar->set_visible(m_scrollbars_enabled); - m_corner_widget->set_visible(m_scrollbars_enabled); -} - -void AbstractScrollableWidget::scroll_to_top() -{ - scroll_into_view({}, Orientation::Vertical); -} - -void AbstractScrollableWidget::scroll_to_bottom() -{ - scroll_into_view({ 0, content_height(), 0, 0 }, Orientation::Vertical); -} - -void AbstractScrollableWidget::scroll_to_right() -{ - scroll_into_view({ content_width(), 0, 0, 0 }, Orientation::Horizontal); -} - -void AbstractScrollableWidget::set_automatic_scrolling_timer_active(bool active) -{ - if (active == m_active_scrolling_enabled) - return; - - m_active_scrolling_enabled = active; - - if (active) { - automatic_scrolling_timer_did_fire(); - m_automatic_scrolling_timer->start(); - } else { - m_automatic_scrolling_timer->stop(); - } -} - -Gfx::IntPoint AbstractScrollableWidget::automatic_scroll_delta_from_position(Gfx::IntPoint pos) const -{ - Gfx::IntPoint delta { 0, 0 }; - - if (pos.y() < m_autoscroll_threshold) - delta.set_y(AK::min(pos.y() - m_autoscroll_threshold, 0)); - else if (pos.y() > widget_inner_rect().height() - m_autoscroll_threshold) - delta.set_y(AK::max(pos.y() + m_autoscroll_threshold - widget_inner_rect().height(), 0)); - - if (pos.x() < m_autoscroll_threshold) - delta.set_x(clamp(-(m_autoscroll_threshold - pos.x()), -m_autoscroll_threshold, 0)); - else if (pos.x() > widget_inner_rect().width() - m_autoscroll_threshold) - delta.set_x(clamp(m_autoscroll_threshold - (widget_inner_rect().width() - pos.x()), 0, m_autoscroll_threshold)); - - return delta; -} - -Gfx::IntRect AbstractScrollableWidget::widget_inner_rect() const -{ - auto rect = frame_inner_rect(); - rect.set_width(rect.width() - width_occupied_by_vertical_scrollbar()); - rect.set_height(rect.height() - height_occupied_by_horizontal_scrollbar() - height_occupied_by_banner_widget()); - rect.set_top(rect.top() + height_occupied_by_banner_widget()); - return rect; -} - -Gfx::IntPoint AbstractScrollableWidget::to_content_position(Gfx::IntPoint widget_position) const -{ - auto content_position = widget_position; - content_position.translate_by(horizontal_scrollbar().value(), vertical_scrollbar().value()); - content_position.translate_by(-frame_thickness(), -frame_thickness()); - return content_position; -} - -Gfx::IntPoint AbstractScrollableWidget::to_widget_position(Gfx::IntPoint content_position) const -{ - auto widget_position = content_position; - widget_position.translate_by(-horizontal_scrollbar().value(), -vertical_scrollbar().value()); - widget_position.translate_by(frame_thickness(), frame_thickness()); - return widget_position; -} - -Optional AbstractScrollableWidget::calculated_min_size() const -{ - auto vertical_scrollbar = m_vertical_scrollbar->effective_min_size().height().as_int(); - auto horizontal_scrollbar = m_horizontal_scrollbar->effective_min_size().width().as_int(); - auto banner = m_banner_widget && m_banner_widget->is_visible() ? m_banner_widget->effective_min_size().width().as_int() : 0; - auto max_width = max(banner, horizontal_scrollbar + corner_widget().width() + frame_thickness() * 2); - return { { max_width, vertical_scrollbar + corner_widget().height() + frame_thickness() * 2 + height_occupied_by_banner_widget() } }; -} - -} diff --git a/Userland/Libraries/LibGUI/AbstractScrollableWidget.h b/Userland/Libraries/LibGUI/AbstractScrollableWidget.h deleted file mode 100644 index aca5b93eefe..00000000000 --- a/Userland/Libraries/LibGUI/AbstractScrollableWidget.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2018-2021, Andreas Kling - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace GUI { - -class AbstractScrollableWidget : public Frame { - C_OBJECT_ABSTRACT(AbstractScrollableWidget); - -public: - virtual ~AbstractScrollableWidget() override = default; - - Gfx::IntSize content_size() const { return m_content_size; } - int content_width() const { return m_content_size.width(); } - int content_height() const { return m_content_size.height(); } - Gfx::IntSize min_content_size() const { return m_min_content_size; } - - Gfx::IntRect visible_content_rect() const; - - Gfx::IntRect widget_inner_rect() const; - - Gfx::IntRect viewport_rect_in_content_coordinates() const - { - auto viewport_rect = visible_content_rect(); - viewport_rect.set_size(widget_inner_rect().size()); - return viewport_rect; - } - - void scroll_into_view(Gfx::IntRect const&, Orientation); - void scroll_into_view(Gfx::IntRect const&, bool scroll_horizontally, bool scroll_vertically); - - void set_scrollbars_enabled(bool); - bool is_scrollbars_enabled() const { return m_scrollbars_enabled; } - - Gfx::IntSize available_size() const; - Gfx::IntSize excess_size() const; - - Scrollbar& vertical_scrollbar() { return *m_vertical_scrollbar; } - Scrollbar const& vertical_scrollbar() const { return *m_vertical_scrollbar; } - Scrollbar& horizontal_scrollbar() { return *m_horizontal_scrollbar; } - Scrollbar const& horizontal_scrollbar() const { return *m_horizontal_scrollbar; } - Widget& corner_widget() { return *m_corner_widget; } - Widget const& corner_widget() const { return *m_corner_widget; } - - void set_banner_widget(Widget*); - Widget* banner_widget() { return m_banner_widget; } - Widget const* banner_widget() const { return m_banner_widget; } - - void scroll_to_top(); - void scroll_to_bottom(); - void scroll_to_right(); - void update_scrollbar_ranges(); - - void set_automatic_scrolling_timer_active(bool); - virtual Gfx::IntPoint automatic_scroll_delta_from_position(Gfx::IntPoint) const; - - int width_occupied_by_vertical_scrollbar() const; - int height_occupied_by_horizontal_scrollbar() const; - int height_occupied_by_banner_widget() const; - - virtual Margins content_margins() const override; - - void set_should_hide_unnecessary_scrollbars(bool); - bool should_hide_unnecessary_scrollbars() const { return m_should_hide_unnecessary_scrollbars; } - - Gfx::IntPoint to_content_position(Gfx::IntPoint widget_position) const; - Gfx::IntPoint to_widget_position(Gfx::IntPoint content_position) const; - - Gfx::IntRect to_content_rect(Gfx::IntRect const& widget_rect) const { return { to_content_position(widget_rect.location()), widget_rect.size() }; } - Gfx::IntRect to_widget_rect(Gfx::IntRect const& content_rect) const { return { to_widget_position(content_rect.location()), content_rect.size() }; } - - virtual Optional calculated_min_size() const override; - -protected: - AbstractScrollableWidget(); - virtual void custom_layout() override; - virtual void resize_event(ResizeEvent&) override; - virtual void mousewheel_event(MouseEvent&) override; - virtual void did_scroll() { } - virtual void automatic_scrolling_timer_did_fire() {}; - void set_content_size(Gfx::IntSize); - void set_min_content_size(Gfx::IntSize); - void set_size_occupied_by_fixed_elements(Gfx::IntSize); - int autoscroll_threshold() const { return m_autoscroll_threshold; } - void update_scrollbar_visibility(); - -private: - class AbstractScrollableWidgetScrollbar final : public Scrollbar { - C_OBJECT(AbstractScrollableWidgetScrollbar); - - private: - explicit AbstractScrollableWidgetScrollbar(AbstractScrollableWidget& owner, Gfx::Orientation orientation) - : Scrollbar(orientation) - , m_owner(owner) - { - } - - virtual void mousewheel_event(MouseEvent& event) override - { - m_owner.handle_wheel_event(event, *this); - } - - AbstractScrollableWidget& m_owner; - }; - friend class ScrollableWidgetScrollbar; - - void handle_wheel_event(MouseEvent&, Widget&); - - RefPtr m_vertical_scrollbar; - RefPtr m_horizontal_scrollbar; - RefPtr m_corner_widget; - WeakPtr m_banner_widget; - Gfx::IntSize m_content_size; - Gfx::IntSize m_min_content_size; - Gfx::IntSize m_size_occupied_by_fixed_elements; - bool m_scrollbars_enabled { true }; - bool m_should_hide_unnecessary_scrollbars { false }; - - RefPtr m_automatic_scrolling_timer; - bool m_active_scrolling_enabled { false }; - int m_autoscroll_threshold { 20 }; -}; - -} diff --git a/Userland/Libraries/LibGUI/AbstractSlider.cpp b/Userland/Libraries/LibGUI/AbstractSlider.cpp deleted file mode 100644 index 4a45a5c674c..00000000000 --- a/Userland/Libraries/LibGUI/AbstractSlider.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include - -namespace GUI { - -AbstractSlider::AbstractSlider(Orientation orientation) - : m_orientation(orientation) -{ - REGISTER_INT_PROPERTY("value", value, set_value); - REGISTER_INT_PROPERTY("min", min, set_min); - REGISTER_INT_PROPERTY("max", max, set_max); - REGISTER_INT_PROPERTY("step", step, set_step); - REGISTER_INT_PROPERTY("page_step", page_step, set_page_step); - REGISTER_ENUM_PROPERTY("orientation", this->orientation, set_orientation, Orientation, - { Orientation::Horizontal, "Horizontal" }, - { Orientation::Vertical, "Vertical" }); -} - -void AbstractSlider::set_orientation(Orientation value) -{ - if (m_orientation == value) - return; - m_orientation = value; - update(); -} - -void AbstractSlider::set_page_step(int page_step) -{ - m_page_step = AK::max(0, page_step); -} - -void AbstractSlider::set_range(int min, int max) -{ - VERIFY(min <= max); - if (m_min == min && m_max == max) - return; - m_min = min; - m_max = max; - m_value = clamp(m_value, m_min, m_max); - update(); -} - -void AbstractSlider::set_value(int value, AllowCallback allow_callback, DoClamp do_clamp) -{ - if (do_clamp == DoClamp::Yes) - value = clamp(value, m_min, m_max); - if (m_value == value) - return; - m_value = value; - if (on_change && allow_callback == AllowCallback::Yes) - on_change(m_value); - update(); -} - -} diff --git a/Userland/Libraries/LibGUI/AbstractSlider.h b/Userland/Libraries/LibGUI/AbstractSlider.h deleted file mode 100644 index 671cef82b85..00000000000 --- a/Userland/Libraries/LibGUI/AbstractSlider.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace GUI { - -class AbstractSlider : public Widget { - C_OBJECT_ABSTRACT(AbstractSlider); - -public: - virtual ~AbstractSlider() override = default; - - void set_orientation(Orientation value); - Orientation orientation() const { return m_orientation; } - - int value() const { return m_value; } - int min() const { return m_min; } - int max() const { return m_max; } - int step() const { return m_step; } - int page_step() const { return m_page_step; } - bool jump_to_cursor() const { return m_jump_to_cursor; } - - bool is_min() const { return m_value == m_min; } - bool is_max() const { return m_value == m_max; } - - void set_range(int min, int max); - - enum class DoClamp { - Yes = 1, - No = 0 - }; - virtual void set_value(int, AllowCallback = AllowCallback::Yes, DoClamp = DoClamp::Yes); - - void set_min(int min) { set_range(min, max()); } - void set_max(int max) { set_range(min(), max); } - void set_step(int step) { m_step = step; } - void set_page_step(int page_step); - void set_jump_to_cursor(bool b) { m_jump_to_cursor = b; } - - virtual void increase_slider_by(int delta) { set_value(value() + delta); } - virtual void decrease_slider_by(int delta) { set_value(value() - delta); } - virtual void increase_slider_by_page_steps(int page_steps) { set_value(value() + page_step() * page_steps); } - virtual void decrease_slider_by_page_steps(int page_steps) { set_value(value() - page_step() * page_steps); } - virtual void increase_slider_by_steps(int steps) { set_value(value() + step() * steps); } - virtual void decrease_slider_by_steps(int steps) { set_value(value() - step() * steps); } - - Function on_change; - -protected: - explicit AbstractSlider(Orientation = Orientation::Vertical); - -private: - int m_value { 0 }; - int m_min { 0 }; - int m_max { 0 }; - int m_step { 1 }; - int m_page_step { 10 }; - bool m_jump_to_cursor { false }; - Orientation m_orientation { Orientation::Horizontal }; -}; - -} diff --git a/Userland/Libraries/LibGUI/AbstractTableView.cpp b/Userland/Libraries/LibGUI/AbstractTableView.cpp deleted file mode 100644 index b22344b34cb..00000000000 --- a/Userland/Libraries/LibGUI/AbstractTableView.cpp +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * Copyright (c) 2022, the SerenityOS developers. - * Copyright (c) 2023, Sam Atkins - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace GUI { - -AbstractTableView::AbstractTableView() -{ - REGISTER_BOOL_PROPERTY("column_headers_visible", column_headers_visible, set_column_headers_visible); - - set_selection_behavior(SelectionBehavior::SelectRows); - m_corner_button = add