From e87f889e31afbb5fa32c910603c7f5e781c97afd Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 17 Feb 2026 14:23:39 +0100 Subject: [PATCH] Everywhere: Abandon Swift adoption After making no progress on this for a very long time, let's acknowledge it's not going anywhere and remove it from the codebase. --- .github/actions/setup/action.yml | 45 - .github/workflows/lagom-template.yml | 6 +- .github/workflows/lint-code.yml | 2 +- .github/workflows/nightly-lagom.yml | 14 - .swift-format | 8 - .swift-version | 1 - AK/AK+Swift.swift | 47 - AK/CMakeLists.txt | 12 - AK/Function.h | 3 +- AK/Swift.h | 47 - AK/Windows.h | 2 +- CMakeLists.txt | 6 +- Documentation/AdvancedBuildInstructions.md | 58 - Documentation/FAQ.md | 1 - Libraries/LibCore/CMakeLists.txt | 24 - Libraries/LibCore/EventLoop.h | 3 +- Libraries/LibCore/EventLoopExecutor.swift | 53 - Libraries/LibCore/EventSwift.mm | 17 - Libraries/LibGC/CMakeLists.txt | 10 - Libraries/LibGC/Cell.h | 13 +- Libraries/LibGC/DeferGC.h | 3 +- Libraries/LibGC/ForeignCell.cpp | 61 - Libraries/LibGC/ForeignCell.h | 182 -- Libraries/LibGC/Forward.h | 1 - Libraries/LibGC/Heap+Swift.swift | 82 - Libraries/LibGC/Heap.h | 4 +- Libraries/LibGfx/CMakeLists.txt | 17 - Libraries/LibGfx/Color.cpp | 15 - Libraries/LibGfx/Color.swift | 89 - Libraries/LibWeb/CMakeLists.txt | 20 - Libraries/LibWeb/HTML/Parser/HTMLParser.cpp | 8 - Libraries/LibWeb/HTML/Parser/HTMLParser.h | 20 +- Libraries/LibWeb/HTML/Parser/HTMLToken.swift | 286 --- .../LibWeb/HTML/Parser/HTMLTokenizer.swift | 1928 ----------------- .../HTML/Parser/HTMLTokenizerHelpers.cpp | 51 - .../LibWeb/HTML/Parser/HTMLTokenizerHelpers.h | 32 - .../HTML/Parser/SpeculativeHTMLParser.swift | 60 - Libraries/LibWeb/Loader/FileRequest.h | 3 +- Libraries/LibWebView/Application.h | 3 +- Meta/CMake/FindBlocksRuntime.cmake | 6 +- Meta/CMake/FindSwiftTesting.cmake | 60 - Meta/CMake/Swift/GenerateSwiftHeader.cmake | 92 - Meta/CMake/Swift/InitializeSwift.cmake | 109 - Meta/CMake/Swift/swift-settings.cmake | 82 - Meta/CMake/code_generators.cmake | 34 - Meta/CMake/collections.cmake | 25 - Meta/CMake/common_compile_options.cmake | 18 - Meta/CMake/common_options.cmake | 11 - Meta/CMake/lagom_install_options.cmake | 4 - ...ve-top-level-binary-module-locations.patch | 170 -- Meta/CMake/presets/CMakeBasePresets.json | 19 - Meta/CMake/presets/CMakeUnixPresets.json | 19 - Meta/CMake/sanitizers.cmake | 6 +- Meta/CMake/skia.cmake | 1 - Meta/CMake/utils.cmake | 5 - .../ClangPlugins/LibJSGCPluginAction.cpp | 9 - Meta/Lagom/ClangPlugins/LibJSGCPluginAction.h | 1 - Meta/check-newlines-at-eof.py | 2 +- Meta/find_compiler.py | 28 - Meta/generate_clang_module_map.py | 72 - Meta/gn/secondary/AK/BUILD.gn | 1 - .../Libraries/LibWeb/HTML/Parser/BUILD.gn | 1 - Meta/ladybird.py | 12 +- Meta/lint-ci.sh | 7 - Meta/lint-swift.sh | 33 - Tests/AK/CMakeLists.txt | 9 - Tests/AK/TestAKBindings.swift | 50 - Tests/CMakeLists.txt | 1 - .../classes_are_missing_expected_macros.cpp | 5 - .../Macros/classes_have_expected_macros.cpp | 5 - .../classes_have_incorrect_macro_types.cpp | 11 - .../Macros/wrong_classname_arg.cpp | 6 - Tests/LibCore/CMakeLists.txt | 17 - Tests/LibCore/TestEventLoopActor.swift | 63 - Tests/LibGC/CMakeLists.txt | 25 - Tests/LibGC/TestGCBindings.swift | 53 - Tests/LibGC/TestHeap.cpp | 15 - Tests/LibGC/TestHeap.h | 11 - Tests/LibGC/TestInterop.cpp | 44 - Tests/LibGC/TestInterop.h | 9 - Tests/LibWeb/CMakeLists.txt | 16 - Tests/LibWeb/TestHTMLTokenizerSwift.swift | 314 --- Tests/LibWeb/TestLibWebSwiftBindings.swift | 24 - Tests/Resources/SwiftTestMain.swift | 27 - 84 files changed, 22 insertions(+), 4747 deletions(-) delete mode 100644 .swift-format delete mode 100644 .swift-version delete mode 100644 AK/AK+Swift.swift delete mode 100644 AK/Swift.h delete mode 100644 Libraries/LibCore/EventLoopExecutor.swift delete mode 100644 Libraries/LibCore/EventSwift.mm delete mode 100644 Libraries/LibGC/ForeignCell.cpp delete mode 100644 Libraries/LibGC/ForeignCell.h delete mode 100644 Libraries/LibGC/Heap+Swift.swift delete mode 100644 Libraries/LibGfx/Color.swift delete mode 100644 Libraries/LibWeb/HTML/Parser/HTMLToken.swift delete mode 100644 Libraries/LibWeb/HTML/Parser/HTMLTokenizer.swift delete mode 100644 Libraries/LibWeb/HTML/Parser/HTMLTokenizerHelpers.cpp delete mode 100644 Libraries/LibWeb/HTML/Parser/HTMLTokenizerHelpers.h delete mode 100644 Libraries/LibWeb/HTML/Parser/SpeculativeHTMLParser.swift delete mode 100644 Meta/CMake/FindSwiftTesting.cmake delete mode 100644 Meta/CMake/Swift/GenerateSwiftHeader.cmake delete mode 100644 Meta/CMake/Swift/InitializeSwift.cmake delete mode 100644 Meta/CMake/Swift/swift-settings.cmake delete mode 100644 Meta/CMake/collections.cmake delete mode 100644 Meta/CMake/patches/swift-collections/0001-CMake-Remove-top-level-binary-module-locations.patch delete mode 100644 Meta/generate_clang_module_map.py delete mode 100755 Meta/lint-swift.sh delete mode 100644 Tests/AK/TestAKBindings.swift delete mode 100644 Tests/LibCore/TestEventLoopActor.swift delete mode 100644 Tests/LibGC/CMakeLists.txt delete mode 100644 Tests/LibGC/TestGCBindings.swift delete mode 100644 Tests/LibGC/TestHeap.cpp delete mode 100644 Tests/LibGC/TestHeap.h delete mode 100644 Tests/LibGC/TestInterop.cpp delete mode 100644 Tests/LibGC/TestInterop.h delete mode 100644 Tests/LibWeb/TestHTMLTokenizerSwift.swift delete mode 100644 Tests/LibWeb/TestLibWebSwiftBindings.swift delete mode 100644 Tests/Resources/SwiftTestMain.swift diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 2a5a8d77a7..aff21bd817 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -74,51 +74,6 @@ runs: with: xcode-version: 26.2 - - name: 'Install Swift toolchain' - if: ${{ inputs.toolchain == 'Swift' }} - shell: bash - run: | - set -e - - export SWIFTLY_HOME_DIR=${{ github.workspace }}/.swiftly/share - export SWIFTLY_BIN_DIR=${{ github.workspace }}/.swiftly/bin - - echo "$SWIFTLY_BIN_DIR" >> $GITHUB_PATH - echo "SWIFTLY_HOME_DIR=$SWIFTLY_HOME_DIR" >> $GITHUB_ENV - echo "SWIFTLY_BIN_DIR=$SWIFTLY_BIN_DIR" >> $GITHUB_ENV - - export PATH=$SWIFTLY_BIN_DIR:$PATH - - mkdir -p $SWIFTLY_HOME_DIR - mkdir -p $SWIFTLY_BIN_DIR - - if ${{ inputs.os == 'Linux' }} ; then - curl -O https://download.swift.org/swiftly/linux/swiftly-${{ inputs.arch }}.tar.gz - file swiftly-${{ inputs.arch }}.tar.gz - tar -xzf swiftly-${{ inputs.arch }}.tar.gz -C $SWIFTLY_BIN_DIR - rm swiftly-${{ inputs.arch }}.tar.gz - else - # FIXME: https://github.com/swiftlang/swiftly/issues/271 - # Why does this drop files in $HOME? That's not very CI-friendly - curl -O https://download.swift.org/swiftly/darwin/swiftly.pkg - installer -pkg swiftly.pkg -target CurrentUserHomeDirectory - cp ~/.swiftly/bin/swiftly $SWIFTLY_BIN_DIR - rm swiftly.pkg - fi - - swiftly init \ - --no-modify-profile \ - --quiet-shell-followup \ - --assume-yes \ - --skip-install \ - --verbose - - echo "swiftly version: $(swiftly --version)" >&2 - - # installs version listed in .swift-version - swiftly install - swiftly list - - name: 'Install Dependencies' if: ${{ inputs.os == 'macOS' || inputs.os == 'Android' }} shell: bash diff --git a/.github/workflows/lagom-template.yml b/.github/workflows/lagom-template.yml index d03a6d98da..11a4b5c13c 100644 --- a/.github/workflows/lagom-template.yml +++ b/.github/workflows/lagom-template.yml @@ -66,11 +66,7 @@ jobs: id: 'build-parameters' run: | CMAKE_OPTIONS="-DENABLE_CI_BASELINE_CPU=ON" - if ${{ inputs.toolchain == 'Swift' }} ; then - echo "host_cc=$(swiftly use --print-location)/usr/bin/clang" >> "$GITHUB_OUTPUT" - echo "host_cxx=$(swiftly use --print-location)/usr/bin/clang++" >> "$GITHUB_OUTPUT" - CMAKE_OPTIONS="$CMAKE_OPTIONS -DENABLE_SWIFT=ON" - elif ${{ inputs.os_name == 'Linux' }} ; then + if ${{ inputs.os_name == 'Linux' }} ; then # FIXME: https://github.com/WebAssembly/wabt/issues/2533 # wabt doesn't have binary releases for arm64 Linux if ${{ inputs.arch == 'arm64' }} ; then diff --git a/.github/workflows/lint-code.yml b/.github/workflows/lint-code.yml index a1a697001a..a87e9f4835 100644 --- a/.github/workflows/lint-code.yml +++ b/.github/workflows/lint-code.yml @@ -15,7 +15,7 @@ jobs: run: | set -e - brew install curl llvm@20 ninja optipng ruff shellcheck swift-format unzip + brew install curl llvm@20 ninja optipng ruff shellcheck unzip # Note: gn isn't available in homebrew :( # Corresponds to https://gn.googlesource.com/gn/+/225e90c5025bf74f41dbee60d9cde4512c846fe7 diff --git a/.github/workflows/nightly-lagom.yml b/.github/workflows/nightly-lagom.yml index 05f1ea98aa..165a9babba 100644 --- a/.github/workflows/nightly-lagom.yml +++ b/.github/workflows/nightly-lagom.yml @@ -47,20 +47,6 @@ jobs: clang_plugins: false runner_labels: '["blacksmith-8vcpu-ubuntu-2404-arm"]' - - os_name: 'Linux' - arch: 'x86_64' - build_preset: 'Sanitizer' - toolchain: 'Swift' - clang_plugins: false - runner_labels: '["blacksmith-8vcpu-ubuntu-2404"]' - - - os_name: 'macOS' - arch: 'arm64' - build_preset: 'Sanitizer' - toolchain: 'Swift' - clang_plugins: false - runner_labels: '["macos-15", "self-hosted"]' - - os_name: 'Windows' arch: 'x86_64' build_preset: 'Sanitizer' diff --git a/.swift-format b/.swift-format deleted file mode 100644 index 94b67e307d..0000000000 --- a/.swift-format +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version": 1, - "indentation": { - "spaces": 4 - }, - "tabWidth": 4, - "lineLength": 320 -} diff --git a/.swift-version b/.swift-version deleted file mode 100644 index 80274bdc98..0000000000 --- a/.swift-version +++ /dev/null @@ -1 +0,0 @@ -main-snapshot-2025-06-22 \ No newline at end of file diff --git a/AK/AK+Swift.swift b/AK/AK+Swift.swift deleted file mode 100644 index 6fa270dd23..0000000000 --- a/AK/AK+Swift.swift +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -@_exported import AKCxx -import Foundation - -extension Swift.String { - public init?(akString: AK.String) { - let bytes = akString.__bytes_as_string_viewUnsafe().bytes() - let data = Foundation.Data(bytesNoCopy: UnsafeMutableRawPointer(mutating: bytes.data()), count: bytes.size(), deallocator: .none) - - self.init(data: data, encoding: .utf8) - } - - public init?(akStringView: AK.StringView) { - let bytes = akStringView.bytes() - let data = Foundation.Data(bytesNoCopy: UnsafeMutableRawPointer(mutating: bytes.data()), count: bytes.size(), deallocator: .none) - - self.init(data: data, encoding: .utf8) - } -} - -extension AK.String { - public init(swiftString: consuming Swift.String) { - self.init() // Create empty string first, using default constructor - swiftString.withUTF8 { buffer in - self = AK.String.from_utf8_without_validation(AK.ReadonlyBytes(buffer.baseAddress!, buffer.count)) - } - } -} -extension AK.StringView: ExpressibleByStringLiteral { - public typealias StringLiteralType = Swift.StaticString - - public init(stringLiteral value: StringLiteralType) { - self.init(value.utf8Start, value.utf8CodeUnitCount) - } - - public func endsWith(_ suffix: AK.StringView) -> Bool { - if suffix.length() == 1 { - return self.ends_with(suffix[0]) - } - return self.ends_with(suffix, AK.CaseSensitivity.sensitive) - } -} diff --git a/AK/CMakeLists.txt b/AK/CMakeLists.txt index 7beadc21df..ad9b8434ed 100644 --- a/AK/CMakeLists.txt +++ b/AK/CMakeLists.txt @@ -68,11 +68,9 @@ endif() configure_file(Backtrace.h.in Backtrace.h @ONLY) find_package(simdutf REQUIRED) -swizzle_target_properties_for_swift(simdutf::simdutf) target_link_libraries(AK PRIVATE simdutf::simdutf) find_package(FastFloat CONFIG REQUIRED) -swizzle_target_properties_for_swift(FastFloat::fast_float) target_link_libraries(AK PRIVATE FastFloat::fast_float) # FIXME: Make this generic for all imported shared library dependencies and apply globally @@ -83,16 +81,6 @@ if (BUILD_SHARED_LIBS AND NOT CMAKE_SKIP_INSTALL_RULES AND NOT "${VCPKG_INSTALLE ) endif() -if (ENABLE_SWIFT) - generate_clang_module_map(AK - GENERATED_FILES - "${CMAKE_CURRENT_BINARY_DIR}/Backtrace.h" - "${CMAKE_CURRENT_BINARY_DIR}/Debug.h" - ) - target_sources(AK PRIVATE AK+Swift.swift) - add_swift_target_properties(AK) -endif() - if (WIN32) # FIXME: Windows on ARM target_link_libraries(AK PRIVATE clang_rt.builtins-x86_64.lib) diff --git a/AK/Function.h b/AK/Function.h index b58067b75c..fb887493ea 100644 --- a/AK/Function.h +++ b/AK/Function.h @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -380,7 +379,7 @@ private: static constexpr size_t inline_capacity = 4 * sizeof(void*); alignas(inline_alignment) u8 m_storage[inline_capacity]; -} SWIFT_UNSAFE_REFERENCE; +}; } diff --git a/AK/Swift.h b/AK/Swift.h deleted file mode 100644 index 8c58f7a83d..0000000000 --- a/AK/Swift.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#if __has_include() -# include -// FIXME: Workaround for Xcode 14/15. When swif becomes required, we should bump the -// required Xcode version to one that supports all the features we are using. -# ifndef SWIFT_UNCHECKED_SENDABLE -# define SWIFT_UNCHECKED_SENDABLE -# define SWIFT_NONCOPYABLE -# define SWIFT_NONESCAPABLE -# define SWIFT_ESCAPABLE -# define SWIFT_ESCAPABLE_IF(...) -# define SWIFT_RETURNS_RETAINED -# define SWIFT_RETURNS_UNRETAINED -# endif -#else -# define SWIFT_SELF_CONTAINED -# define SWIFT_RETURNS_INDEPENDENT_VALUE -# define SWIFT_SHARED_REFERENCE(retain, release) -# define SWIFT_IMMORTAL_REFERENCE -# define SWIFT_UNSAFE_REFERENCE -# define SWIFT_NAME(name) -# define SWIFT_CONFORMS_TO_PROTOCOL(protocol) -# define SWIFT_COMPUTED_PROPERTY -# define SWIFT_MUTATING -# define SWIFT_UNCHECKED_SENDABLE -# define SWIFT_NONCOPYABLE -# define SWIFT_NONESCAPABLE -# define SWIFT_ESCAPABLE -# define SWIFT_ESCAPABLE_IF(...) -# define SWIFT_RETURNS_RETAINED -# define SWIFT_RETURNS_UNRETAINED -#endif - -// FIXME: This needs to be in the global namespace for reasons -// https://github.com/swiftlang/swift/issues/80231 -template -To cxxCast(From i) -{ - return static_cast(i); -} diff --git a/AK/Windows.h b/AK/Windows.h index 9a0b1017c8..dbb2e43582 100644 --- a/AK/Windows.h +++ b/AK/Windows.h @@ -15,7 +15,7 @@ #include #include -#ifdef AK_OS_WINDOWS // needed for Swift +#ifdef AK_OS_WINDOWS # define timeval dummy_timeval # include # include diff --git a/CMakeLists.txt b/CMakeLists.txt index afcc5bf265..3ae05cabbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,11 +11,7 @@ endif() include("Meta/CMake/use_linker.cmake") if (APPLE AND NOT CMAKE_OSX_DEPLOYMENT_TARGET) - if (ENABLE_SWIFT) - set(CMAKE_OSX_DEPLOYMENT_TARGET 15.0) - else() - set(CMAKE_OSX_DEPLOYMENT_TARGET 14.0) - endif() + set(CMAKE_OSX_DEPLOYMENT_TARGET 14.0) endif() # Pass additional information to vcpkg toolchain files if we are using vcpkg. diff --git a/Documentation/AdvancedBuildInstructions.md b/Documentation/AdvancedBuildInstructions.md index 5553f5354c..c7bfb8ab89 100644 --- a/Documentation/AdvancedBuildInstructions.md +++ b/Documentation/AdvancedBuildInstructions.md @@ -187,61 +187,3 @@ After you’ve finished debugging your code changes with that build, you can rev That will restore your git environment to the state it was in before you patched the build file. -## Building with Swift support - -There is experimental Swift 6 support in the Ladybird codebase. This experiment intends to determine whether Swift 6 and -its improved C++ interoperability is a good choice for new memory-safe and concurrent code for Ladybird. - -Building with Swift 6 support requires a main snapshot toolchain. The Ladybird team is actively working with the Swift -team to improve the C++ interop features to meet the needs of our project. - -The best way to get started is with `swiftly`. After setting up a `swiftly` toolchain, any of the existing build presets -can be modified to use the Swift toolchain. However, note that in order to build Swift support into the project, the -build must use a version of Clang that is built from an LLVM fork with Swift support. The two places this can be found -are from the swift.org snapshot/release toolchains, and Xcode toolchains. Upstream llvm.org Clang does not support -Swift, and GCC does not support Swift either. - -### Get Swiftly - -`swiftly` is a tool that helps you manage Swift toolchains. It can be installed from https://www.swift.org/install/linux/ -or https://www.swift.org/install/macos/ as applicable. After following the instructions on the swift.org install page, -`swiftly` installs the latest release toolchain. If you wish to save space, add the `--skip-install` flag to the `swiftly -init` invocation. If you wish to avoid `swiftly` messing with your shellrc files, add `--no-modify-profile`. On some Linux -platforms, it may be necessary to add a `--platform` flag to the `swiftly init` invocation to instruct `swiftly` on which -supported platform to masquerade as. This is especially necessary on Fedora or other non-Debian based distributions. - -Note that while `$SWIFTLY_HOME_DIR` and `$SWIFTLY_BIN_DIR` can be used -to set the installed location of the `swiftly` binary and its associated files, the install location of toolchains is not -nearly as customizable. On Linux they will always be placed in `$XDG_DATA_HOME/swiftly/toolchains`, and on macOS they will always be -placed in `$HOME/Library/Developer/Toolchains`. On macOS, the `.pkg` file will always drop temporary files in `$HOME/.swiftly`, -so be sure to clear them out if you change the default home/bin directories. - -### Build with Swift - -The simplest way to enable Swift is to use the `Swift_Release` preset and `ladybird.py`. - -```bash -./Meta/ladybird.py build --preset Swift_Release -``` - -Note that because building with Swift support requires use of `clang` and `clang++` from a Swift toolchain, a standard -install of Clang or GCC will not work. Additional IDE settings are be required to ensure that the IDE uses the correct -compiler paths. Trying to use just `clang` or `$SWIFTLY_BIN_DIR/clang` will both fail, due to https://github.com/swiftlang/swiftly/issues/272. - -The full paths that must be configured for the C and C++ compilers in your IDE are -`$(swiftly use --print-location)/usr/bin/clang` and `$(swiftly use --print-location)/usr/bin/clang++`. These paths -will change depending on the version of the Swift toolchain specified in `.swift-version`. - -As another note, the main-snapshot toolchains from swift.org are `+assertion` builds. This means that both `clang` and -`swiftc` are built with extra assertions that will cause compile-times to be longer than a standard release build. - -To configure the build preset manually, you must first install the specified Swift toolchain, and then set the C and C++ -compiler paths manually. - -```bash -swiftly install - -cmake --preset Swift_Release \ - -DCMAKE_C_COMPILER=$(swiftly use --print-location)/usr/bin/clang \ - -DCMAKE_CXX_COMPILER=$(swiftly use --print-location)/usr/bin/clang++ -``` diff --git a/Documentation/FAQ.md b/Documentation/FAQ.md index 62da4e6262..94064aa532 100644 --- a/Documentation/FAQ.md +++ b/Documentation/FAQ.md @@ -99,7 +99,6 @@ Here’s a short timeline: ## Do you have some general details about the code and basic architecture? -- C++ while selectively migrating parts to Swift and while keeping an eye on things like Sean Baxter’s [Circle](https://github.com/seanbaxter/circle) & [Safe C++](https://safecpp.org/draft.html). - Some use of third-party libraries (e.g., Harfbuzz, Skia, [simdutf](https://github.com/simdutf/simdutf), libcurl). - Performance optimizing is not yet a super-high priority (but performance-boosting changes are regularly getting made). - Code size: diff --git a/Libraries/LibCore/CMakeLists.txt b/Libraries/LibCore/CMakeLists.txt index e027380c1c..3f6eabd28a 100644 --- a/Libraries/LibCore/CMakeLists.txt +++ b/Libraries/LibCore/CMakeLists.txt @@ -149,27 +149,3 @@ endif() if (ANDROID) target_link_libraries(LibCore PRIVATE log) endif() - -if (ENABLE_SWIFT) - if(WIN32) - list(APPEND SWIFT_EXCLUDE_HEADERS "EventLoopImplementationUnix.h") - else() - list(APPEND SWIFT_EXCLUDE_HEADERS "EventLoopImplementationWindows.h") - endif() - if (NOT APPLE) - list(APPEND SWIFT_EXCLUDE_HEADERS - IOSurface.h - MachPort.h - MachMessageTypes.h - ProcessStatisticsMach.h - ) - endif() - - generate_clang_module_map(LibCore EXCLUDE_FILES ${SWIFT_EXCLUDE_HEADERS}) - target_sources(LibCore PRIVATE - EventSwift.mm - EventLoopExecutor.swift) - set_source_files_properties(EventSwift.mm PRIVATE PROPERTIES COMPILE_FLAGS -fblocks) - target_link_libraries(LibCore PRIVATE AK) - add_swift_target_properties(LibCore LAGOM_LIBRARIES AK) -endif() diff --git a/Libraries/LibCore/EventLoop.h b/Libraries/LibCore/EventLoop.h index a23f222c66..355ff0a8ec 100644 --- a/Libraries/LibCore/EventLoop.h +++ b/Libraries/LibCore/EventLoop.h @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -99,7 +98,7 @@ public: private: NonnullOwnPtr m_impl; RefPtr m_weak; -} SWIFT_UNSAFE_REFERENCE; +}; class StrongEventLoopReference; diff --git a/Libraries/LibCore/EventLoopExecutor.swift b/Libraries/LibCore/EventLoopExecutor.swift deleted file mode 100644 index d678d38737..0000000000 --- a/Libraries/LibCore/EventLoopExecutor.swift +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2025, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -import AK -@_exported import CoreCxx - -extension Core.EventLoop: Equatable { - func deferred_invoke(_ task: @escaping () -> Void) { - Core.deferred_invoke_block(self, task) - } - - public static func == (lhs: Core.EventLoop, rhs: Core.EventLoop) -> Bool { - Unmanaged.passUnretained(lhs).toOpaque() == Unmanaged.passUnretained(rhs).toOpaque() - } -} - -public class EventLoopExecutor: SerialExecutor, TaskExecutor, @unchecked Sendable { - nonisolated private let eventLoop: Core.EventLoop - - public init() { - eventLoop = Core.EventLoop.current() - } - - public init(eventLoop: Core.EventLoop) { - self.eventLoop = eventLoop - } - - public nonisolated func enqueue(_ job: consuming ExecutorJob) { - let job = UnownedJob(job) - eventLoop.deferred_invoke { [self, job] in - job.runSynchronously( - isolatedTo: self.asUnownedSerialExecutor(), - taskExecutor: self.asUnownedTaskExecutor()) - } - } - - public func checkIsolated() { - precondition(Core.EventLoop.current() == eventLoop) - } -} - -public protocol EventLoopActor: Actor { - nonisolated var executor: EventLoopExecutor { get } // impl with a let -} - -extension EventLoopActor { - public nonisolated var unownedExecutor: UnownedSerialExecutor { - executor.asUnownedSerialExecutor() - } -} diff --git a/Libraries/LibCore/EventSwift.mm b/Libraries/LibCore/EventSwift.mm deleted file mode 100644 index ee3c678f04..0000000000 --- a/Libraries/LibCore/EventSwift.mm +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2025, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -namespace Core { - -void deferred_invoke_block(EventLoop& event_loop, void (^invokee)(void)) -{ - event_loop.deferred_invoke(invokee); -} - -} diff --git a/Libraries/LibGC/CMakeLists.txt b/Libraries/LibGC/CMakeLists.txt index 378f0790b5..6cf7defce3 100644 --- a/Libraries/LibGC/CMakeLists.txt +++ b/Libraries/LibGC/CMakeLists.txt @@ -3,7 +3,6 @@ set(SOURCES Cell.cpp CellAllocator.cpp ConservativeVector.cpp - ForeignCell.cpp Root.cpp RootHashMap.cpp RootVector.cpp @@ -16,15 +15,6 @@ set(SOURCES ladybird_lib(LibGC gc EXPLICIT_SYMBOL_EXPORT) target_link_libraries(LibGC PRIVATE LibCore) -if (ENABLE_SWIFT) - generate_clang_module_map(LibGC) - target_sources(LibGC PRIVATE - Heap+Swift.swift - ) - target_link_libraries(LibGC PRIVATE AK) - add_swift_target_properties(LibGC LAGOM_LIBRARIES AK) -endif() - # TODO: Use lagom_generate_export_header and annotate entire LibGC with export macros include(GenerateExportHeader) generate_export_header(LibGC EXPORT_MACRO_NAME GC_API EXPORT_FILE_NAME "Export.h") diff --git a/Libraries/LibGC/Cell.h b/Libraries/LibGC/Cell.h index 4c832bd59c..708cb61f56 100644 --- a/Libraries/LibGC/Cell.h +++ b/Libraries/LibGC/Cell.h @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -72,17 +71,17 @@ public: visit_impl(*cell); } - void visit(Cell& cell) SWIFT_NAME(visitRef(_:)) + void visit(Cell& cell) { visit_impl(cell); } - void visit(Cell const* cell) SWIFT_NAME(visitConst(_:)) + void visit(Cell const* cell) { visit(const_cast(cell)); } - void visit(Cell const& cell) SWIFT_NAME(visitConstRef(_:)) + void visit(Cell const& cell) { visit(const_cast(cell)); } @@ -185,7 +184,7 @@ public: visit(optional.value()); } - void visit(NanBoxedValue const& value) SWIFT_NAME(visitValue(_:)); + void visit(NanBoxedValue const& value); // Allow explicitly ignoring a GC-allocated member in a visit_edges implementation instead // of just not using it. @@ -200,7 +199,7 @@ public: virtual void visit_impl(Cell&) = 0; virtual void visit_impl(ReadonlySpan) = 0; virtual ~Visitor() = default; - } SWIFT_UNSAFE_REFERENCE; + }; MUST_UPCALL virtual void visit_edges(Visitor&) { } @@ -220,7 +219,7 @@ protected: private: bool m_mark { false }; State m_state { State::Live }; -} SWIFT_UNSAFE_REFERENCE; +}; } diff --git a/Libraries/LibGC/DeferGC.h b/Libraries/LibGC/DeferGC.h index 3d4b5999cb..812b839fe8 100644 --- a/Libraries/LibGC/DeferGC.h +++ b/Libraries/LibGC/DeferGC.h @@ -6,7 +6,6 @@ #pragma once -#include #include namespace GC { @@ -26,6 +25,6 @@ public: private: Heap& m_heap; -} SWIFT_NONCOPYABLE; +}; } diff --git a/Libraries/LibGC/ForeignCell.cpp b/Libraries/LibGC/ForeignCell.cpp deleted file mode 100644 index 0d6539433f..0000000000 --- a/Libraries/LibGC/ForeignCell.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace GC { - -void* ForeignCell::foreign_data() -{ - // !!! - auto offset = round_up_to_power_of_two(sizeof(ForeignCell), m_vtable.alignment); - return static_cast(reinterpret_cast(this) + offset); -} - -ForeignCell::ForeignCell(ForeignCell::Vtable vtable) - : m_vtable(move(vtable)) -{ - if (m_vtable.initialize) - m_vtable.initialize(foreign_data(), m_vtable.class_metadata_pointer, *this); -} - -ForeignCell::~ForeignCell() -{ - if (m_vtable.destroy) - m_vtable.destroy(foreign_data(), m_vtable.class_metadata_pointer); -} - -Ref ForeignCell::create(Heap& heap, size_t size, ForeignCell::Vtable vtable) -{ - // NOTE: GC must be deferred so that a collection during allocation doesn't get tripped - // up looking for the Cell pointer on the stack or in a register when it might only exist in the heap. - // We can't guarantee that the ForeignCell will be stashed in a proper ForeignRef/ForeignPtr or similar - // foreign type until after all the dust has settled on both sides of the FFI boundary. - VERIFY(heap.is_gc_deferred()); - VERIFY(is_power_of_two(vtable.alignment)); - auto& allocator = heap.allocator_for_size(sizeof(ForeignCell) + round_up_to_power_of_two(size, vtable.alignment)); - auto* memory = allocator.allocate_cell(heap); - auto* foreign_cell = new (memory) ForeignCell(move(vtable)); - return *foreign_cell; -} - -void ForeignCell::finalize() -{ - Base::finalize(); - if (m_vtable.finalize) - m_vtable.finalize(foreign_data(), m_vtable.class_metadata_pointer); -} - -void ForeignCell::visit_edges(Cell::Visitor& visitor) -{ - Base::visit_edges(visitor); - if (m_vtable.visit_edges) - m_vtable.visit_edges(foreign_data(), m_vtable.class_metadata_pointer, visitor); -} - -} diff --git a/Libraries/LibGC/ForeignCell.h b/Libraries/LibGC/ForeignCell.h deleted file mode 100644 index def11169a9..0000000000 --- a/Libraries/LibGC/ForeignCell.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace GC { - -template -struct ForeignRef; - -template -struct ForeignPtr; - -#define FOREIGN_CELL(class_, base_class) \ - using Base = base_class; \ - friend class GC::Heap; - -class GC_API ForeignCell : public Cell { - FOREIGN_CELL(ForeignCell, Cell); - -public: - static constexpr bool OVERRIDES_FINALIZE = true; - - struct Vtable { - // Holds a pointer to the foreign vtable information such as - // a jclass in Java, or a Swift type metadata pointer - void* class_metadata_pointer = nullptr; - - // FIXME: FlyString? The class name must be owned by the ForeignCell so it can vend StringViews - // We should properly cache the name and class info pointer to avoid string churn - String class_name; - - size_t alignment { 1 }; - - void (*initialize)(void* thiz, void* clazz, Ref); - void (*destroy)(void* thiz, void* clazz); - void (*finalize)(void* thiz, void* clazz); - void (*visit_edges)(void* thiz, void* clazz, Cell::Visitor&); - }; - static Ref create(Heap&, size_t size, Vtable); - - void* foreign_data() SWIFT_RETURNS_INDEPENDENT_VALUE; // technically lying to swift, but it's fiiiiine - - // ^Cell - virtual void finalize() override; - virtual void visit_edges(Cell::Visitor& visitor) override; - virtual StringView class_name() const override { return m_vtable.class_name; } - - ~ForeignCell(); - -private: - ForeignCell(Vtable vtable); - - Vtable m_vtable; -} SWIFT_IMMORTAL_REFERENCE; - -template -struct ForeignRef { - friend struct ForeignPtr; - - template - static ForeignRef allocate(Heap& heap, Args... args) - { - DeferGC const defer_gc(heap); - auto* cell = T::create(&heap, forward(args)...); - if constexpr (IsSame) { - return ForeignRef(*as(cell)); - } else { - static_assert(IsSame); - auto* cast_cell = static_cast(cell); - return ForeignRef(*as(cast_cell)); - } - } - - ForeignRef() = delete; - - // This constructor should only be called directly after allocating a foreign cell by calling an FFI create method - ForeignRef(ForeignCell& cell) - : m_cell(cell) - { - // FIXME: This is super dangerous. How can we assert that the cell is actually a T? - m_data = static_cast(m_cell->foreign_data()); - } - - ~ForeignRef() = default; - ForeignRef(ForeignRef const& other) = default; - ForeignRef& operator=(ForeignRef const& other) = default; - - RETURNS_NONNULL T* operator->() const { return m_data; } - [[nodiscard]] T& operator*() const { return *m_data; } - - RETURNS_NONNULL T* ptr() const { return m_data; } - RETURNS_NONNULL operator T*() const { return m_data; } - - operator T&() const { return *m_data; } - - Ref cell() const { return m_cell; } - - void visit_edges(Cell::Visitor& visitor) - { - visitor.visit(m_cell); - } - -private: - Ref m_cell; - T* m_data { nullptr }; -}; - -template -struct ForeignPtr { - constexpr ForeignPtr() = default; - - // This constructor should only be called directly after allocating a foreign cell by calling an FFI create method - ForeignPtr(ForeignCell& cell) - : m_cell(&cell) - { - // FIXME: This is super dangerous. How can we assert that the cell is actually a T? - m_data = static_cast(m_cell->foreign_data()); - } - - // This constructor should only be called directly after allocating a foreign cell by calling an FFI create method - ForeignPtr(ForeignCell* cell) - : m_cell(cell) - { - // FIXME: This is super dangerous. How can we assert that the cell is actually a T? - m_data = m_cell ? static_cast(m_cell->foreign_data()) : nullptr; - } - - ForeignPtr(ForeignRef const& other) - : m_cell(other.m_cell) - , m_data(other.m_data) - { - } - - ForeignPtr(nullptr_t) - : m_cell(nullptr) - { - } - - ForeignPtr(ForeignPtr const& other) = default; - ForeignPtr& operator=(ForeignPtr const& other) = default; - - T* operator->() const - { - ASSERT(m_cell && m_data); - return m_data; - } - - [[nodiscard]] T& operator*() const - { - ASSERT(m_cell && m_data); - return *m_data; - } - - operator T*() const { return m_data; } - T* ptr() const { return m_data; } - - explicit operator bool() const { return !!m_cell; } - bool operator!() const { return !m_cell; } - - Ptr cell() const { return m_cell; } - - void visit_edges(Cell::Visitor& visitor) - { - visitor.visit(m_cell); - } - -private: - Ptr m_cell; - T* m_data { nullptr }; -}; - -} diff --git a/Libraries/LibGC/Forward.h b/Libraries/LibGC/Forward.h index c81288ba2c..3d6345121c 100644 --- a/Libraries/LibGC/Forward.h +++ b/Libraries/LibGC/Forward.h @@ -14,7 +14,6 @@ namespace GC { class Cell; class CellAllocator; class DeferGC; -class ForeignCell; class RootImpl; class Heap; class HeapBlock; diff --git a/Libraries/LibGC/Heap+Swift.swift b/Libraries/LibGC/Heap+Swift.swift deleted file mode 100644 index e48f8b0af1..0000000000 --- a/Libraries/LibGC/Heap+Swift.swift +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -import AK -@_exported import GCCxx - -extension GC.Heap { - public func withDeferredGC(_ body: () throws(E) -> R) throws(E) -> R { - let deferredRAII = GC.DeferGC(self) - _ = deferredRAII - return try body() - } -} - -public protocol HeapAllocatable { - static func allocate(on heap: GC.Heap) -> UnsafeMutablePointer - - init(cell: GC.Cell) - - func finalize() - func visitEdges(_ visitor: GC.Cell.Visitor) - - var cell: GC.Cell { get } -} - -// Here be dragons - -func asTypeMetadataPointer(_ type: Any.Type) -> UnsafeMutableRawPointer { - unsafeBitCast(type, to: UnsafeMutableRawPointer.self) -} - -func asHeapAllocatableType(_ typeMetadata: UnsafeMutableRawPointer) -> any HeapAllocatable.Type { - let typeObject = unsafeBitCast(typeMetadata, to: Any.Type.self) - guard let type = typeObject as? any HeapAllocatable.Type else { - fatalError("Passed foreign class but it wasn't a Swift type!") - } - return type -} - -extension HeapAllocatable { - fileprivate static func initializeFromFFI(at this: UnsafeMutableRawPointer, cell: GC.Cell) { - this.assumingMemoryBound(to: Self.self).initialize(to: Self.self.init(cell: cell)) - } - - fileprivate static func destroyFromFFI(at this: UnsafeMutableRawPointer) { - this.assumingMemoryBound(to: Self.self).deinitialize(count: 1) - } - - fileprivate static func finalizeFromFFI(at this: UnsafeMutableRawPointer) { - this.assumingMemoryBound(to: Self.self).pointee.finalize() - } - - fileprivate static func visitEdgesFromFFI(at this: UnsafeMutableRawPointer, visitor: GC.Cell.Visitor) { - this.assumingMemoryBound(to: Self.self).pointee.visitEdges(visitor) - } - - public static func allocate(on heap: GC.Heap) -> UnsafeMutablePointer { - let vtable = GC.ForeignCell.Vtable( - class_metadata_pointer: asTypeMetadataPointer(Self.self), - class_name: AK.String(swiftString: Swift.String(describing: Self.self)), - alignment: MemoryLayout.alignment, - initialize: { this, typeMetadata, cell in - asHeapAllocatableType(typeMetadata!).initializeFromFFI(at: this!, cell: cell.ptr()) - }, - destroy: { this, typeMetadata in - asHeapAllocatableType(typeMetadata!).destroyFromFFI(at: this!) - }, - finalize: { this, typeMetadata in - asHeapAllocatableType(typeMetadata!).finalizeFromFFI(at: this!) - }, - visit_edges: nil - ) - let cell = GC.ForeignCell.create(heap, MemoryLayout.stride, vtable) - return cell.pointee.foreign_data().assumingMemoryBound(to: Self.self) - } - - public func finalize() {} - public func visitEdges(_ visitor: GC.Cell.Visitor) {} -} diff --git a/Libraries/LibGC/Heap.h b/Libraries/LibGC/Heap.h index 7c683a7d21..920da2d1f0 100644 --- a/Libraries/LibGC/Heap.h +++ b/Libraries/LibGC/Heap.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -90,7 +89,6 @@ private: friend class MarkingVisitor; friend class GraphConstructorVisitor; friend class DeferGC; - friend class ForeignCell; void defer_gc(); void undefer_gc(); @@ -179,7 +177,7 @@ private: WeakBlock::List m_usable_weak_blocks; WeakBlock::List m_full_weak_blocks; -} SWIFT_IMMORTAL_REFERENCE; +}; inline void Heap::did_create_root(Badge, RootImpl& impl) { diff --git a/Libraries/LibGfx/CMakeLists.txt b/Libraries/LibGfx/CMakeLists.txt index 109366736c..23e09a2623 100644 --- a/Libraries/LibGfx/CMakeLists.txt +++ b/Libraries/LibGfx/CMakeLists.txt @@ -61,14 +61,6 @@ set(SOURCES YUVData.cpp ) -set(SWIFT_EXCLUDE_HEADERS - FilterImpl.h - GlobalFontConfig.h - MetalContext.h - VulkanContext.h - SkiaUtils.h -) - if (APPLE) list(APPEND SOURCES MetalContext.mm) endif() @@ -157,15 +149,6 @@ else() target_link_libraries(LibGfx PRIVATE libjxl::libjxl hwy::hwy) endif() -if (ENABLE_SWIFT) - generate_clang_module_map(LibGfx GENERATED_FILES ${generated_headers} EXCLUDE_FILES ${SWIFT_EXCLUDE_HEADERS}) - target_sources(LibGfx PRIVATE - Color.swift - ) - target_link_libraries(LibGfx PRIVATE AK) - add_swift_target_properties(LibGfx LAGOM_LIBRARIES AK) -endif() - if (APPLE) target_link_libraries(LibCore PUBLIC "-framework Metal") target_link_libraries(LibCore PUBLIC "-framework Accelerate") diff --git a/Libraries/LibGfx/Color.cpp b/Libraries/LibGfx/Color.cpp index 089d9ce604..4249bd77b4 100644 --- a/Libraries/LibGfx/Color.cpp +++ b/Libraries/LibGfx/Color.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -19,10 +18,6 @@ #include #include -#ifdef LIBGFX_USE_SWIFT -# include -#endif - namespace Gfx { namespace { @@ -355,15 +350,6 @@ Optional Color::from_named_css_color_string(StringView string) return {}; } -#if defined(LIBGFX_USE_SWIFT) -static Optional hex_string_to_color(StringView string) -{ - auto color = parseHexString(string); - if (color.getCount() == 0) - return {}; - return color[0]; -} -#else static Optional hex_string_to_color(StringView string) { auto hex_nibble_to_u8 = [](char nibble) -> Optional { @@ -414,7 +400,6 @@ static Optional hex_string_to_color(StringView string) return Color(r.value(), g.value(), b.value(), a.value()); } -#endif Optional Color::from_string(StringView string) { diff --git a/Libraries/LibGfx/Color.swift b/Libraries/LibGfx/Color.swift deleted file mode 100644 index 638e12a77b..0000000000 --- a/Libraries/LibGfx/Color.swift +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -import AK -@_exported import GfxCxx - -// FIXME: Do this without extending String with an index operation that was explicitly deleted :^) -extension Swift.String { - subscript(_ index: Int) -> Character { - return self[self.index(self.startIndex, offsetBy: index)] - } -} - -private func hexNibbleToUInt8(_ nibble: Character) -> UInt8? { - guard nibble.isHexDigit else { - return nil - } - return UInt8(nibble.hexDigitValue!) -} - -private func hexNibblesToUInt8(_ nib1: Character, _ nib2: Character) -> UInt8? { - guard let n1 = hexNibbleToUInt8(nib1) else { - return nil - } - guard let n2 = hexNibbleToUInt8(nib2) else { - return nil - } - return n1 << 4 | n2 -} - -// FIXME: Return Gfx.Color? When swift ABI bug is fixed -public func parseHexString(_ rawString: AK.StringView) -> [Gfx.Color] { - guard let string = Swift.String(akStringView: rawString) else { - return [] - } - - assert(string.hasPrefix("#")) - - switch string.count { - case 4: - let r = hexNibbleToUInt8(string[1]) - let g = hexNibbleToUInt8(string[2]) - let b = hexNibbleToUInt8(string[3]) - - guard r != nil && g != nil && b != nil else { - return [] - } - - return [Gfx.Color(r! * 17, g! * 17, b! * 17)] - case 5: - let r = hexNibbleToUInt8(string[1]) - let g = hexNibbleToUInt8(string[2]) - let b = hexNibbleToUInt8(string[3]) - let a = hexNibbleToUInt8(string[4]) - - guard r != nil && g != nil && b != nil && a != nil else { - return [] - } - - return [Gfx.Color(r! * 17, g! * 17, b! * 17, a! * 17)] - case 6: return [] - case 7: - let r = hexNibblesToUInt8(string[1], string[2]) - let g = hexNibblesToUInt8(string[3], string[4]) - let b = hexNibblesToUInt8(string[5], string[6]) - - guard r != nil && g != nil && b != nil else { - return [] - } - - return [Gfx.Color(r!, g!, b!, UInt8(255))] - case 8: return [] - case 9: - let r = hexNibblesToUInt8(string[1], string[2]) - let g = hexNibblesToUInt8(string[3], string[4]) - let b = hexNibblesToUInt8(string[5], string[6]) - let a = hexNibblesToUInt8(string[7], string[8]) - - guard r != nil && g != nil && b != nil && a != nil else { - return [] - } - - return [Gfx.Color(r!, g!, b!, a!)] - default: return [] - } -} diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 4e2f302691..2c76120683 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -1210,23 +1210,3 @@ target_link_libraries(LibWeb PRIVATE LibCore LibCompress LibCrypto LibJS LibHTTP target_include_directories(LibWeb PRIVATE ${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include) generate_js_bindings(LibWeb) - -if (ENABLE_SWIFT) - include(collections) - - set(generated_headers ${GENERATED_SOURCES}) - list(FILTER generated_headers INCLUDE REGEX "\\.h$") - list(TRANSFORM generated_headers PREPEND "${CMAKE_CURRENT_BINARY_DIR}/") - list(APPEND LIBWEB_ALL_GENERATED_HEADERS ${generated_headers}) - - generate_clang_module_map(LibWeb GENERATED_FILES ${LIBWEB_ALL_GENERATED_HEADERS}) - - target_sources(LibWeb PRIVATE - HTML/Parser/HTMLToken.swift - HTML/Parser/HTMLTokenizer.swift - HTML/Parser/HTMLTokenizerHelpers.cpp - HTML/Parser/SpeculativeHTMLParser.swift - ) - target_link_libraries(LibWeb PRIVATE AK Collections) - add_swift_target_properties(LibWeb LAGOM_LIBRARIES AK LibGfx LibGC) -endif() diff --git a/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp b/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp index c1c7c20380..0fe2a40c03 100644 --- a/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp +++ b/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp @@ -51,10 +51,6 @@ #include #include -#ifdef LIBWEB_USE_SWIFT -# include -#endif - namespace Web::HTML { GC_DEFINE_ALLOCATOR(HTMLParser); @@ -205,10 +201,6 @@ void HTMLParser::visit_edges(Cell::Visitor& visitor) void HTMLParser::initialize(JS::Realm& realm) { Base::initialize(realm); - -#if defined(LIBWEB_USE_SWIFT) - m_speculative_parser = GC::ForeignRef::allocate(realm.heap(), this); -#endif } void HTMLParser::run(HTMLTokenizer::StopAtInsertionPoint stop_at_insertion_point) diff --git a/Libraries/LibWeb/HTML/Parser/HTMLParser.h b/Libraries/LibWeb/HTML/Parser/HTMLParser.h index b61ec44b18..b49ffdea72 100644 --- a/Libraries/LibWeb/HTML/Parser/HTMLParser.h +++ b/Libraries/LibWeb/HTML/Parser/HTMLParser.h @@ -15,16 +15,6 @@ #include #include -#ifdef LIBWEB_USE_SWIFT -# include - -namespace Web { - -class SpeculativeHTMLParser; - -} -#endif - namespace Web::HTML { #define ENUMERATE_INSERTION_MODES \ @@ -221,22 +211,14 @@ private: GC::Ptr m_form_element; GC::Ptr m_context_element; -#ifdef LIBWEB_USE_SWIFT - GC::ForeignPtr m_speculative_parser; -#endif - Vector m_pending_table_character_tokens; GC::Ptr m_character_insertion_node; StringBuilder m_character_insertion_builder { StringBuilder::Mode::UTF16 }; -} SWIFT_UNSAFE_REFERENCE; +}; RefPtr parse_dimension_value(StringView); RefPtr parse_nonzero_dimension_value(StringView); Optional parse_legacy_color_value(StringView); -// Swift interop -using HTMLParserGCPtr = GC::Ptr; -using HTMLParserGCRef = GC::Ref; - } diff --git a/Libraries/LibWeb/HTML/Parser/HTMLToken.swift b/Libraries/LibWeb/HTML/Parser/HTMLToken.swift deleted file mode 100644 index 2188673823..0000000000 --- a/Libraries/LibWeb/HTML/Parser/HTMLToken.swift +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -@_exported import WebCxx - -public class HTMLToken { - public struct Position: Equatable { - var line = UInt() - var column = UInt() - var byteOffset = UInt() - } - - public struct Attribute: Equatable { - public var prefix: Swift.String? = nil - public var localName: Swift.String - public var namespace_: Swift.String? = nil - public var value: Swift.String - public var nameStartPosition = Position() - public var nameEndPosition = Position() - public var valueStartPosition = Position() - public var valueEndPosition = Position() - - public init(localName: Swift.String, value: Swift.String) { - self.localName = localName - self.value = value - } - } - - public enum TokenType: Equatable { - case Invalid - case DOCTYPE( - name: Swift.String?, - publicIdentifier: Swift.String?, - systemIdentifier: Swift.String?, - forceQuirksMode: Bool) - case StartTag( - tagName: Swift.String, - selfClosing: Bool = false, - selfClosingAcknowledged: Bool = false, - attributes: [Attribute] = []) - case EndTag( - tagName: Swift.String, - selfClosing: Bool = false, - selfClosingAcknowledged: Bool = false, - attributes: [Attribute] = []) - case Comment(data: Swift.String) - case Character(codePoint: Character) - case EndOfFile - } - - public func isCharacter() -> Bool { - if case .Character(_) = self.type { - return true - } - return false - } - - public func isEndTag() -> Bool { - if case .EndTag(_, _, _, _) = self.type { - return true - } - return false - } - - public func isStartTag() -> Bool { - if case .StartTag(_, _, _, _) = self.type { - return true - } - return false - } - - public func isTag() -> Bool { - return isStartTag() || isEndTag() - } - - public func isParserWhitespace() -> Bool { - precondition(isCharacter(), "isParserWhitespace() called on non-character token") - - // NOTE: The parser considers '\r' to be whitespace, while the tokenizer does not. - switch self.type { - case .Character(codePoint: "\t"), - .Character(codePoint: "\n"), - .Character(codePoint: "\u{000C}"), // \f - .Character(codePoint: "\r"), - .Character(codePoint: " "): - return true - default: - return false - } - } - - public var type = TokenType.Invalid - public var startPosition = Position() - public var endPosition = Position() - - // Is in-place mutating enums a thing? Seems not https://forums.swift.org/t/in-place-mutation-of-an-enum-associated-value/11747 - public var attributes: [Attribute] { - get { - switch self.type { - case .StartTag(_, _, _, let attributes): - return attributes - case .EndTag(_, _, _, let attributes): - return attributes - default: - preconditionFailure("attributes called on non-tag token") - } - } - set { - switch self.type { - case .StartTag(let tagName, let selfClosing, let selfClosingAcknowledged, attributes: _): - self.type = .StartTag(tagName: tagName, selfClosing: selfClosing, selfClosingAcknowledged: selfClosingAcknowledged, attributes: newValue) - case .EndTag(let tagName, let selfClosing, let selfClosingAcknowledged, attributes: _): - self.type = .EndTag(tagName: tagName, selfClosing: selfClosing, selfClosingAcknowledged: selfClosingAcknowledged, attributes: newValue) - default: - preconditionFailure("attributes= called on non-tag token") - } - } - } - public var tagName: Swift.String { - get { - switch self.type { - case .StartTag(let tagName, _, _, _): - return tagName - case .EndTag(let tagName, _, _, _): - return tagName - default: - preconditionFailure("tagName called on non-tag token") - } - } - set { - switch self.type { - case .StartTag(tagName: _, let selfClosing, let selfClosingAcknowledged, let attributes): - self.type = .StartTag(tagName: newValue, selfClosing: selfClosing, selfClosingAcknowledged: selfClosingAcknowledged, attributes: attributes) - case .EndTag(tagName: _, let selfClosing, let selfClosingAcknowledged, let attributes): - self.type = .EndTag(tagName: newValue, selfClosing: selfClosing, selfClosingAcknowledged: selfClosingAcknowledged, attributes: attributes) - default: - preconditionFailure("tagName= called on non-tag token") - } - } - } - public var selfClosing: Bool { - get { - switch self.type { - case .StartTag(_, let selfClosing, _, _): - return selfClosing - case .EndTag(_, let selfClosing, _, _): - return selfClosing - default: - preconditionFailure("selfClosing called on non-tag token") - } - } - set { - switch self.type { - case .StartTag(let tagName, _, let selfClosingAcknowledged, let attributes): - self.type = .StartTag(tagName: tagName, selfClosing: newValue, selfClosingAcknowledged: selfClosingAcknowledged, attributes: attributes) - case .EndTag(let tagName, _, let selfClosingAcknowledged, let attributes): - self.type = .EndTag(tagName: tagName, selfClosing: newValue, selfClosingAcknowledged: selfClosingAcknowledged, attributes: attributes) - default: - preconditionFailure("selfClosing= called on non-tag token") - } - } - } - public var name: Swift.String? { - get { - switch self.type { - case .DOCTYPE(let name, _, _, _): - return name - default: - preconditionFailure("doctypeName called on non-doctype token") - } - } - set { - switch self.type { - case .DOCTYPE(_, let publicIdentifier, let systemIdentifier, let forceQuirksMode): - self.type = .DOCTYPE(name: newValue, publicIdentifier: publicIdentifier, systemIdentifier: systemIdentifier, forceQuirksMode: forceQuirksMode) - default: - preconditionFailure("doctypeName= called on non-doctype token") - } - } - } - - public var forceQuirks: Bool { - get { - switch self.type { - case .DOCTYPE(_, _, _, let forceQuirksMode): - return forceQuirksMode - default: - preconditionFailure("forceQuirks called on non-doctype token") - } - } - set { - switch self.type { - case .DOCTYPE(let name, let publicIdentifier, let systemIdentifier, _): - self.type = .DOCTYPE(name: name, publicIdentifier: publicIdentifier, systemIdentifier: systemIdentifier, forceQuirksMode: newValue) - default: - preconditionFailure("forceQuirks= called on non-doctype token") - } - } - } - - public var publicIdentifier: Swift.String? { - get { - switch self.type { - case .DOCTYPE(_, let publicIdentifier, _, _): - return publicIdentifier - default: - preconditionFailure("publicIdentifier called on non-doctype token") - } - } - set { - switch self.type { - case .DOCTYPE(let name, _, let systemIdentifier, let forceQuirksMode): - self.type = .DOCTYPE(name: name, publicIdentifier: newValue, systemIdentifier: systemIdentifier, forceQuirksMode: forceQuirksMode) - default: - preconditionFailure("publicIdentifier= called on non-doctype token") - } - } - } - - public var systemIdentifier: Swift.String? { - get { - switch self.type { - case .DOCTYPE(_, _, let systemIdentifier, _): - return systemIdentifier - default: - preconditionFailure("systemIdentifier called on non-doctype token") - } - } - set { - switch self.type { - case .DOCTYPE(let name, let publicIdentifier, _, let forceQuirksMode): - self.type = .DOCTYPE(name: name, publicIdentifier: publicIdentifier, systemIdentifier: newValue, forceQuirksMode: forceQuirksMode) - default: - preconditionFailure("systemIdentifier= called on non-doctype token") - } - } - } - - public init() {} - public init(type: TokenType) { - self.type = type - } -} - -extension HTMLToken.Position: CustomStringConvertible { - public var description: Swift.String { - return "\(self.line):\(self.column)" - } -} - -extension HTMLToken.TokenType: CustomStringConvertible { - // FIXME: Print attributes for start/end tags - public var description: Swift.String { - switch self { - case .Invalid: - return "Invalid" - case .DOCTYPE(let name, let publicIdentifier, let systemIdentifier, let forceQuirksMode): - return "DOCTYPE(name: \(name ?? "nil"), publicIdentifier: \(publicIdentifier ?? "nil"), systemIdentifier: \(systemIdentifier ?? "nil"), forceQuirksMode: \(forceQuirksMode))" - case .StartTag(let tagName, let selfClosing, let selfClosingAcknowledged, let attributes): - return "StartTag(tagName: \(tagName), selfClosing: \(selfClosing), selfClosingAcknowledged: \(selfClosingAcknowledged), attributes: \(attributes))" - case .EndTag(let tagName, let selfClosing, let selfClosingAcknowledged, let attributes): - return "EndTag(tagName: \(tagName), selfClosing: \(selfClosing), selfClosingAcknowledged: \(selfClosingAcknowledged), attributes: \(attributes))" - case .Comment(let data): - return "Comment(data: \(data))" - case .Character(let codePoint): - return "Character(codePoint: \(codePoint))" - case .EndOfFile: - return "EndOfFile" - } - } -} - -extension HTMLToken: CustomStringConvertible { - public var description: Swift.String { - if self.startPosition == Position() { - return "HTMLToken(type: \(self.type))" - } else if self.endPosition == Position() { - return "HTMLToken(type: \(self.type))@\(self.startPosition)" - } else { - return "HTMLToken(type: \(self.type))@\(self.startPosition)-\(self.endPosition)" - } - } -} diff --git a/Libraries/LibWeb/HTML/Parser/HTMLTokenizer.swift b/Libraries/LibWeb/HTML/Parser/HTMLTokenizer.swift deleted file mode 100644 index 99370b1495..0000000000 --- a/Libraries/LibWeb/HTML/Parser/HTMLTokenizer.swift +++ /dev/null @@ -1,1928 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -import AK -import Collections -import Foundation -@_exported import WebCxx - -extension Swift.String { - public init?(decoding: AK.StringView, as: AK.StringView) { - let maybe_decoded = Web.HTML.decode_to_utf8(decoding, `as`) - if maybe_decoded.hasValue { - self.init(akString: maybe_decoded.value!) - } else { - return nil - } - } - - public mutating func takeString() -> Swift.String { - let result = self - self = "" - return result - } -} - -public class HTMLTokenizer { - - public enum State { - case Data - case RCDATA - case RAWTEXT - case ScriptData - case PLAINTEXT - case TagOpen - case EndTagOpen - case TagName - case RCDATALessThanSign - case RCDATAEndTagOpen - case RCDATAEndTagName - case RAWTEXTLessThanSign - case RAWTEXTEndTagOpen - case RAWTEXTEndTagName - case ScriptDataLessThanSign - case ScriptDataEndTagOpen - case ScriptDataEndTagName - case ScriptDataEscapeStart - case ScriptDataEscapeStartDash - case ScriptDataEscaped - case ScriptDataEscapedDash - case ScriptDataEscapedDashDash - case ScriptDataEscapedLessThanSign - case ScriptDataEscapedEndTagOpen - case ScriptDataEscapedEndTagName - case ScriptDataDoubleEscapeStart - case ScriptDataDoubleEscaped - case ScriptDataDoubleEscapedDash - case ScriptDataDoubleEscapedDashDash - case ScriptDataDoubleEscapedLessThanSign - case ScriptDataDoubleEscapeEnd - case BeforeAttributeName - case AttributeName - case AfterAttributeName - case BeforeAttributeValue - case AttributeValueDoubleQuoted - case AttributeValueSingleQuoted - case AttributeValueUnquoted - case AfterAttributeValueQuoted - case SelfClosingStartTag - case BogusComment - case MarkupDeclarationOpen - case CommentStart - case CommentStartDash - case Comment - case CommentLessThanSign - case CommentLessThanSignBang - case CommentLessThanSignBangDash - case CommentLessThanSignBangDashDash - case CommentEndDash - case CommentEnd - case CommentEndBang - case DOCTYPE - case BeforeDOCTYPEName - case DOCTYPEName - case AfterDOCTYPEName - case AfterDOCTYPEPublicKeyword - case BeforeDOCTYPEPublicIdentifier - case DOCTYPEPublicIdentifierDoubleQuoted - case DOCTYPEPublicIdentifierSingleQuoted - case AfterDOCTYPEPublicIdentifier - case BetweenDOCTYPEPublicAndSystemIdentifiers - case AfterDOCTYPESystemKeyword - case BeforeDOCTYPESystemIdentifier - case DOCTYPESystemIdentifierDoubleQuoted - case DOCTYPESystemIdentifierSingleQuoted - case AfterDOCTYPESystemIdentifier - case BogusDOCTYPE - case CDATASection - case CDATASectionBracket - case CDATASectionEnd - case CharacterReference - case NamedCharacterReference - case AmbiguousAmpersand - case NumericCharacterReference - case HexadecimalCharacterReferenceStart - case DecimalCharacterReferenceStart - case HexadecimalCharacterReference - case DecimalCharacterReference - case NumericCharacterReferenceEnd - } - - private var input = Swift.String() - private var cursor: Swift.String.Index - private var previousCursor: Swift.String.Index - - public private(set) var state = State.Data - private var returnState = State.Data - - private var currentToken = HTMLToken() - private var queuedTokens = Deque() - - private var currentBuilder = Swift.String() - private var temporaryBuffer = Swift.String() - private var lastStartTagName: Swift.String? = nil - private var currentTokensAttributes: [HTMLToken.Attribute]? = nil - private var currentAttribute: HTMLToken.Attribute? = nil - private var characterReferenceCode: Int = 0 - - private var aborted = false - private var hasEmittedEOF = false - - // https://infra.spec.whatwg.org/#noncharacter - // A noncharacter is a code point that is in the range U+FDD0 to U+FDEF, inclusive, - // or U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFFE, U+2FFFF, U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, - // U+5FFFE, U+5FFFF, U+6FFFE, U+6FFFF, U+7FFFE, U+7FFFF, U+8FFFE, U+8FFFF, U+9FFFE, U+9FFFF, - // U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF, U+CFFFE, U+CFFFF, U+DFFFE, U+DFFFF, U+EFFFE, U+EFFFF, - // U+FFFFE, U+FFFFF, U+10FFFE, or U+10FFFF. - static private var nonCharacter = CharacterSet(charactersIn: Unicode.Scalar(0xFDD0)!...Unicode.Scalar(0xFDEF)!) - .union(CharacterSet(charactersIn: "\u{FFFE}"..."\u{FFFF}")) - .union(CharacterSet(charactersIn: "\u{1FFFE}"..."\u{1FFFF}")) - .union(CharacterSet(charactersIn: "\u{2FFFE}"..."\u{2FFFF}")) - .union(CharacterSet(charactersIn: "\u{3FFFE}"..."\u{3FFFF}")) - .union(CharacterSet(charactersIn: "\u{4FFFE}"..."\u{4FFFF}")) - .union(CharacterSet(charactersIn: "\u{5FFFE}"..."\u{5FFFF}")) - .union(CharacterSet(charactersIn: "\u{6FFFE}"..."\u{6FFFF}")) - .union(CharacterSet(charactersIn: "\u{7FFFE}"..."\u{7FFFF}")) - .union(CharacterSet(charactersIn: "\u{8FFFE}"..."\u{8FFFF}")) - .union(CharacterSet(charactersIn: "\u{9FFFE}"..."\u{9FFFF}")) - .union(CharacterSet(charactersIn: "\u{AFFFE}"..."\u{AFFFF}")) - .union(CharacterSet(charactersIn: "\u{BFFFE}"..."\u{BFFFF}")) - .union(CharacterSet(charactersIn: "\u{CFFFE}"..."\u{CFFFF}")) - .union(CharacterSet(charactersIn: "\u{DFFFE}"..."\u{DFFFF}")) - .union(CharacterSet(charactersIn: "\u{EFFFE}"..."\u{EFFFF}")) - .union(CharacterSet(charactersIn: "\u{FFFFE}"..."\u{FFFFF}")) - .union(CharacterSet(charactersIn: "\u{10FFFE}"..."\u{10FFFF}")) - - // https://infra.spec.whatwg.org/#ascii-whitespace - static private var asciiWhitespace = CharacterSet(charactersIn: "\t\n\u{000C}\u{000D} ") - - // https://infra.spec.whatwg.org/#c0-control - static private var c0Control = CharacterSet(charactersIn: "\u{0000}"..."\u{001F}") - - // https://infra.spec.whatwg.org/#control - static private var control = c0Control.union(CharacterSet(charactersIn: "\u{007F}"..."\u{009F}")) - - // IMPLEMENTATION DEFINED: Used for the numeric character reference end state - static private var controlNotAsciiWhitespace = control.subtracting(asciiWhitespace) - - // https://infra.spec.whatwg.org/#ascii-digit - static private var asciiDigit = CharacterSet(charactersIn: "0123456789") - - // https://infra.spec.whatwg.org/#ascii-upper-hex-digit - static private var asciiUpperHexDigit = CharacterSet(charactersIn: "ABCDEF") - - // https://infra.spec.whatwg.org/#ascii-lower-hex-digit - static private var asciiLowerHexDigit = CharacterSet(charactersIn: "abcdef") - - // https://infra.spec.whatwg.org/#ascii-hex-digit - static private var asciiHexDigit = asciiUpperHexDigit.union(asciiLowerHexDigit) - - // https://infra.spec.whatwg.org/#ascii-upper-alpha - static private var asciiUpperAlpha = CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZ") - - // https://infra.spec.whatwg.org/#ascii-lower-alpha - static private var asciiLowerAlpha = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyz") - - // https://infra.spec.whatwg.org/#ascii-upper-alpha - static private var asciiAlpha = asciiUpperAlpha.union(asciiLowerAlpha) - - // https://infra.spec.whatwg.org/#ascii-alphanumeric - static private var asciiAlphanumeric = asciiAlpha.union(asciiDigit) - - static private var characterReferenceControlCodeMapping: [Int: Unicode.Scalar] = - [ - 0x80: Unicode.Scalar(0x20AC)!, // € - 0x82: Unicode.Scalar(0x201A)!, // ‚ - 0x83: Unicode.Scalar(0x0192)!, // ƒ - 0x84: Unicode.Scalar(0x201E)!, // „ - 0x85: Unicode.Scalar(0x2026)!, // … - 0x86: Unicode.Scalar(0x2020)!, // † - 0x87: Unicode.Scalar(0x2021)!, // ‡ - 0x88: Unicode.Scalar(0x02C6)!, // ˆ - 0x89: Unicode.Scalar(0x2030)!, // ‰ - 0x8A: Unicode.Scalar(0x0160)!, // Š - 0x8B: Unicode.Scalar(0x2039)!, // ‹ - 0x8C: Unicode.Scalar(0x0152)!, // Œ - 0x8E: Unicode.Scalar(0x017D)!, // Ž - 0x91: Unicode.Scalar(0x2018)!, // ‘ - 0x92: Unicode.Scalar(0x2019)!, // ’ - 0x93: Unicode.Scalar(0x201C)!, // “ - 0x94: Unicode.Scalar(0x201D)!, // ” - 0x95: Unicode.Scalar(0x2022)!, // • - 0x96: Unicode.Scalar(0x2013)!, // – - 0x97: Unicode.Scalar(0x2014)!, // — - 0x98: Unicode.Scalar(0x02DC)!, // ˜ - 0x99: Unicode.Scalar(0x2122)!, // ™ - 0x9A: Unicode.Scalar(0x0161)!, // š - 0x9B: Unicode.Scalar(0x203A)!, // › - 0x9C: Unicode.Scalar(0x0153)!, // œ - 0x9E: Unicode.Scalar(0x017E)!, // ž - 0x9F: Unicode.Scalar(0x0178)!, // Ÿ - ] - - public init() { - self.cursor = self.input.startIndex - self.previousCursor = self.input.startIndex - } - public init?(input: AK.StringView, encoding: AK.StringView) { - if let string = Swift.String(decoding: input, as: encoding) { - self.input = string - } else { - return nil - } - self.cursor = self.input.startIndex - self.previousCursor = self.input.startIndex - } - - public convenience init?(input: AK.StringView) { - self.init(input: input, encoding: "UTF-8") - } - - public func abort() { - self.aborted = true - } - - func skip(_ count: Int) { - self.previousCursor = self.cursor - self.cursor = self.input.index(self.cursor, offsetBy: count, limitedBy: self.input.endIndex) ?? input.endIndex - } - - func peekCodePoint(_ offset: Int = 0) -> Character? { - guard let index = self.input.index(self.cursor, offsetBy: offset, limitedBy: self.input.index(before: self.input.endIndex)) else { - return nil - } - return self.input[index] - } - - func peekNext(count: Int) -> Swift.Substring? { - guard let endIndex = self.input.index(self.cursor, offsetBy: count, limitedBy: self.input.index(before: self.input.endIndex)) else { - return nil - } - return self.input[self.cursor.. Character? { - guard self.cursor < self.input.endIndex else { - return nil - } - - // https://html.spec.whatwg.org/multipage/parsing.html#preprocessing-the-input-stream:tokenization - // https://infra.spec.whatwg.org/#normalize-newlines - var codePoint: Character - if let peeked = peekCodePoint(), let peekedNext = peekCodePoint(1), peeked == "\r", peekedNext == "\n" { - // replace every U+000D CR U+000A LF code point pair with a single U+000A LF code point, - skip(2) - codePoint = "\n" - } else if let peeked = peekCodePoint(), peeked == "\r" { - // replace every remaining U+000D CR code point with a U+000A LF code point. - skip(1) - codePoint = "\n" - } else { - skip(1) - codePoint = self.input[self.previousCursor] - } - return codePoint - } - - func restoreCursorToPrevious() { - self.cursor = self.previousCursor - } - - func createNewToken(_ token: HTMLToken) { - self.currentToken = token - if self.currentToken.isTag() { - self.currentTokensAttributes = [] - } - // FIXME: Assign Position - } - - enum AttributeStringBehavior { - case SetName - case SetValue - case IgnoreString - } - func finalizeCurrentAttribute(_ behavior: AttributeStringBehavior) { - precondition(self.currentAttribute != nil && self.currentTokensAttributes != nil) - switch behavior { - case .SetName: - self.currentAttribute!.localName = self.currentBuilder.takeString() - case .SetValue: - self.currentAttribute!.value = self.currentBuilder.takeString() - case .IgnoreString: - _ = self.currentBuilder.takeString() - } - self.currentTokensAttributes!.append(self.currentAttribute!) - self.currentAttribute = nil - } - - enum NextTokenState { - case Emit(token: HTMLToken?) - case SwitchTo - case Reconsume(inputCharacter: Character?) - case ReprocessQueue - case Continue - } - - public func nextToken(stopAtInsertionPoint: Bool = false) -> HTMLToken? { - - let processQueue = { () -> HTMLToken?? in - if let token = self.queuedTokens.popFirst() { - return token - } - return self.aborted ? Optional(nil) : nil - } - - if let maybeToken = processQueue() { - return maybeToken - } - - var nextInputCharacter: Character? = nil - while true { - // FIXME: Handle insertion point - switch nextTokenImpl(nextInputCharacter) { - case .Emit(let token): - return token - case .SwitchTo, .Continue: - nextInputCharacter = nil - break - case .Reconsume(let character): - nextInputCharacter = character - break - case .ReprocessQueue: - if let maybeToken = processQueue() { - return maybeToken - } - nextInputCharacter = nil - break - } - } - } - - func continueInCurrentState() -> NextTokenState { - return .Continue - } - - func switchTo(_ state: State) -> NextTokenState { - self.state = state - return .SwitchTo - } - - func reconsume(_ character: Character?, `in` state: State) -> NextTokenState { - self.state = state - return .Reconsume(inputCharacter: character) - } - - func switchToReturnState() -> NextTokenState { - self.state = self.returnState - return .ReprocessQueue - } - - func reconsumeInReturnState(_ character: Character?) -> NextTokenState { - self.state = self.returnState - if character != nil { - restoreCursorToPrevious() - } - return .ReprocessQueue - } - - func switchToAndEmitCurrentToken(_ state: State) -> NextTokenState { - self.state = state - if self.currentToken.isTag() { - self.currentToken.attributes = self.currentTokensAttributes ?? [] - self.currentTokensAttributes = nil - } - self.queuedTokens.append(self.currentToken) - self.currentToken = HTMLToken() - return .Emit(token: self.queuedTokens.popFirst()!) - } - - func switchToAndEmitCharacter(_ state: State, character: Character) -> NextTokenState { - self.state = state - return emitCharacter(character) - } - - func emitCharacterAndReconsume(_ character: Character, `in`: State, currentInputCharacter: Character?) -> NextTokenState { - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: character))) - self.state = `in` - return .Reconsume(inputCharacter: currentInputCharacter) - } - - func emitEOF() -> NextTokenState { - if self.hasEmittedEOF { - return .Emit(token: nil) - } - self.hasEmittedEOF = true - createNewToken(HTMLToken(type: .EndOfFile)) - self.queuedTokens.append(self.currentToken) - self.currentToken = HTMLToken() - return .Emit(token: self.queuedTokens.popFirst()!) - } - - func emitCurrentTokenFollowedByEOF() -> NextTokenState { - precondition(!self.hasEmittedEOF) - if self.currentToken.isTag() { - self.currentToken.attributes = self.currentTokensAttributes ?? [] - self.currentTokensAttributes = nil - } - self.queuedTokens.append(self.currentToken) - self.currentToken = HTMLToken() - return emitEOF() - } - - func emitCharacter(_ character: Character) -> NextTokenState { - createNewToken(HTMLToken(type: .Character(codePoint: character))) - self.queuedTokens.append(self.currentToken) - self.currentToken = HTMLToken() - return .Emit(token: self.queuedTokens.popFirst()!) - } - - func flushCodepointsConsumedAsACharacterReference() { - if consumedAsPartOfAnAttribute() { - self.currentBuilder += self.temporaryBuffer.takeString() - } else { - for codePoint in self.temporaryBuffer.takeString() { - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: codePoint))) - } - } - } - - func consumedAsPartOfAnAttribute() -> Bool { - return self.returnState == .AttributeValueDoubleQuoted || self.returnState == .AttributeValueSingleQuoted || self.returnState == .AttributeValueUnquoted - } - - func isAppropriateEndTagToken(_ token: HTMLToken) -> Bool { - guard case .EndTag(let endTagName, _, _, _) = token.type else { - preconditionFailure("isAppropriateEndTagToken called with non-end-tag token") - } - if let startTagName = self.lastStartTagName { - return startTagName == endTagName - } else { - return false - } - } - - func nextTokenImpl(_ nextInputCharacter: Character? = nil) -> NextTokenState { - let dontConsumeNextInputCharacter = { - self.restoreCursorToPrevious() - } - let _ = dontConsumeNextInputCharacter - - // Handle reconsume by passing the character around in the state enum - let currentInputCharacter = nextInputCharacter ?? nextCodePoint() - - switch self.state { - // 13.2.5.1 Data state, https://html.spec.whatwg.org/multipage/parsing.html#data-state - case .Data: - precondition(currentTokensAttributes == nil) - switch currentInputCharacter { - case "&": - self.returnState = .Data - return switchTo(.CharacterReference) - case "<": - return switchTo(.TagOpen) - case "\0": - // FIXME: log_parse_error() - return emitCharacter("\u{FFFD}") - case nil: - return emitEOF() - default: - return emitCharacter(currentInputCharacter!) - } - - // 13.2.5.2 RCDATA state, https://html.spec.whatwg.org/multipage/parsing.html#rcdata-state - case .RCDATA: - switch currentInputCharacter { - case "&": - self.returnState = .RCDATA - return switchTo(.CharacterReference) - case "<": - return switchTo(.RCDATALessThanSign) - case "\0": - // FIXME: log_parse_error() - return emitCharacter("\u{FFFD}") - case nil: - return emitEOF() - default: - return emitCharacter(currentInputCharacter!) - } - - // 13.2.5.3. RAWTEXT state, https://html.spec.whatwg.org/multipage/parsing.html#rawtext-state - case .RAWTEXT: - switch currentInputCharacter { - case "<": - return switchTo(.RAWTEXTLessThanSign) - case "\0": - // FIXME: log_parse_error() - return emitCharacter("\u{FFFD}") - case nil: - return emitEOF() - default: - return emitCharacter(currentInputCharacter!) - } - // 13.2.5.4 Script data state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-state - case .ScriptData: - switch currentInputCharacter { - case "<": - return switchTo(.ScriptDataLessThanSign) - case "\0": - // FIXME: log_parse_error() - return emitCharacter("\u{FFFD}") - case nil: - return emitEOF() - default: - return emitCharacter(currentInputCharacter!) - } - // 13.2.5.5 PLAINTEXT state, https://html.spec.whatwg.org/multipage/parsing.html#plaintext-state - case .PLAINTEXT: - switch currentInputCharacter { - case "\0": - // FIXME: log_parse_error() - return emitCharacter("\u{FFFD}") - case nil: - return emitEOF() - default: - return emitCharacter(currentInputCharacter!) - } - // 13.2.5.6 Tag open state https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state - case .TagOpen: - switch currentInputCharacter { - case "!": - return switchTo(.MarkupDeclarationOpen) - case "/": - return switchTo(.EndTagOpen) - case let c? where HTMLTokenizer.asciiAlpha.contains(c.unicodeScalars.first!): - createNewToken(HTMLToken(type: .StartTag(tagName: ""))) - return reconsume(currentInputCharacter!, in: .TagName) - case "?": - // FIXME: log_parse_error() - createNewToken(HTMLToken(type: .Comment(data: ""))) - return reconsume(currentInputCharacter!, in: .BogusComment) - case nil: - // FIXME: log_parse_error() - queuedTokens.append(HTMLToken(type: .Character(codePoint: "<"))) - return emitEOF() - default: - // FIXME: log_parse_error() - queuedTokens.append(HTMLToken(type: .Character(codePoint: "<"))) - return reconsume(currentInputCharacter!, in: .Data) - } - // 13.2.5.7 End tag open state, https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state - case .EndTagOpen: - switch currentInputCharacter { - case let c? where HTMLTokenizer.asciiAlpha.contains(c.unicodeScalars.first!): - createNewToken(HTMLToken(type: .EndTag(tagName: ""))) - return reconsume(currentInputCharacter!, in: .TagName) - default: - return emitEOF() - } - // 13.2.5.8 Tag name state, https://html.spec.whatwg.org/multipage/parsing.html#tag-name-state - case .TagName: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - self.currentToken.tagName = self.currentBuilder.takeString() - return switchTo(.BeforeAttributeName) - case "/": - self.currentToken.tagName = self.currentBuilder.takeString() - return switchTo(.SelfClosingStartTag) - case ">": - self.currentToken.tagName = self.currentBuilder.takeString() - return switchToAndEmitCurrentToken(.Data) - case let c? where HTMLTokenizer.asciiUpperAlpha.contains(c.unicodeScalars.first!): - currentBuilder.append(Character(Unicode.Scalar(c.asciiValue! + 0x20))) - return continueInCurrentState() - case "\0": - // FIXME: log_parse_error() - currentBuilder += "\u{FFFD}" - return continueInCurrentState() - case nil: - // FIXME: log_parse_error() - return emitEOF() - default: - currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - // 13.2.5.9 RCDATA less-than sign state, https://html.spec.whatwg.org/multipage/parsing.html#rcdata-less-than-sign-state - case .RCDATALessThanSign: - switch currentInputCharacter { - case "/": - self.temporaryBuffer = "" - return switchTo(.RCDATAEndTagOpen) - default: - return emitCharacterAndReconsume("<", in: .RCDATA, currentInputCharacter: currentInputCharacter) - } - // 13.2.5.10 RCDATA end tag open state, https://html.spec.whatwg.org/multipage/parsing.html#rcdata-end-tag-open-state - case .RCDATAEndTagOpen: - switch currentInputCharacter { - case let c? where HTMLTokenizer.asciiAlpha.contains(c.unicodeScalars.first!): - createNewToken(HTMLToken(type: .EndTag(tagName: ""))) - return reconsume(currentInputCharacter!, in: .RCDATAEndTagName) - default: - queuedTokens.append(HTMLToken(type: .Character(codePoint: "<"))) - queuedTokens.append(HTMLToken(type: .Character(codePoint: "/"))) - return reconsume(currentInputCharacter, in: .RCDATA) - } - // 13.2.5.11 RCDATA end tag name state, https://html.spec.whatwg.org/multipage/parsing.html#rcdata-end-tag-name-state - case .RCDATAEndTagName: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - if self.isAppropriateEndTagToken(currentToken) { - return switchTo(.BeforeAttributeName) - } - break - case "/": - if self.isAppropriateEndTagToken(currentToken) { - return switchTo(.SelfClosingStartTag) - } - break - case ">": - if self.isAppropriateEndTagToken(currentToken) { - return switchToAndEmitCurrentToken(.Data) - } - break - case let c? where HTMLTokenizer.asciiUpperAlpha.contains(c.unicodeScalars.first!): - self.currentBuilder.append(Character(Unicode.Scalar(c.asciiValue! + 0x20))) - self.temporaryBuffer.append(c) - return continueInCurrentState() - case let c? where HTMLTokenizer.asciiLowerAlpha.contains(c.unicodeScalars.first!): - self.currentBuilder.append(c) - self.temporaryBuffer.append(c) - return continueInCurrentState() - default: - break - } - - // First three steps fall through to the "anything else" block - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: "<"))) - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: "/"))) - // NOTE: The spec doesn't mention this, but it seems that m_current_token (an end tag) is just dropped in this case. - self.currentBuilder = "" - for codePoint in self.temporaryBuffer { - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: codePoint))) - } - return reconsume(currentInputCharacter, in: .RCDATA) - // 13.2.5.12 RAWTEXT less-than sign state, https://html.spec.whatwg.org/multipage/parsing.html#rawtext-less-than-sign-state - case .RAWTEXTLessThanSign: - switch currentInputCharacter { - case "/": - self.temporaryBuffer = "" - return switchTo(.RAWTEXTEndTagOpen) - default: - return emitCharacterAndReconsume("<", in: .RAWTEXT, currentInputCharacter: currentInputCharacter) - } - // 13.2.5.13 RAWTEXT end tag open state, https://html.spec.whatwg.org/multipage/parsing.html#rawtext-end-tag-open-state - case .RAWTEXTEndTagOpen: - switch currentInputCharacter { - case let c? where HTMLTokenizer.asciiAlpha.contains(c.unicodeScalars.first!): - createNewToken(HTMLToken(type: .EndTag(tagName: ""))) - return reconsume(currentInputCharacter!, in: .RAWTEXTEndTagName) - default: - queuedTokens.append(HTMLToken(type: .Character(codePoint: "<"))) - queuedTokens.append(HTMLToken(type: .Character(codePoint: "/"))) - return reconsume(currentInputCharacter, in: .RAWTEXT) - } - // 13.2.5.14 RAWTEXT end tag name state, https://html.spec.whatwg.org/multipage/parsing.html#rawtext-end-tag-name-state - case .RAWTEXTEndTagName: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - if self.isAppropriateEndTagToken(currentToken) { - return switchTo(.BeforeAttributeName) - } - break - case "/": - if self.isAppropriateEndTagToken(currentToken) { - return switchTo(.SelfClosingStartTag) - } - break - case ">": - if self.isAppropriateEndTagToken(currentToken) { - return switchToAndEmitCurrentToken(.Data) - } - break - case let c? where HTMLTokenizer.asciiUpperAlpha.contains(c.unicodeScalars.first!): - self.currentBuilder.append(Character(Unicode.Scalar(c.asciiValue! + 0x20))) - self.temporaryBuffer.append(c) - return continueInCurrentState() - case let c? where HTMLTokenizer.asciiLowerAlpha.contains(c.unicodeScalars.first!): - self.currentBuilder.append(c) - self.temporaryBuffer.append(c) - return continueInCurrentState() - default: - break - } - - // First three steps fall through to the "anything else" block - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: "<"))) - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: "/"))) - // NOTE: The spec doesn't mention this, but it seems that m_current_token (an end tag) is just dropped in this case. - self.currentBuilder = "" - for codePoint in self.temporaryBuffer { - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: codePoint))) - } - return reconsume(currentInputCharacter, in: .RAWTEXT) - // 13.2.5.15 Script data less-than sign state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-less-than-sign-state - case .ScriptDataLessThanSign: - switch currentInputCharacter { - case "/": - self.temporaryBuffer = "" - return switchTo(.ScriptDataEndTagOpen) - case "!": - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: "<"))) - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: "!"))) - return switchTo(.ScriptDataEscapeStart) - default: - return emitCharacterAndReconsume("<", in: .ScriptData, currentInputCharacter: currentInputCharacter) - } - // 13.2.5.16 Script data end tag open state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-end-tag-open-state - case .ScriptDataEndTagOpen: - switch currentInputCharacter { - case let c? where HTMLTokenizer.asciiAlpha.contains(c.unicodeScalars.first!): - createNewToken(HTMLToken(type: .EndTag(tagName: ""))) - return reconsume(currentInputCharacter!, in: .ScriptDataEndTagName) - default: - queuedTokens.append(HTMLToken(type: .Character(codePoint: "<"))) - queuedTokens.append(HTMLToken(type: .Character(codePoint: "/"))) - return reconsume(currentInputCharacter, in: .ScriptData) - } - // 13.2.5.17 Script data end tag name state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-end-tag-name-state - case .ScriptDataEndTagName: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - if self.isAppropriateEndTagToken(currentToken) { - return switchTo(.BeforeAttributeName) - } - break - case "/": - if self.isAppropriateEndTagToken(currentToken) { - return switchTo(.SelfClosingStartTag) - } - break - case ">": - if self.isAppropriateEndTagToken(currentToken) { - return switchToAndEmitCurrentToken(.Data) - } - break - case let c? where HTMLTokenizer.asciiUpperAlpha.contains(c.unicodeScalars.first!): - self.currentBuilder.append(Character(Unicode.Scalar(c.asciiValue! + 0x20))) - self.temporaryBuffer.append(c) - return continueInCurrentState() - case let c? where HTMLTokenizer.asciiLowerAlpha.contains(c.unicodeScalars.first!): - self.currentBuilder.append(c) - self.temporaryBuffer.append(c) - return continueInCurrentState() - default: - break - } - - // First three steps fall through to the "anything else" block - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: "<"))) - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: "/"))) - // NOTE: The spec doesn't mention this, but it seems that m_current_token (an end tag) is just dropped in this case. - self.currentBuilder = "" - for codePoint in self.temporaryBuffer { - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: codePoint))) - } - return reconsume(currentInputCharacter, in: .ScriptData) - // 13.2.5.18 Script data escape start state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-escape-start-state - case .ScriptDataEscapeStart: - switch currentInputCharacter { - case "-": - return switchToAndEmitCharacter(.ScriptDataEscapeStartDash, character: "-") - default: - return reconsume(currentInputCharacter, in: .ScriptData) - } - // 13.2.5.19 Script data escape start dash state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-escape-start-dash-state - case .ScriptDataEscapeStartDash: - switch currentInputCharacter { - case "-": - return switchToAndEmitCharacter(.ScriptDataEscapedDashDash, character: "-") - default: - return reconsume(currentInputCharacter, in: .ScriptData) - } - // 13.2.5.20 Script data escaped state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-escaped-state - case .ScriptDataEscaped: - switch currentInputCharacter { - case "-": - return switchToAndEmitCharacter(.ScriptDataEscapedDash, character: "-") - case "<": - return switchTo(.ScriptDataEscapedLessThanSign) - case "\0": - // FIXME: log_parse_error() - return emitCharacter("\u{FFFD}") - case nil: - // FIXME: log_parse_error() - return emitEOF() - default: - return emitCharacter(currentInputCharacter!) - } - // 13.2.5.21 Script data escaped dash state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-escaped-dash-state - case .ScriptDataEscapedDash: - switch currentInputCharacter { - case "-": - return switchToAndEmitCharacter(.ScriptDataEscapedDashDash, character: "-") - case "<": - return switchTo(.ScriptDataEscapedLessThanSign) - case "\0": - // FIXME: log_parse_error() - return switchToAndEmitCharacter(.ScriptDataEscaped, character: "\u{FFFD}") - case nil: - // FIXME: log_parse_error() - return emitEOF() - default: - return switchToAndEmitCharacter(.ScriptDataEscaped, character: currentInputCharacter!) - } - // 13.2.5.22 Script data escaped dash dash state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-escaped-dash-dash-state - case .ScriptDataEscapedDashDash: - switch currentInputCharacter { - case "-": - return emitCharacter("-") - case "<": - return switchTo(.ScriptDataEscapedLessThanSign) - case ">": - return switchToAndEmitCharacter(.ScriptData, character: ">") - case "\0": - // FIXME: log_parse_error() - return switchToAndEmitCharacter(.ScriptDataEscaped, character: "\u{FFFD}") - case nil: - // FIXME: log_parse_error() - return emitEOF() - default: - return switchToAndEmitCharacter(.ScriptDataEscaped, character: currentInputCharacter!) - } - // 13.2.5.23 Script data escaped less-than sign state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-escaped-less-than-sign-state - case .ScriptDataEscapedLessThanSign: - switch currentInputCharacter { - case "/": - self.temporaryBuffer = "" - return switchTo(.ScriptDataEscapedEndTagOpen) - case let c? where HTMLTokenizer.asciiAlpha.contains(c.unicodeScalars.first!): - self.temporaryBuffer = "" - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: "<"))) - return reconsume(currentInputCharacter!, in: .ScriptDataDoubleEscapeStart) - default: - return emitCharacterAndReconsume("<", in: .ScriptDataEscaped, currentInputCharacter: currentInputCharacter) - } - // 13.2.5.24 Script data escaped end tag open state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-escaped-end-tag-open-state - case .ScriptDataEscapedEndTagOpen: - switch currentInputCharacter { - case let c? where HTMLTokenizer.asciiAlpha.contains(c.unicodeScalars.first!): - createNewToken(HTMLToken(type: .EndTag(tagName: ""))) - return reconsume(currentInputCharacter!, in: .ScriptDataEscapedEndTagName) - default: - queuedTokens.append(HTMLToken(type: .Character(codePoint: "<"))) - queuedTokens.append(HTMLToken(type: .Character(codePoint: "/"))) - return reconsume(currentInputCharacter, in: .ScriptDataEscaped) - } - // 13.2.5.25 Script data escaped end tag name state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-escaped-end-tag-name-state - case .ScriptDataEscapedEndTagName: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - if self.isAppropriateEndTagToken(currentToken) { - return switchTo(.BeforeAttributeName) - } - break - case "/": - if self.isAppropriateEndTagToken(currentToken) { - return switchTo(.SelfClosingStartTag) - } - break - case ">": - if self.isAppropriateEndTagToken(currentToken) { - return switchToAndEmitCurrentToken(.Data) - } - break - case let c? where HTMLTokenizer.asciiUpperAlpha.contains(c.unicodeScalars.first!): - self.currentBuilder.append(Character(Unicode.Scalar(c.asciiValue! + 0x20))) - self.temporaryBuffer.append(c) - return continueInCurrentState() - case let c? where HTMLTokenizer.asciiLowerAlpha.contains(c.unicodeScalars.first!): - self.currentBuilder.append(c) - self.temporaryBuffer.append(c) - return continueInCurrentState() - default: - break - } - - // First three steps fall through to the "anything else" block - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: "<"))) - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: "/"))) - // NOTE: The spec doesn't mention this, but it seems that m_current_token (an end tag) is just dropped in this case. - self.currentBuilder = "" - for codePoint in self.temporaryBuffer { - self.queuedTokens.append(HTMLToken(type: .Character(codePoint: codePoint))) - } - return reconsume(currentInputCharacter, in: .ScriptDataEscaped) - // 13.2.5.26 Script data double escape start state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escape-start-state - case .ScriptDataDoubleEscapeStart: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ", "/", ">": - if self.temporaryBuffer == "script" { - return switchToAndEmitCharacter(.ScriptDataDoubleEscaped, character: currentInputCharacter!) - } else { - return switchToAndEmitCharacter(.ScriptDataEscaped, character: currentInputCharacter!) - } - case let c? where HTMLTokenizer.asciiUpperAlpha.contains(c.unicodeScalars.first!): - self.temporaryBuffer.append(Character(Unicode.Scalar(c.asciiValue! + 0x20))) - return emitCharacter(currentInputCharacter!) - case let c? where HTMLTokenizer.asciiLowerAlpha.contains(c.unicodeScalars.first!): - self.temporaryBuffer.append(c) - return emitCharacter(currentInputCharacter!) - default: - return reconsume(currentInputCharacter, in: .ScriptDataEscaped) - } - // 13.2.5.27 Script data double escaped state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escaped-state - case .ScriptDataDoubleEscaped: - switch currentInputCharacter { - case "-": - return switchToAndEmitCharacter(.ScriptDataDoubleEscapedDash, character: "-") - case "<": - return switchTo(.ScriptDataDoubleEscapedLessThanSign) - case "\0": - // FIXME: log_parse_error() - return emitCharacter("\u{FFFD}") - case nil: - // FIXME: log_parse_error() - return emitEOF() - default: - return emitCharacter(currentInputCharacter!) - } - // 13.2.5.28 Script data double escaped dash state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escaped-dash-state - case .ScriptDataDoubleEscapedDash: - switch currentInputCharacter { - case "-": - return switchToAndEmitCharacter(.ScriptDataDoubleEscapedDashDash, character: "-") - case "<": - return switchTo(.ScriptDataDoubleEscapedLessThanSign) - case "\0": - // FIXME: log_parse_error() - return switchToAndEmitCharacter(.ScriptDataDoubleEscaped, character: "\u{FFFD}") - case nil: - // FIXME: log_parse_error() - return emitEOF() - default: - return switchToAndEmitCharacter(.ScriptDataDoubleEscaped, character: currentInputCharacter!) - } - // 13.2.5.29 Script data double escaped dash dash state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escaped-dash-dash-state - case .ScriptDataDoubleEscapedDashDash: - switch currentInputCharacter { - case "-": - return emitCharacter("-") - case "<": - return switchToAndEmitCharacter(.ScriptDataDoubleEscapedLessThanSign, character: "<") - case ">": - return switchToAndEmitCharacter(.ScriptData, character: ">") - case "\0": - // FIXME: log_parse_error() - return switchToAndEmitCharacter(.ScriptDataDoubleEscaped, character: "\u{FFFD}") - case nil: - // FIXME: log_parse_error() - return emitEOF() - default: - return switchToAndEmitCharacter(.ScriptDataDoubleEscaped, character: currentInputCharacter!) - } - // 13.2.5.30 Script data double escaped less-than sign state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escaped-less-than-sign-state - case .ScriptDataDoubleEscapedLessThanSign: - switch currentInputCharacter { - case "/": - self.temporaryBuffer = "" - return switchToAndEmitCharacter(.ScriptDataDoubleEscapeEnd, character: "/") - default: - return reconsume(currentInputCharacter, in: .ScriptDataDoubleEscaped) - } - // 13.2.5.31 Script data double escape end state, https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escape-end-state - case .ScriptDataDoubleEscapeEnd: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ", "/", ">": - if self.temporaryBuffer == "script" { - return switchToAndEmitCharacter(.ScriptDataEscaped, character: currentInputCharacter!) - } else { - return switchToAndEmitCharacter(.ScriptDataDoubleEscaped, character: currentInputCharacter!) - } - case let c? where HTMLTokenizer.asciiUpperAlpha.contains(c.unicodeScalars.first!): - self.temporaryBuffer.append(Character(Unicode.Scalar(c.asciiValue! + 0x20))) - return emitCharacter(currentInputCharacter!) - case let c? where HTMLTokenizer.asciiLowerAlpha.contains(c.unicodeScalars.first!): - self.temporaryBuffer.append(c) - return emitCharacter(currentInputCharacter!) - default: - return reconsume(currentInputCharacter, in: .ScriptDataDoubleEscaped) - } - // 13.2.5.32 Before attribute name state, https://html.spec.whatwg.org/multipage/parsing.html#before-attribute-name-state - case .BeforeAttributeName: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return continueInCurrentState() - case "/", ">", nil: - return reconsume(currentInputCharacter, in: .AfterAttributeName) - case "=": - // FIXME: log_parse_error() - self.currentBuilder = Swift.String(currentInputCharacter!) - self.currentAttribute = HTMLToken.Attribute(localName: "", value: "") - return switchTo(.AttributeName) - default: - self.currentAttribute = HTMLToken.Attribute(localName: "", value: "") - return reconsume(currentInputCharacter!, in: .AttributeName) - } - // 13.2.5.33 Attribute name state, https://html.spec.whatwg.org/multipage/parsing.html#attribute-name-state - case .AttributeName: - // FIXME: When the user agent leaves the attribute name state (and before emitting the tag token, if appropriate), - // the complete attribute's name must be compared to the other attributes on the same token; - // if there is already an attribute on the token with the exact same name, then this is a duplicate-attribute - // parse error and the new attribute must be removed from the token. - // NOTE: If an attribute is so removed from a token, it, and the value that gets associated with it, if any, - // are never subsequently used by the parser, and are therefore effectively discarded. Removing the attribute - // in this way does not change its status as the "current attribute" for the purposes of the tokenizer, however. - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ", "/", ">", nil: - // FIXME: set name position - self.currentAttribute!.localName = self.currentBuilder.takeString() - return reconsume(currentInputCharacter, in: .AfterAttributeName) - case "=": - // FIXME: set name position - self.currentAttribute!.localName = self.currentBuilder.takeString() - return switchTo(.BeforeAttributeValue) - case let c? where HTMLTokenizer.asciiUpperAlpha.contains(c.unicodeScalars.first!): - self.currentBuilder.append(Character(Unicode.Scalar(c.asciiValue! + 0x20))) - return continueInCurrentState() - case "\0": - // FIXME: log_parse_error() - self.currentBuilder.append("\u{FFFD}") - return continueInCurrentState() - default: - self.currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - // 13.2.5.34 After attribute name state, https://html.spec.whatwg.org/multipage/parsing.html#after-attribute-name-state - case .AfterAttributeName: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return continueInCurrentState() - case "/": - self.finalizeCurrentAttribute(.SetName) - return switchTo(.SelfClosingStartTag) - case "=": - self.finalizeCurrentAttribute(.SetName) - return switchTo(.BeforeAttributeValue) - case ">": - self.finalizeCurrentAttribute(.SetName) - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.finalizeCurrentAttribute(.IgnoreString) - return emitEOF() - default: - self.finalizeCurrentAttribute(.SetName) - self.currentAttribute = HTMLToken.Attribute(localName: "", value: "") - return reconsume(currentInputCharacter!, in: .AttributeName) - } - // 13.2.5.35 Before attribute value state, https://html.spec.whatwg.org/multipage/parsing.html#before-attribute-value-state - case .BeforeAttributeValue: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return continueInCurrentState() - case "\"": - return switchTo(.AttributeValueDoubleQuoted) - case "'": - return switchTo(.AttributeValueSingleQuoted) - case ">": - // FIXME: log_parse_error() - self.finalizeCurrentAttribute(.IgnoreString) - return switchToAndEmitCurrentToken(.Data) - default: - return reconsume(currentInputCharacter, in: .AttributeValueUnquoted) - } - // 13.2.5.36 Attribute value (double-quoted) state, https://html.spec.whatwg.org/multipage/parsing.html#attribute-value-double-quoted-state - case .AttributeValueDoubleQuoted: - switch currentInputCharacter { - case "\"": - return switchTo(.AfterAttributeValueQuoted) - case "&": - self.returnState = .AttributeValueDoubleQuoted - return switchTo(.CharacterReference) - case "\0": - // FIXME: log_parse_error() - self.currentBuilder.append("\u{FFFD}") - return continueInCurrentState() - case nil: - // FIXME: log_parse_error() - self.finalizeCurrentAttribute(.IgnoreString) - return emitEOF() - default: - self.currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - // 13.2.5.37 Attribute value (single-quoted) state, https://html.spec.whatwg.org/multipage/parsing.html#attribute-value-single-quoted-state - case .AttributeValueSingleQuoted: - switch currentInputCharacter { - case "'": - return switchTo(.AfterAttributeValueQuoted) - case "&": - self.returnState = .AttributeValueSingleQuoted - return switchTo(.CharacterReference) - case "\0": - // FIXME: log_parse_error() - self.currentBuilder.append("\u{FFFD}") - return continueInCurrentState() - case nil: - // FIXME: log_parse_error() - return emitEOF() - default: - self.currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - // 13.2.5.38 Attribute value (unquoted) state, https://html.spec.whatwg.org/multipage/parsing.html#attribute-value-unquoted-state - case .AttributeValueUnquoted: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - self.finalizeCurrentAttribute(.SetValue) - return switchTo(.BeforeAttributeName) - case "&": - self.returnState = .AttributeValueUnquoted - return switchTo(.CharacterReference) - case ">": - self.finalizeCurrentAttribute(.SetValue) - return switchToAndEmitCurrentToken(.Data) - case "\0": - // FIXME: log_parse_error() - self.currentBuilder.append("\u{FFFD}") - return continueInCurrentState() - case "\"", "'", "<", "=", "`": - // FIXME: log_parse_error() - self.currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - case nil: - // FIXME: log_parse_error() - self.finalizeCurrentAttribute(.IgnoreString) - return emitEOF() - default: - self.currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - // 13.2.5.39 After attribute value (quoted) state, https://html.spec.whatwg.org/multipage/parsing.html#after-attribute-value-quoted-state - case .AfterAttributeValueQuoted: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - self.finalizeCurrentAttribute(.SetValue) - return switchTo(.BeforeAttributeName) - case "/": - self.finalizeCurrentAttribute(.SetValue) - return switchTo(.SelfClosingStartTag) - case ">": - self.finalizeCurrentAttribute(.SetValue) - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.finalizeCurrentAttribute(.IgnoreString) - return emitEOF() - default: - // FIXME: log_parse_error() - self.finalizeCurrentAttribute(.SetValue) - return reconsume(currentInputCharacter!, in: .BeforeAttributeName) - } - // 13.2.5.40 Self-closing start tag state, https://html.spec.whatwg.org/multipage/parsing.html#self-closing-start-tag-state - case .SelfClosingStartTag: - switch currentInputCharacter { - case ">": - self.currentToken.selfClosing = true - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - return emitEOF() - default: - // FIXME: log_parse_error() - return reconsume(currentInputCharacter!, in: .BeforeAttributeName) - } - // 13.2.5.41 Bogus comment state, https://html.spec.whatwg.org/multipage/parsing.html#bogus-comment-state - case .BogusComment: - switch currentInputCharacter { - case ">": - currentToken = HTMLToken(type: .Comment(data: currentBuilder.takeString())) - return switchToAndEmitCurrentToken(.Data) - case nil: - currentToken = HTMLToken(type: .Comment(data: currentBuilder.takeString())) - return emitCurrentTokenFollowedByEOF() - case "\0": - // FIXME: log_parse_error() - currentBuilder.append("\u{FFFD}") - return continueInCurrentState() - default: - self.currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - // 13.2.5.42 Markup declaration open state, https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state - case .MarkupDeclarationOpen: - dontConsumeNextInputCharacter() - if let nextTwo = peekNext(count: 2), nextTwo == "--" { - skip(2) - return switchTo(.CommentStart) - } else if let nextSeven = peekNext(count: 7), nextSeven.uppercased() == "DOCTYPE" { - skip(7) - return switchTo(.DOCTYPE) - } else if let nextSeven = peekNext(count: 7), nextSeven.uppercased() == "[CDATA[" { - skip(7) - // FIXME: If there is an adjusted current node and it is not an element in the HTML namespace, - // then switch to the CDATA section state. - // FIXME: log_parse_error() - self.currentBuilder = "[CDATA[" - self.currentToken = HTMLToken(type: .Comment(data: "")) - return switchTo(.BogusComment) - } else { - // FIXME: log_parse_error() - self.currentToken = HTMLToken(type: .Comment(data: "")) - return switchTo(.BogusComment) - } - // 13.2.5.43 Comment start state, https://html.spec.whatwg.org/multipage/parsing.html#comment-start-state - case .CommentStart: - switch currentInputCharacter { - case "-": - return switchTo(.CommentStartDash) - case ">": - // FIXME: log_parse_error() - return switchToAndEmitCurrentToken(.Data) - default: - return reconsume(currentInputCharacter, in: .Comment) - } - // 13.2.5.44 Comment start dash state, https://html.spec.whatwg.org/multipage/parsing.html#comment-start-dash-state - case .CommentStartDash: - switch currentInputCharacter { - case "-": - return switchTo(.CommentEnd) - case ">": - // FIXME: log_parse_error() - currentToken = HTMLToken(type: .Comment(data: currentBuilder.takeString())) - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - currentToken = HTMLToken(type: .Comment(data: currentBuilder.takeString())) - return emitCurrentTokenFollowedByEOF() - default: - currentBuilder.append("-") - return reconsume(currentInputCharacter, in: .Comment) - } - // 13.2.5.45 Comment state, https://html.spec.whatwg.org/multipage/parsing.html#comment-state - case .Comment: - switch currentInputCharacter { - case "<": - currentBuilder.append("<") - return switchTo(.CommentLessThanSign) - case "-": - return switchTo(.CommentEndDash) - case "\0": - // FIXME: log_parse_error() - currentBuilder.append("\u{FFFD}") - return continueInCurrentState() - case nil: - // FIXME: log_parse_error() - currentToken = HTMLToken(type: .Comment(data: currentBuilder.takeString())) - return emitCurrentTokenFollowedByEOF() - default: - currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - // 13.2.5.46 Comment less-than sign state, https://html.spec.whatwg.org/multipage/parsing.html#comment-less-than-sign-state - case .CommentLessThanSign: - switch currentInputCharacter { - case "!": - currentBuilder.append(currentInputCharacter!) - return switchTo(.CommentLessThanSignBang) - case "<": - currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - default: - return reconsume(currentInputCharacter, in: .Comment) - } - // 13.2.5.47 Comment less-than sign bang state, https://html.spec.whatwg.org/multipage/parsing.html#comment-less-than-sign-bang-state - case .CommentLessThanSignBang: - switch currentInputCharacter { - case "-": - return switchTo(.CommentLessThanSignBangDash) - default: - return reconsume(currentInputCharacter, in: .Comment) - } - // 13.2.5.48 Comment less-than sign bang dash state, https://html.spec.whatwg.org/multipage/parsing.html#comment-less-than-sign-bang-dash-state - case .CommentLessThanSignBangDash: - switch currentInputCharacter { - case "-": - return switchTo(.CommentLessThanSignBangDashDash) - default: - return reconsume(currentInputCharacter, in: .CommentEndDash) - } - // 13.2.5.49 Comment less-than sign bang dash dash state, https://html.spec.whatwg.org/multipage/parsing.html#comment-less-than-sign-bang-dash-dash-state - case .CommentLessThanSignBangDashDash: - switch currentInputCharacter { - case ">", nil: - return reconsume(currentInputCharacter, in: .CommentEnd) - default: - // FIXME: log_parse_error() - return reconsume(currentInputCharacter, in: .CommentEnd) - } - // 13.2.5.50 Comment end dash state, https://html.spec.whatwg.org/multipage/parsing.html#comment-end-dash-state - case .CommentEndDash: - switch currentInputCharacter { - case "-": - return switchTo(.CommentEnd) - case nil: - // FIXME: log_parse_error() - currentToken = HTMLToken(type: .Comment(data: currentBuilder.takeString())) - return emitCurrentTokenFollowedByEOF() - default: - currentBuilder.append("-") - return reconsume(currentInputCharacter, in: .Comment) - } - // 13.2.5.51 Comment end state, https://html.spec.whatwg.org/multipage/parsing.html#comment-end-state - case .CommentEnd: - switch currentInputCharacter { - case ">": - currentToken = HTMLToken(type: .Comment(data: currentBuilder.takeString())) - return switchToAndEmitCurrentToken(.Data) - case "!": - return switchTo(.CommentEndBang) - case "-": - currentBuilder.append("-") - return continueInCurrentState() - case nil: - // FIXME: log_parse_error() - currentToken = HTMLToken(type: .Comment(data: currentBuilder.takeString())) - return emitCurrentTokenFollowedByEOF() - default: - currentBuilder.append("--") - return reconsume(currentInputCharacter, in: .Comment) - } - // 13.2.5.52 Comment end bang state, https://html.spec.whatwg.org/multipage/parsing.html#comment-end-bang-state - case .CommentEndBang: - switch currentInputCharacter { - case "-": - currentBuilder.append("--!") - return switchTo(.CommentEndDash) - case ">": - // FIXME: log_parse_error() - currentToken = HTMLToken(type: .Comment(data: currentBuilder.takeString())) - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - currentToken = HTMLToken(type: .Comment(data: currentBuilder.takeString())) - return emitCurrentTokenFollowedByEOF() - default: - currentBuilder.append("--!") - return reconsume(currentInputCharacter, in: .Comment) - } - // 13.2.5.53 DOCTYPE state, https://html.spec.whatwg.org/multipage/parsing.html#doctype-state - case .DOCTYPE: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return switchTo(.BeforeDOCTYPEName) - case ">": - return reconsume(currentInputCharacter, in: .BeforeDOCTYPEName) - case nil: - // FIXME: log_parse_error() - currentToken = HTMLToken(type: .DOCTYPE(name: nil, publicIdentifier: nil, systemIdentifier: nil, forceQuirksMode: true)) - return emitCurrentTokenFollowedByEOF() - default: - // FIXME: log_parse_error() - return reconsume(currentInputCharacter!, in: .BeforeDOCTYPEName) - } - // 13.2.5.54 Before DOCTYPE name state, https://html.spec.whatwg.org/multipage/parsing.html#before-doctype-name-state - case .BeforeDOCTYPEName: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return continueInCurrentState() - case let c? where HTMLTokenizer.asciiUpperAlpha.contains(c.unicodeScalars.first!): - precondition(self.currentBuilder.isEmpty) - self.currentToken = HTMLToken(type: .DOCTYPE(name: nil, publicIdentifier: nil, systemIdentifier: nil, forceQuirksMode: false)) - self.currentBuilder.append(Character(Unicode.Scalar(c.asciiValue! + 0x20))) - return switchTo(.DOCTYPEName) - case "\0": - // FIXME: log_parse_error() - precondition(self.currentBuilder.isEmpty) - self.currentToken = HTMLToken(type: .DOCTYPE(name: nil, publicIdentifier: nil, systemIdentifier: nil, forceQuirksMode: false)) - self.currentBuilder.append("\u{FFFD}") - return switchTo(.DOCTYPEName) - case ">": - // FIXME: log_parse_error() - self.currentToken = HTMLToken(type: .DOCTYPE(name: nil, publicIdentifier: nil, systemIdentifier: nil, forceQuirksMode: true)) - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.currentToken = HTMLToken(type: .DOCTYPE(name: nil, publicIdentifier: nil, systemIdentifier: nil, forceQuirksMode: true)) - return emitCurrentTokenFollowedByEOF() - default: - // FIXME: log_parse_error() - precondition(self.currentBuilder.isEmpty) - self.currentToken = HTMLToken(type: .DOCTYPE(name: nil, publicIdentifier: nil, systemIdentifier: nil, forceQuirksMode: false)) - self.currentBuilder.append(currentInputCharacter!) - return switchTo(.DOCTYPEName) - } - // 13.2.5.55 DOCTYPE name state, https://html.spec.whatwg.org/multipage/parsing.html#doctype-name-state - case .DOCTYPEName: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - self.currentToken.name = self.currentBuilder.takeString() - return switchTo(.AfterDOCTYPEName) - case ">": - self.currentToken.name = self.currentBuilder.takeString() - return switchToAndEmitCurrentToken(.Data) - case let c? where HTMLTokenizer.asciiUpperAlpha.contains(c.unicodeScalars.first!): - self.currentBuilder.append(Character(Unicode.Scalar(c.asciiValue! + 0x20))) - return continueInCurrentState() - case "\0": - // FIXME: log_parse_error() - self.currentBuilder.append("\u{FFFD}") - return continueInCurrentState() - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - self.currentToken.name = self.currentBuilder.takeString() - return emitCurrentTokenFollowedByEOF() - default: - self.currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - // 13.2.5.56 After DOCTYPE name state, https://html.spec.whatwg.org/multipage/parsing.html#after-doctype-name-state - case .AfterDOCTYPEName: - precondition(self.currentBuilder.isEmpty) - precondition(self.currentToken.name != nil) - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return continueInCurrentState() - case ">": - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return emitCurrentTokenFollowedByEOF() - default: - if "pP".contains(currentInputCharacter!), peekNext(count: 5)?.uppercased() == "UBLIC" { - skip(5) - return switchTo(.AfterDOCTYPEPublicKeyword) - } - if "sS".contains(currentInputCharacter!), peekNext(count: 5)?.uppercased() == "YSTEM" { - skip(5) - return switchTo(.AfterDOCTYPESystemKeyword) - } - - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return reconsume(currentInputCharacter!, in: .BogusDOCTYPE) - } - // 13.2.5.57 After DOCTYPE public keyword state, https://html.spec.whatwg.org/multipage/parsing.html#after-doctype-public-keyword-state - case .AfterDOCTYPEPublicKeyword: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return switchTo(.BeforeDOCTYPEPublicIdentifier) - case "\"": - // FIXME: log_parse_error() - self.currentToken.publicIdentifier = "" - return switchTo(.DOCTYPEPublicIdentifierDoubleQuoted) - case "'": - self.currentToken.publicIdentifier = "" - return switchTo(.DOCTYPEPublicIdentifierSingleQuoted) - case ">": - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return emitCurrentTokenFollowedByEOF() - default: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return reconsume(currentInputCharacter!, in: .BogusDOCTYPE) - } - // 13.2.5.58 Before DOCTYPE public identifier state, https://html.spec.whatwg.org/multipage/parsing.html#before-doctype-public-identifier-state - case .BeforeDOCTYPEPublicIdentifier: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return continueInCurrentState() - case "\"": - self.currentToken.publicIdentifier = "" - return switchTo(.DOCTYPEPublicIdentifierDoubleQuoted) - case "'": - self.currentToken.publicIdentifier = "" - return switchTo(.DOCTYPEPublicIdentifierSingleQuoted) - case ">": - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return emitCurrentTokenFollowedByEOF() - default: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return reconsume(currentInputCharacter!, in: .BogusDOCTYPE) - } - // 13.2.5.59 DOCTYPE public identifier (double-quoted) state, https://html.spec.whatwg.org/multipage/parsing.html#doctype-public-identifier-double-quoted-state - case .DOCTYPEPublicIdentifierDoubleQuoted: - switch currentInputCharacter { - case "\"": - self.currentToken.publicIdentifier = self.currentBuilder.takeString() - return switchTo(.AfterDOCTYPEPublicIdentifier) - case "\0": - // FIXME: log_parse_error() - self.currentBuilder.append("\u{FFFD}") - return continueInCurrentState() - case ">": - // FIXME: log_parse_error() - self.currentToken.publicIdentifier = self.currentBuilder.takeString() - self.currentToken.forceQuirks = true - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return emitCurrentTokenFollowedByEOF() - default: - self.currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - // 13.2.5.60 DOCTYPE public identifier (single-quoted) state, https://html.spec.whatwg.org/multipage/parsing.html#doctype-public-identifier-single-quoted-state - case .DOCTYPEPublicIdentifierSingleQuoted: - switch currentInputCharacter { - case "'": - self.currentToken.publicIdentifier = self.currentBuilder.takeString() - return switchTo(.AfterDOCTYPEPublicIdentifier) - case "\0": - // FIXME: log_parse_error() - self.currentBuilder.append("\u{FFFD}") - return continueInCurrentState() - case ">": - // FIXME: log_parse_error() - self.currentToken.publicIdentifier = self.currentBuilder.takeString() - self.currentToken.forceQuirks = true - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return emitCurrentTokenFollowedByEOF() - default: - self.currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - // 13.2.5.61 After DOCTYPE public identifier state, https://html.spec.whatwg.org/multipage/parsing.html#after-doctype-public-identifier-state - case .AfterDOCTYPEPublicIdentifier: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return switchTo(.BetweenDOCTYPEPublicAndSystemIdentifiers) - case ">": - return switchToAndEmitCurrentToken(.Data) - case "\"": - // FIXME: log_parse_error() - self.currentToken.systemIdentifier = "" - return switchTo(.DOCTYPESystemIdentifierDoubleQuoted) - case "'": - // FIXME: log_parse_error() - self.currentToken.systemIdentifier = "" - return switchTo(.DOCTYPESystemIdentifierSingleQuoted) - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return emitCurrentTokenFollowedByEOF() - default: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return reconsume(currentInputCharacter!, in: .BogusDOCTYPE) - } - // 13.2.5.62 Between DOCTYPE public and system identifiers state, https://html.spec.whatwg.org/multipage/parsing.html#between-doctype-public-and-system-identifiers-state - case .BetweenDOCTYPEPublicAndSystemIdentifiers: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return continueInCurrentState() - case ">": - return switchToAndEmitCurrentToken(.Data) - case "\"": - self.currentToken.systemIdentifier = "" - return switchTo(.DOCTYPESystemIdentifierDoubleQuoted) - case "'": - self.currentToken.systemIdentifier = "" - return switchTo(.DOCTYPESystemIdentifierSingleQuoted) - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return emitCurrentTokenFollowedByEOF() - default: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return reconsume(currentInputCharacter!, in: .BogusDOCTYPE) - } - // 13.2.5.63 After DOCTYPE system keyword state, https://html.spec.whatwg.org/multipage/parsing.html#after-doctype-system-keyword-state - case .AfterDOCTYPESystemKeyword: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return switchTo(.BeforeDOCTYPESystemIdentifier) - case "\"": - // FIXME: log_parse_error() - self.currentToken.systemIdentifier = "" - return switchTo(.DOCTYPESystemIdentifierDoubleQuoted) - case "'": - // FIXME: log_parse_error() - self.currentToken.systemIdentifier = "" - return switchTo(.DOCTYPESystemIdentifierSingleQuoted) - case ">": - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return emitCurrentTokenFollowedByEOF() - default: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return reconsume(currentInputCharacter!, in: .BogusDOCTYPE) - } - // 13.2.5.64 Before DOCTYPE system identifier state, https://html.spec.whatwg.org/multipage/parsing.html#before-doctype-system-identifier-state - case .BeforeDOCTYPESystemIdentifier: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return continueInCurrentState() - case "\"": - self.currentToken.systemIdentifier = "" - return switchTo(.DOCTYPESystemIdentifierDoubleQuoted) - case "'": - self.currentToken.systemIdentifier = "" - return switchTo(.DOCTYPESystemIdentifierSingleQuoted) - case ">": - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return emitCurrentTokenFollowedByEOF() - default: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return reconsume(currentInputCharacter!, in: .BogusDOCTYPE) - } - // 13.2.5.65 DOCTYPE system identifier (double-quoted) state, https://html.spec.whatwg.org/multipage/parsing.html#doctype-system-identifier-double-quoted-state - case .DOCTYPESystemIdentifierDoubleQuoted: - switch currentInputCharacter { - case "\"": - self.currentToken.systemIdentifier = self.currentBuilder.takeString() - return switchTo(.AfterDOCTYPESystemIdentifier) - case "\0": - // FIXME: log_parse_error() - self.currentBuilder.append("\u{FFFD}") - return continueInCurrentState() - case ">": - // FIXME: log_parse_error() - self.currentToken.systemIdentifier = self.currentBuilder.takeString() - self.currentToken.forceQuirks = true - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return emitCurrentTokenFollowedByEOF() - default: - self.currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - // 13.2.5.66 DOCTYPE system identifier (single-quoted) state, https://html.spec.whatwg.org/multipage/parsing.html#doctype-system-identifier-single-quoted-state - case .DOCTYPESystemIdentifierSingleQuoted: - switch currentInputCharacter { - case "'": - return switchTo(.AfterDOCTYPESystemIdentifier) - case "\0": - // FIXME: log_parse_error() - self.currentBuilder.append("\u{FFFD}") - return continueInCurrentState() - case ">": - // FIXME: log_parse_error() - self.currentToken.systemIdentifier = self.currentBuilder.takeString() - self.currentToken.forceQuirks = true - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return emitCurrentTokenFollowedByEOF() - default: - self.currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - // 13.2.5.67 After DOCTYPE system identifier state, https://html.spec.whatwg.org/multipage/parsing.html#after-doctype-system-identifier-state - case .AfterDOCTYPESystemIdentifier: - switch currentInputCharacter { - case "\t", "\n", "\u{000C}", " ": - return continueInCurrentState() - case ">": - return switchToAndEmitCurrentToken(.Data) - case nil: - // FIXME: log_parse_error() - self.currentToken.forceQuirks = true - return emitCurrentTokenFollowedByEOF() - default: - // FIXME: log_parse_error() - // NOTE: This does not set the current DOCTYPE token's force-quirks flag to on. - return reconsume(currentInputCharacter!, in: .BogusDOCTYPE) - } - // 13.2.5.68 Bogus DOCTYPE state, https://html.spec.whatwg.org/multipage/parsing.html#bogus-doctype-state - case .BogusDOCTYPE: - switch currentInputCharacter { - case ">": - return switchToAndEmitCurrentToken(.Data) - case "\0": - // FIXME: log_parse_error() - return continueInCurrentState() - case nil: - return emitCurrentTokenFollowedByEOF() - default: - return continueInCurrentState() - } - // 13.2.5.69 CDATA section state, https://html.spec.whatwg.org/multipage/parsing.html#cdata-section-state - case .CDATASection: - switch currentInputCharacter { - case "]": - return switchTo(.CDATASectionBracket) - case nil: - // FIXME: log_parse_error() - return emitEOF() - default: - // NOTE: U+0000 NULL characters are handled in the tree construction stage, - // as part of the in foreign content insertion mode, which is the only place where CDATA sections can appear. - return emitCharacter(currentInputCharacter!) - } - // 13.2.5.70 CDATA section bracket state, https://html.spec.whatwg.org/multipage/parsing.html#cdata-section-bracket-state - case .CDATASectionBracket: - switch currentInputCharacter { - case "]": - return switchTo(.CDATASectionEnd) - default: - return emitCharacterAndReconsume("]", in: .CDATASection, currentInputCharacter: currentInputCharacter) - } - - // 13.2.5.71 CDATA section end state, https://html.spec.whatwg.org/multipage/parsing.html#cdata-section-end-state - case .CDATASectionEnd: - switch currentInputCharacter { - case "]": - return emitCharacter("]") - case ">": - return switchTo(.Data) - default: - queuedTokens.append(HTMLToken(type: .Character(codePoint: "]"))) - return emitCharacterAndReconsume("]", in: .CDATASection, currentInputCharacter: currentInputCharacter) - } - // 13.2.5.72 Character reference state, https://html.spec.whatwg.org/multipage/parsing.html#character-reference-state - case .CharacterReference: - self.temporaryBuffer = "&" - switch currentInputCharacter { - case let c? where HTMLTokenizer.asciiAlphanumeric.contains(c.unicodeScalars.first!): - return reconsume(currentInputCharacter!, in: .NamedCharacterReference) - case "#": - self.temporaryBuffer.append(currentInputCharacter!) - return switchTo(.NumericCharacterReference) - default: - self.flushCodepointsConsumedAsACharacterReference() - return reconsume(currentInputCharacter, in: self.returnState) - } - // 13.2.5.73 Named character reference state, https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state - case .NamedCharacterReference: - // FIXME: This should be updated to match the C++ implementation, this - // won't handle one-character-at-a-time document.write calls properly. - var subString = self.input[self.previousCursor...] - let entityMatch = subString.withUTF8 { utf8 in - return Web.HTML.match_entity_for_named_character_reference(AK.StringView(utf8.baseAddress!, utf8.count)) - } - if entityMatch.hasValue { - let entity = entityMatch.value!.entity - skip(entity.length()) - // FIXME: Iterate over the entity's code points and add them instead of creating a string - self.temporaryBuffer.append(Swift.String(akStringView: entity)!) - - if self.consumedAsPartOfAnAttribute(), !entity.endsWith(";") { - if let peeked = peekCodePoint(), peeked == "=" || HTMLTokenizer.asciiAlphanumeric.contains(peeked.unicodeScalars.first!) { - self.flushCodepointsConsumedAsACharacterReference() - return switchTo(self.returnState) - } - } - - if !entity.endsWith(";") { - // FIXME: log_parse_error() - } - - self.temporaryBuffer = "" - - // FIXME: This AK::Vector should be CxxConvertibleToContainer, but https://github.com/swiftlang/swift/issues/77607 - let codePoints = entityMatch.value!.code_points - for i in 0...codePoints.size() { - self.temporaryBuffer.append(Character(Unicode.Scalar(codePoints[i])!)) - } - self.flushCodepointsConsumedAsACharacterReference() - return switchTo(self.returnState) - } - - self.flushCodepointsConsumedAsACharacterReference() - return reconsume(currentInputCharacter, in: .AmbiguousAmpersand) - // 13.2.5.74 Ambiguous ampersand state, https://html.spec.whatwg.org/multipage/parsing.html#ambiguous-ampersand-state - case .AmbiguousAmpersand: - switch currentInputCharacter { - case let c? where HTMLTokenizer.asciiAlphanumeric.contains(c.unicodeScalars.first!): - if self.consumedAsPartOfAnAttribute() { - self.currentBuilder.append(currentInputCharacter!) - return continueInCurrentState() - } - return emitCharacter(currentInputCharacter!) - case ";": - // FIXME: log_parse_error() - return reconsume(currentInputCharacter!, in: self.returnState) - default: - return reconsume(currentInputCharacter, in: self.returnState) - } - // 13.2.5.75 Numeric character reference state, https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-state - case .NumericCharacterReference: - self.characterReferenceCode = 0 - switch currentInputCharacter { - case "x", "X": - self.temporaryBuffer.append(currentInputCharacter!) - return switchTo(.HexadecimalCharacterReferenceStart) - default: - return reconsume(currentInputCharacter, in: .DecimalCharacterReferenceStart) - } - // 13.2.5.76 Hexadecimal character reference start state, https://html.spec.whatwg.org/multipage/parsing.html#hexadecimal-character-reference-start-state - case .HexadecimalCharacterReferenceStart: - switch currentInputCharacter { - case let c? where HTMLTokenizer.asciiHexDigit.contains(c.unicodeScalars.first!): - return reconsume(currentInputCharacter!, in: .HexadecimalCharacterReference) - default: - // FIXME: log_parse_error() - self.flushCodepointsConsumedAsACharacterReference() - return reconsume(currentInputCharacter, in: self.returnState) - } - // 13.2.5.77 Decimal character reference start state, https://html.spec.whatwg.org/multipage/parsing.html#decimal-character-reference-start-state - case .DecimalCharacterReferenceStart: - switch currentInputCharacter { - case let c? where HTMLTokenizer.asciiDigit.contains(c.unicodeScalars.first!): - return reconsume(currentInputCharacter!, in: .DecimalCharacterReference) - default: - // FIXME: log_parse_error() - self.flushCodepointsConsumedAsACharacterReference() - return reconsume(currentInputCharacter, in: self.returnState) - } - // 13.2.5.78 Hexadecimal character reference state, https://html.spec.whatwg.org/multipage/parsing.html#hexadecimal-character-reference-state - case .HexadecimalCharacterReference: - switch currentInputCharacter { - case let c? where HTMLTokenizer.asciiDigit.contains(c.unicodeScalars.first!): - self.characterReferenceCode = self.characterReferenceCode * 16 + Int(c.asciiValue! - 0x30) - return continueInCurrentState() - case let c? where HTMLTokenizer.asciiUpperHexDigit.contains(c.unicodeScalars.first!): - self.characterReferenceCode = self.characterReferenceCode * 16 + Int(c.asciiValue! - 0x37) - return continueInCurrentState() - case let c? where HTMLTokenizer.asciiLowerHexDigit.contains(c.unicodeScalars.first!): - self.characterReferenceCode = self.characterReferenceCode * 16 + Int(c.asciiValue! - 0x57) - return continueInCurrentState() - case ";": - return switchTo(.NumericCharacterReferenceEnd) - default: - // FIXME: log_parse_error() - return reconsume(currentInputCharacter, in: .NumericCharacterReferenceEnd) - } - - // 13.2.5.79 Decimal character reference state, https://html.spec.whatwg.org/multipage/parsing.html#decimal-character-reference-state - case .DecimalCharacterReference: - switch currentInputCharacter { - case let c? where HTMLTokenizer.asciiDigit.contains(c.unicodeScalars.first!): - self.characterReferenceCode = self.characterReferenceCode * 10 + Int(c.asciiValue! - 0x30) - return continueInCurrentState() - case ";": - return switchTo(.NumericCharacterReferenceEnd) - default: - // FIXME: log_parse_error() - return reconsume(currentInputCharacter, in: .NumericCharacterReferenceEnd) - } - - // 13.2.5.80 Numeric character reference end state, https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state - case .NumericCharacterReferenceEnd: - dontConsumeNextInputCharacter() - let codePoint: UnicodeScalar = - switch self.characterReferenceCode { - case 0x00: - // FIXME: log_parse_error() - UnicodeScalar(0xFFFD)! - case let c where c > 0x10FFFF: - // FIXME: log_parse_error() - UnicodeScalar(0xFFFD)! - case let c where UTF16.CodeUnit(exactly: c).map({ UTF16.isSurrogate($0) }) != nil: - // FIXME: log_parse_error() - UnicodeScalar(0xFFFD)! - case let c where UnicodeScalar(c)! == "\u{000D}" || HTMLTokenizer.controlNotAsciiWhitespace.contains(UnicodeScalar(c)!): - // FIXME: log_parse_error() - if let codePoint = HTMLTokenizer.characterReferenceControlCodeMapping[c] { - codePoint - } else { - UnicodeScalar(c)! - } - case let c where HTMLTokenizer.nonCharacter.contains(UnicodeScalar(c)!): - // FIXME: log_parse_error() - UnicodeScalar(c)! - default: - UnicodeScalar(self.characterReferenceCode)! - } - - self.temporaryBuffer = Swift.String(Character(codePoint)) - self.flushCodepointsConsumedAsACharacterReference() - return switchTo(self.returnState) - } - } -} diff --git a/Libraries/LibWeb/HTML/Parser/HTMLTokenizerHelpers.cpp b/Libraries/LibWeb/HTML/Parser/HTMLTokenizerHelpers.cpp deleted file mode 100644 index 71626b687a..0000000000 --- a/Libraries/LibWeb/HTML/Parser/HTMLTokenizerHelpers.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -namespace Web::HTML { - -OptionalString decode_to_utf8(StringView text, StringView encoding) -{ - auto decoder = TextCodec::decoder_for(encoding); - if (!decoder.has_value()) - return std::nullopt; - auto decoded_or_error = decoder.value().to_utf8(text); - if (decoded_or_error.is_error()) - return std::nullopt; - return decoded_or_error.release_value(); -} - -OptionalEntityMatch match_entity_for_named_character_reference(StringView entity) -{ - NamedCharacterReferenceMatcher matcher; - int consumed_length = 0; - for (auto c : entity) { - if (!matcher.try_consume_ascii_char(c)) - break; - consumed_length++; - } - - auto codepoints = matcher.code_points(); - if (codepoints.has_value()) { - EntityMatch match; - auto matched_length = consumed_length - matcher.overconsumed_code_points(); - auto matched_string_view = entity.substring_view(0, matched_length); - auto second_codepoint = named_character_reference_second_codepoint_value(codepoints.value().second); - if (second_codepoint.has_value()) { - match = { { codepoints.value().first, second_codepoint.release_value() }, matched_string_view }; - } else { - match = { { codepoints.value().first }, matched_string_view }; - } - return match; - } - return std::nullopt; -} - -} diff --git a/Libraries/LibWeb/HTML/Parser/HTMLTokenizerHelpers.h b/Libraries/LibWeb/HTML/Parser/HTMLTokenizerHelpers.h deleted file mode 100644 index a0f40aaf48..0000000000 --- a/Libraries/LibWeb/HTML/Parser/HTMLTokenizerHelpers.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace Web::HTML { - -// FIXME: This is a temporary stop-gap solution, and it should be removed once the C++ -// NamedCharacterReference state implementation is implemented in Swift. -struct EntityMatch { - Vector code_points; - StringView entity; -}; - -// Swift-friendly wrapper for TextCodec::Decoder::to_utf8 -using OptionalString = std::optional; -OptionalString decode_to_utf8(StringView text, StringView encoding); - -// Swift-friendly wrapper for HTML::code_points_from_entity -// FIXME: This is a temporary stop-gap solution, and it should be removed once the C++ -// NamedCharacterReference state implementation is implemented in Swift. -using OptionalEntityMatch = std::optional; -OptionalEntityMatch match_entity_for_named_character_reference(StringView entity); - -} diff --git a/Libraries/LibWeb/HTML/Parser/SpeculativeHTMLParser.swift b/Libraries/LibWeb/HTML/Parser/SpeculativeHTMLParser.swift deleted file mode 100644 index 06cb556820..0000000000 --- a/Libraries/LibWeb/HTML/Parser/SpeculativeHTMLParser.swift +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2025, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -import AK -import Collections -import Foundation -import GC -@_exported import WebCxx - -// Workaround for https://github.com/swiftlang/swift/issues/80231 -// If any line of this changes, the whole thing breaks though -extension GC.Cell.Visitor { - public func visit(_ parser: Web.HTML.HTMLParserGCPtr) { - if let parser = parser.ptr() { - let cell: GC.Cell = cxxCast(parser) - visit(cell) - } - } -} - -struct SpeculativeMockElement { - let name: Swift.String - let localName: Swift.String - let attributes: [HTMLToken.Attribute] - var children: [SpeculativeMockElement] - - init(name: Swift.String, localName: Swift.String, attributes: [HTMLToken.Attribute]) { - self.name = name - self.localName = localName - self.attributes = attributes - self.children = [] - } - - mutating func appendChild(_ child: consuming SpeculativeMockElement) { - children.append(child) - } -} - -public final class SpeculativeHTMLParser: HeapAllocatable { - var parser = Web.HTML.HTMLParserGCPtr() // FIXME: Want HTMLParserGCRef here, but how to initialize it? - - public init(cell: GC.Cell) { - self.cell = cell - } - public var cell: GC.Cell - - public static func create(on heap: GC.Heap, `for` parser: Web.HTML.HTMLParserGCPtr) -> GC.Cell { - precondition(heap.is_gc_deferred()) - let _self = allocate(on: heap) - _self.pointee.parser = parser - return _self.pointee.cell - } - - public func visitEdges(_ visitor: GC.Cell.Visitor) { - visitor.visit(parser) - } -} diff --git a/Libraries/LibWeb/Loader/FileRequest.h b/Libraries/LibWeb/Loader/FileRequest.h index a186aa853d..5960a083fc 100644 --- a/Libraries/LibWeb/Loader/FileRequest.h +++ b/Libraries/LibWeb/Loader/FileRequest.h @@ -9,7 +9,6 @@ #include #include #include -#include #include namespace Web { @@ -24,6 +23,6 @@ public: private: ByteString m_path {}; -} SWIFT_UNSAFE_REFERENCE; // FIXME: This type is actually move-only, not unsafe +}; } diff --git a/Libraries/LibWebView/Application.h b/Libraries/LibWebView/Application.h index 9c067fc9a8..a8ecbbe821 100644 --- a/Libraries/LibWebView/Application.h +++ b/Libraries/LibWebView/Application.h @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -268,7 +267,7 @@ private: OwnPtr m_devtools; mutable HashMap m_navigation_listener_ids; -} SWIFT_IMMORTAL_REFERENCE; +}; } diff --git a/Meta/CMake/FindBlocksRuntime.cmake b/Meta/CMake/FindBlocksRuntime.cmake index b8ed277c1d..b11bc57808 100644 --- a/Meta/CMake/FindBlocksRuntime.cmake +++ b/Meta/CMake/FindBlocksRuntime.cmake @@ -1,9 +1,7 @@ # Finds the BlocksRuntime library # On Apple platforms, this does not exist and is folded into other System libraries -find_library(BLOCKS_RUNTIME NAMES BlocksRuntime - PATHS ${SWIFT_LIBRARY_SEARCH_PATHS} -) +find_library(BLOCKS_RUNTIME NAMES BlocksRuntime) if (BLOCKS_RUNTIME) if (NOT TARGET BlocksRuntime::BlocksRuntime) add_library(BlocksRuntime::BlocksRuntime IMPORTED UNKNOWN) @@ -12,7 +10,7 @@ if (BLOCKS_RUNTIME) set_target_properties(BlocksRuntime::BlocksRuntime PROPERTIES IMPORTED_LOCATION "${BLOCKS_RUNTIME}" INTERFACE_LINK_DIRECTORIES "${_BLOCKS_RUNTIME_DIR}" - INTERFACE_COMPILE_OPTIONS "$<$:-fblocks>;SHELL:$<$:-Xcc -fblocks>" + INTERFACE_COMPILE_OPTIONS "$<$:-fblocks>" ) endif() set(BlocksRuntime_FOUND TRUE) diff --git a/Meta/CMake/FindSwiftTesting.cmake b/Meta/CMake/FindSwiftTesting.cmake deleted file mode 100644 index e0a7d4f2cd..0000000000 --- a/Meta/CMake/FindSwiftTesting.cmake +++ /dev/null @@ -1,60 +0,0 @@ -# Finds the swift-testing library -# On Apple platforms, this is a framework included in the Xcode release -include_guard() - -if (NOT TARGET SwiftTesting::SwiftTesting) - cmake_policy(PUSH) - if (POLICY CMP0152) - cmake_policy(SET CMP0152 NEW) - endif() - - set(_SEARCH_PATHS "") - set(_PLUGIN_PATHS "") - foreach(path IN LISTS SWIFT_LIBRARY_SEARCH_PATHS) - file(REAL_PATH ${path} real_path) - if (EXISTS ${real_path}) - list(APPEND _SEARCH_PATHS ${real_path}) - if (EXISTS "${real_path}/testing") - list(APPEND _SEARCH_PATHS "${real_path}/testing") - endif() - endif() - if (EXISTS "${real_path}/../host/plugins") - file(REAL_PATH "${real_path}/../host/plugins" plugin_path) - list(APPEND _PLUGIN_PATHS ${plugin_path}) - if (EXISTS "${plugin_path}/testing") - list(APPEND _PLUGIN_PATHS "${plugin_path}/testing") - endif() - endif() - endforeach() - list(REMOVE_DUPLICATES _SEARCH_PATHS) - list(REMOVE_DUPLICATES _PLUGIN_PATHS) - - find_library(SWIFT_TESTING NAMES Testing - PATHS ${_SEARCH_PATHS} - ) - if (SWIFT_TESTING) - add_library(SwiftTesting::SwiftTesting IMPORTED UNKNOWN) - message(STATUS "Found SwiftTesting: ${SWIFT_TESTING}") - cmake_path(GET SWIFT_TESTING PARENT_PATH _SWIFT_TESTING_DIR) - - find_library(SWIFT_TESTING_MACROS NAMES TestingMacros - PATHS ${_PLUGIN_PATHS} - NO_DEFAULT_PATH - ) - if (NOT SWIFT_TESTING_MACROS) - message(FATAL_ERROR "Could not find associated TestingMacros plugin for ${SWIFT_TESTING}") - else() - message(VERBOSE "Found SwiftTesting macros: ${SWIFT_TESTING_MACROS}") - endif() - - set_target_properties(SwiftTesting::SwiftTesting PROPERTIES - IMPORTED_LOCATION "${SWIFT_TESTING}" - INTERFACE_LINK_DIRECTORIES "${_SWIFT_TESTING_DIR}" - INTERFACE_INCLUDE_DIRECTORIES "${_SWIFT_TESTING_DIR}" - INTERFACE_COMPILE_OPTIONS "$<$:SHELL:-load-plugin-library ${SWIFT_TESTING_MACROS}>" - INTERFACE_LINK_OPTIONS "-load-plugin-library;${SWIFT_TESTING_MACROS}" - ) - set(SwiftTesting_FOUND TRUE) - endif() - cmake_policy(POP) -endif() diff --git a/Meta/CMake/Swift/GenerateSwiftHeader.cmake b/Meta/CMake/Swift/GenerateSwiftHeader.cmake deleted file mode 100644 index e7606a569d..0000000000 --- a/Meta/CMake/Swift/GenerateSwiftHeader.cmake +++ /dev/null @@ -1,92 +0,0 @@ -# This source file is part of the Swift open source project -# -# Copyright (c) 2023 Apple Inc. and the Swift project authors. -# Licensed under Apache License v2.0 with Runtime Library Exception -# -# See https://swift.org/LICENSE.txt for license information - - -# Generate the bridging header from Swift to C++ -# -# target: the name of the target to generate headers for. -# This target must build swift source files. -# header: the name of the header file to generate. -# -# NOTE: This logic will eventually be unstreamed into CMake. -function(_swift_generate_cxx_header target header) - if(NOT TARGET ${target}) - message(FATAL_ERROR "Target ${target} not defined.") - endif() - - if(NOT DEFINED CMAKE_Swift_COMPILER) - message(WARNING "Swift not enabled in project. Cannot generate headers for Swift files.") - return() - endif() - - cmake_parse_arguments(PARSE_ARGV 2 "ARG" "" "MODULE_NAME;CXX_STD_VERSION" "SEARCH_PATHS;COMPILE_OPTIONS") - - if(NOT ARG_MODULE_NAME) - set(target_module_name $) - set(ARG_MODULE_NAME $,${target_module_name},${target}>) - endif() - - if(ARG_SEARCH_PATHS) - list(TRANSFORM ARG_SEARCH_PATHS PREPEND "-I") - endif() - - if(APPLE) - set(SDK_FLAGS "-sdk" "${CMAKE_OSX_SYSROOT}") - list(APPEND SDK_FLAGS "-target" "${CMAKE_Swift_COMPILER_TARGET}") - elseif(WIN32) - set(SDK_FLAGS "-sdk" "$ENV{SDKROOT}") - elseif(DEFINED ${CMAKE_SYSROOT}) - set(SDK_FLAGS "-sdk" "${CMAKE_SYSROOT}") - list(APPEND SDK_FLAGS "-target" "${CMAKE_Swift_COMPILER_TARGET}") - endif() - - cmake_path(APPEND CMAKE_CURRENT_BINARY_DIR include - OUTPUT_VARIABLE base_path) - - cmake_path(APPEND base_path ${header} - OUTPUT_VARIABLE header_path) - - if (NOT ARG_CXX_STD_VERSION) - set(ARG_CXX_STD_VERSION "14") - get_target_property(CxxFeatures ${target} COMPILE_FEATURES) - list(FILTER CxxFeatures INCLUDE REGEX "cxx_std_[0-9]+$") - if (NOT "${CxxFeatures}" STREQUAL "") - string(SUBSTRING ${CxxFeatures} 8 2 ARG_CXX_STD_VERSION) - endif() - endif() - - set(CXX_STD_FLAGS -Xcc -std=c++${ARG_CXX_STD_VERSION}) - - set(_AllSources $) - set(_SwiftSources $) - add_custom_command(OUTPUT ${header_path} - DEPENDS ${_SwiftSources} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND - ${CMAKE_Swift_COMPILER} -frontend -typecheck - ${ARG_SEARCH_PATHS} - ${_SwiftSources} - ${SDK_FLAGS} - ${CXX_STD_FLAGS} - ${ARG_COMPILE_OPTIONS} - -Xcc -Wno-unqualified-std-cast-call - -Xcc -Wno-user-defined-literals - -Xcc -Wno-unknown-warning-option - -Xcc -Wno-invalid-offsetof - -module-name "${ARG_MODULE_NAME}" - -cxx-interoperability-mode=default - -emit-clang-header-path ${header_path} - COMMENT - "Generating '${header_path}'" - COMMAND_EXPAND_LISTS) - - # Added to public interface for dependees to find. - target_include_directories(${target} PUBLIC $) - # Added to the target to ensure target rebuilds if header changes and is used - # by sources in the target. - target_sources(${target} PRIVATE ${header_path}) -endfunction() diff --git a/Meta/CMake/Swift/InitializeSwift.cmake b/Meta/CMake/Swift/InitializeSwift.cmake deleted file mode 100644 index 532c23767b..0000000000 --- a/Meta/CMake/Swift/InitializeSwift.cmake +++ /dev/null @@ -1,109 +0,0 @@ -# This source file is part of the Swift open source project -# -# Copyright (c) 2023 Apple Inc. and the Swift project authors. -# Licensed under Apache License v2.0 with Runtime Library Exception -# -# See https://swift.org/LICENSE.txt for license information - -# Compute the name of the architecture directory on Windows from the CMake -# system processor name. -function(_swift_windows_arch_name output_variable_name target_arch) - if(NOT WIN32) - return() - endif() - - if("${target_arch}" STREQUAL "AMD64") - set("${output_variable_name}" "x86_64" PARENT_SCOPE) - elseif("${target_arch}" STREQUAL "ARM64") - set("${output_variable_name}" "aarch64" PARENT_SCOPE) - else() - message(FATAL_ERROR "Unknown windows architecture: ${target_arch}") - endif() -endfunction() - -# Compute flags and search paths -# NOTE: This logic will eventually move to CMake -function(_setup_swift_paths) - # If we haven't set the swift library search paths, do that now - if(NOT SWIFT_LIBRARY_SEARCH_PATHS OR NOT SWIFT_INCLUDE_PATHS OR (APPLE AND NOT SWIFT_TARGET_TRIPLE)) - if(APPLE) - set(SDK_FLAGS "-sdk" "${CMAKE_OSX_SYSROOT}") - endif() - - # Note: This does not handle cross-compiling correctly. - # To handle it correctly, we would need to pass the target triple and - # flags to this compiler invocation. - execute_process( - COMMAND ${CMAKE_Swift_COMPILER} ${SDK_FLAGS} -print-target-info - OUTPUT_VARIABLE SWIFT_TARGET_INFO - ) - - # FIXME: https://gitlab.kitware.com/cmake/cmake/-/issues/26174 - if (APPLE) - if (CMAKE_OSX_DEPLOYMENT_TARGET) - set(SWIFT_TARGET_TRIPLE "${CMAKE_SYSTEM_PROCESSOR}-apple-macosx${CMAKE_OSX_DEPLOYMENT_TARGET}" CACHE STRING "Swift target triple") - else() - string(JSON SWIFT_TARGET_TARGET GET ${SWIFT_TARGET_INFO} "target") - string(JSON SWIFT_TARGET_TARGET_TRIPLE GET ${SWIFT_TARGET_TARGET} "triple") - set(SWIFT_TARGET_TRIPLE ${SWIFT_TARGET_TARGET_TRIPLE} CACHE STRING "Swift target triple") - endif() - endif() - - # extract search paths from swift driver response - string(JSON SWIFT_TARGET_PATHS GET ${SWIFT_TARGET_INFO} "paths") - - string(JSON SWIFT_TARGET_LIBRARY_PATHS GET ${SWIFT_TARGET_PATHS} "runtimeLibraryPaths") - string(JSON SWIFT_TARGET_LIBRARY_PATHS_LENGTH LENGTH ${SWIFT_TARGET_LIBRARY_PATHS}) - math(EXPR SWIFT_TARGET_LIBRARY_PATHS_LENGTH "${SWIFT_TARGET_LIBRARY_PATHS_LENGTH} - 1 ") - - string(JSON SWIFT_TARGET_LIBRARY_IMPORT_PATHS GET ${SWIFT_TARGET_PATHS} "runtimeLibraryImportPaths") - string(JSON SWIFT_TARGET_LIBRARY_IMPORT_PATHS_LENGTH LENGTH ${SWIFT_TARGET_LIBRARY_IMPORT_PATHS}) - math(EXPR SWIFT_TARGET_LIBRARY_IMPORT_PATHS_LENGTH "${SWIFT_TARGET_LIBRARY_IMPORT_PATHS_LENGTH} - 1 ") - - string(JSON SWIFT_SDK_IMPORT_PATH ERROR_VARIABLE errno GET ${SWIFT_TARGET_PATHS} "sdkPath") - - foreach(JSON_ARG_IDX RANGE ${SWIFT_TARGET_LIBRARY_PATHS_LENGTH}) - string(JSON SWIFT_LIB GET ${SWIFT_TARGET_LIBRARY_PATHS} ${JSON_ARG_IDX}) - list(APPEND SWIFT_SEARCH_PATHS ${SWIFT_LIB}) - endforeach() - - foreach(JSON_ARG_IDX RANGE ${SWIFT_TARGET_LIBRARY_IMPORT_PATHS_LENGTH}) - string(JSON SWIFT_LIB GET ${SWIFT_TARGET_LIBRARY_IMPORT_PATHS} ${JSON_ARG_IDX}) - list(APPEND SWIFT_SEARCH_PATHS ${SWIFT_LIB}) - endforeach() - - if(SWIFT_SDK_IMPORT_PATH) - list(APPEND SWIFT_SEARCH_PATHS ${SWIFT_SDK_IMPORT_PATH}) - endif() - - # Save the swift library search paths - set(SWIFT_LIBRARY_SEARCH_PATHS ${SWIFT_SEARCH_PATHS} CACHE FILEPATH "Swift driver search paths") - - string(JSON SWIFT_RUNTIME_RESOURCE_PATH GET ${SWIFT_TARGET_PATHS} "runtimeResourcePath") - set(SWIFT_TOOLCHAIN_INCLUDE_DIR "${SWIFT_RUNTIME_RESOURCE_PATH}/../../include") - cmake_path(ABSOLUTE_PATH SWIFT_TOOLCHAIN_INCLUDE_DIR NORMALIZE) - if (NOT IS_DIRECTORY "${SWIFT_TOOLCHAIN_INCLUDE_DIR}") - message(WARNING "Expected toolchain include dir ${SWIFT_TOOLCHAIN_INCLUDE_DIR} does not exist") - endif() - set(SWIFT_INCLUDE_PATHS ${SWIFT_TOOLCHAIN_INCLUDE_DIR} CACHE FILEPATH "Swift interop include paths") - endif() - - link_directories(${SWIFT_LIBRARY_SEARCH_PATHS}) - include_directories(${SWIFT_INCLUDE_PATHS}) - - if(WIN32) - _swift_windows_arch_name(SWIFT_WIN_ARCH_DIR "${CMAKE_SYSTEM_PROCESSOR}") - set(SWIFT_SWIFTRT_FILE "$ENV{SDKROOT}/usr/lib/swift/windows/${SWIFT_WIN_ARCH_DIR}/swiftrt.obj") - add_link_options("$<$:${SWIFT_SWIFTRT_FILE}>") - elseif(NOT APPLE) - find_file(SWIFT_SWIFTRT_FILE - swiftrt.o - PATHS ${SWIFT_LIBRARY_SEARCH_PATHS} - NO_CACHE - REQUIRED - NO_DEFAULT_PATH) - add_link_options("$<$:${SWIFT_SWIFTRT_FILE}>") - endif() -endfunction() - -_setup_swift_paths() diff --git a/Meta/CMake/Swift/swift-settings.cmake b/Meta/CMake/Swift/swift-settings.cmake deleted file mode 100644 index d58a43f05f..0000000000 --- a/Meta/CMake/Swift/swift-settings.cmake +++ /dev/null @@ -1,82 +0,0 @@ -enable_language(Swift) - -if (CMAKE_Swift_COMPILER_VERSION VERSION_LESS 6.0) - message(FATAL_ERROR "Swift 6.0 or newer is required to parse C++ headers in C++23 mode") -endif() - -# Check for a Swift-aware clang -include(CheckCXXSourceCompiles) -check_cxx_source_compiles([=[ - struct __attribute__((swift_name("CxxS"))) __attribute__((swift_attr("~Copyable"))) S { int& x; }; - int main() {} -]=] CXX_COMPILER_SUPPORTS_SWIFT_ATTRS) -if (NOT CXX_COMPILER_SUPPORTS_SWIFT_ATTRS) - message(FATAL_ERROR "A Swift-aware C++ compiler is required to build with Swift interop enabled") -endif() - -include(${CMAKE_CURRENT_LIST_DIR}/InitializeSwift.cmake) -include(${CMAKE_CURRENT_LIST_DIR}/GenerateSwiftHeader.cmake) - -find_package(SwiftTesting REQUIRED) - -# FIXME: https://gitlab.kitware.com/cmake/cmake/-/issues/26174 -if (APPLE) - set(CMAKE_Swift_COMPILER_TARGET "${SWIFT_TARGET_TRIPLE}") -endif() - -add_compile_options("SHELL:$<$:-enable-experimental-feature Extern>") - -set(VFS_OVERLAY_DIRECTORY "${CMAKE_BINARY_DIR}/vfs_overlays" CACHE PATH "Directory to put VFS overlays in") - -# FIXME: https://gitlab.kitware.com/cmake/cmake/-/issues/26195 -# For now, we'll just manually massage the flags. -function(swizzle_target_properties_for_swift target_name) - get_property(compile_options TARGET ${target_name} PROPERTY INTERFACE_COMPILE_OPTIONS) - set(munged_properties "") - foreach(property IN LISTS compile_options) - set(cxx_property "$<$:${property}>") - set(swift_property "SHELL:$<$:-Xcc ${property}>") - list(APPEND munged_properties "${cxx_property}" "${swift_property}") - endforeach() - set_property(TARGET ${target_name} PROPERTY INTERFACE_COMPILE_OPTIONS ${munged_properties}) -endfunction() - -function(add_swift_target_properties target_name) - cmake_parse_arguments(PARSE_ARGV 1 SWIFT_TARGET "" "" "LAGOM_LIBRARIES;COMPILE_DEFINITIONS;COMPILE_OPTIONS") - - target_compile_features(${target_name} PUBLIC cxx_std_${CMAKE_CXX_STANDARD}) - target_compile_options(${target_name} PUBLIC "SHELL:$<$:-Xcc -std=c++23 -cxx-interoperability-mode=default>") - - string(REPLACE "Lib" "" module_name ${target_name}) - - string(TOUPPER ${target_name} TARGET_NAME_UPPER) - target_compile_definitions(${target_name} PRIVATE "${TARGET_NAME_UPPER}_USE_SWIFT") - set_target_properties(${target_name} PROPERTIES Swift_MODULE_NAME ${module_name}) - - # FIXME: These should be pulled automatically from interface compile options for the target - set(VFS_OVERLAY_OPTIONS "-Xcc" "-ivfsoverlay${VFS_OVERLAY_DIRECTORY}/${target_name}_vfs_overlay.yaml") - foreach(internal_library IN LISTS SWIFT_TARGET_LAGOM_LIBRARIES) - list(APPEND VFS_OVERLAY_OPTIONS "-Xcc" "-ivfsoverlay${VFS_OVERLAY_DIRECTORY}/${internal_library}_vfs_overlay.yaml") - endforeach() - - get_target_property(_NATIVE_DIRS ${target_name} INCLUDE_DIRECTORIES) - list(APPEND _NATIVE_DIRS ${CMAKE_Swift_MODULE_DIRECTORY}) - - # Swift-testing in swift.org toolchains on macOS has its .swiftmodule in a testing/ subdirectory of - # the swift compiler's built-in lib dirs. - get_target_property(DEPENDENCIES ${target_name} LINK_LIBRARIES) - if (SwiftTesting::SwiftTesting IN_LIST DEPENDENCIES) - get_target_property(SWIFT_TESTING_INCLUDE_DIRS SwiftTesting::SwiftTesting INTERFACE_INCLUDE_DIRECTORIES) - list(APPEND _NATIVE_DIRS ${SWIFT_TESTING_INCLUDE_DIRS}) - endif() - - set(EXTRA_COMPILE_DEFINITIONS "") - foreach (compile_definition IN LISTS SWIFT_TARGET_COMPILE_DEFINITIONS) - list(APPEND EXTRA_COMPILE_DEFINITIONS "-Xcc" "-D${compile_definition}") - endforeach() - - _swift_generate_cxx_header(${target_name} "${target_name}-Swift.h" - SEARCH_PATHS ${_NATIVE_DIRS} - COMPILE_OPTIONS ${VFS_OVERLAY_OPTIONS} ${EXTRA_COMPILE_DEFINITIONS} ${SWIFT_TARGET_COMPILE_OPTIONS} - ) -endfunction() diff --git a/Meta/CMake/code_generators.cmake b/Meta/CMake/code_generators.cmake index 150ead497c..9418e59c58 100644 --- a/Meta/CMake/code_generators.cmake +++ b/Meta/CMake/code_generators.cmake @@ -23,40 +23,6 @@ function(embed_as_string name source_file output source_variable_name) add_dependencies(ladybird_codegen_accumulator "generate_${name}") endfunction() -function(generate_clang_module_map target_name) - cmake_parse_arguments(PARSE_ARGV 1 MODULE_MAP "" "DIRECTORY" "GENERATED_FILES;EXCLUDE_FILES") - if (NOT MODULE_MAP_DIRECTORY) - set(MODULE_MAP_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") - endif() - - string(REPLACE "Lib" "" module_name ${target_name}) - set(module_name "${module_name}Cxx") - - set(module_map_file "${CMAKE_CURRENT_BINARY_DIR}/module/module.modulemap") - set(vfs_overlay_file "${VFS_OVERLAY_DIRECTORY}/${target_name}_vfs_overlay.yaml") - - find_package(Python3 REQUIRED COMPONENTS Interpreter) - # FIXME: Make this depend on the public headers of the target - add_custom_command( - OUTPUT "${module_map_file}" - COMMAND "${Python3_EXECUTABLE}" "${SerenityOS_SOURCE_DIR}/Meta/generate_clang_module_map.py" - "${MODULE_MAP_DIRECTORY}" - --module-name "${module_name}" - --module-map "${module_map_file}" - --vfs-map ${vfs_overlay_file} - --exclude-files ${MODULE_MAP_EXCLUDE_FILES} - --generated-files ${MODULE_MAP_GENERATED_FILES} - VERBATIM - DEPENDS "${SerenityOS_SOURCE_DIR}/Meta/generate_clang_module_map.py" - ) - - add_custom_target("generate_${target_name}_module_map" DEPENDS "${module_map_file}") - add_dependencies(ladybird_codegen_accumulator "generate_${target_name}_module_map") - add_dependencies("${target_name}" "generate_${target_name}_module_map") - - target_compile_options(${target_name} PUBLIC "SHELL:$<$:-Xcc -ivfsoverlay${vfs_overlay_file}>") -endfunction() - function(compile_ipc source output) if (NOT IS_ABSOLUTE ${source}) set(source ${CMAKE_CURRENT_SOURCE_DIR}/${source}) diff --git a/Meta/CMake/collections.cmake b/Meta/CMake/collections.cmake deleted file mode 100644 index 3fb9e7e66a..0000000000 --- a/Meta/CMake/collections.cmake +++ /dev/null @@ -1,25 +0,0 @@ -include_guard(GLOBAL) - -include(FetchContent) - -set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE OPT_IN) -FetchContent_Declare(SwiftCollections - GIT_REPOSITORY https://github.com/apple/swift-collections.git - GIT_TAG 1.1.2 - PATCH_COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/patches/git-patch.cmake" - "${CMAKE_CURRENT_LIST_DIR}/patches/swift-collections/0001-CMake-Remove-top-level-binary-module-locations.patch" - OVERRIDE_FIND_PACKAGE -) - -set(BUILD_TESTING_SAVE ${BUILD_TESTING}) -set(BUILD_TESTING OFF) -set(BUILD_EXAMPLES OFF) - -# FIXME: https://github.com/apple/swift-collections/issues/440 -set(BUILD_SHARED_LIBS_SAVE ${BUILD_SHARED_LIBS}) -set(BUILD_SHARED_LIBS OFF) - -FetchContent_MakeAvailable(SwiftCollections) - -set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_SAVE}) -set(BUILD_TESTING ${BUILD_TESTING_SAVE}) diff --git a/Meta/CMake/common_compile_options.cmake b/Meta/CMake/common_compile_options.cmake index 52d1300fc2..0e6f6fae42 100644 --- a/Meta/CMake/common_compile_options.cmake +++ b/Meta/CMake/common_compile_options.cmake @@ -11,7 +11,6 @@ macro(add_cxx_compile_options) set(args "") foreach(arg ${ARGN}) string(APPEND args ${arg}$) - add_compile_options("SHELL:$<$:-Xcc ${arg}>") endforeach() add_compile_options($<$:${args}>) endmacro() @@ -20,7 +19,6 @@ macro(add_cxx_compile_definitions) set(args "") foreach(arg ${ARGN}) string(APPEND args ${arg}$) - add_compile_options("SHELL:$<$:-Xcc -D${arg}>") endforeach() add_compile_definitions($<$:${args}>) endmacro() @@ -33,22 +31,6 @@ macro(add_cxx_link_options) add_link_options($<$:${args}>) endmacro() -macro(add_swift_compile_options) - set(args "") - foreach(arg ${ARGN}) - string(APPEND args ${arg}$) - endforeach() - add_compile_options($<$:${args}>) -endmacro() - -macro(add_swift_link_options) - set(args "") - foreach(arg ${ARGN}) - string(APPEND args ${arg}$) - endforeach() - add_link_options($<$:${args}>) -endmacro() - include(CheckLinkerFlag) include(CMakePushCheckState) function(add_cxx_link_option_if_supported option) diff --git a/Meta/CMake/common_options.cmake b/Meta/CMake/common_options.cmake index 013485b442..a3152d063c 100644 --- a/Meta/CMake/common_options.cmake +++ b/Meta/CMake/common_options.cmake @@ -3,12 +3,6 @@ if (POLICY CMP0116) cmake_policy(SET CMP0116 NEW) endif() -# Enable better flags for configuring swift compilation mode -if (POLICY CMP0157) - cmake_policy(SET CMP0157 NEW) - set(CMAKE_Swift_COMPILATION_MODE "$,wholemodule,incremental>") -endif() - # Check arguments to return() if (POLICY CMP0140) cmake_policy(SET CMP0140 NEW) @@ -39,7 +33,6 @@ endif() ladybird_option(ENABLE_GUI_TARGETS ON CACHE BOOL "Enable building GUI targets") ladybird_option(ENABLE_INSTALL_HEADERS ON CACHE BOOL "Enable installing headers") ladybird_option(ENABLE_INSTALL_FREEDESKTOP_FILES ${freedesktop_files_default} CACHE BOOL "Enable installing .desktop and .service files") -ladybird_option(ENABLE_SWIFT OFF CACHE BOOL "Enable building Swift files") ladybird_option(LADYBIRD_ENABLE_CPPTRACE ON CACHE BOOL "Enable use of cpptrace as the default library for stacktraces. If not available falls back to backtrace.h") ladybird_option(ENABLE_CI_BASELINE_CPU OFF CACHE BOOL "Use a baseline CPU target for improved ccache sharing") @@ -48,10 +41,6 @@ if (ENABLE_FUZZERS_LIBFUZZER) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY CACHE STRING "Type of target to use for try_compile()" FORCE) endif() -if (ENABLE_SWIFT) - include(${CMAKE_CURRENT_LIST_DIR}/Swift/swift-settings.cmake) -endif() - include(CheckCXXSourceCompiles) set(BLOCKS_REQUIRED_LIBRARIES "") if (NOT APPLE) diff --git a/Meta/CMake/lagom_install_options.cmake b/Meta/CMake/lagom_install_options.cmake index 97f10d5b49..4f97f6c73b 100644 --- a/Meta/CMake/lagom_install_options.cmake +++ b/Meta/CMake/lagom_install_options.cmake @@ -15,10 +15,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${IN_BUILD_PREFIX}${CMAK set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${IN_BUILD_PREFIX}${CMAKE_INSTALL_LIBDIR}") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${IN_BUILD_PREFIX}${CMAKE_INSTALL_LIBDIR}") -# FIXME: Stop setting this when we have a good way to retrieve the directory that has the swift module -# file for use by the swift frontend's header generator -set(CMAKE_Swift_MODULE_DIRECTORY "${CMAKE_BINARY_DIR}/${IN_BUILD_PREFIX}swift") - set(CMAKE_SKIP_BUILD_RPATH FALSE) if ("${VCPKG_INSTALLED_DIR}" STREQUAL "") diff --git a/Meta/CMake/patches/swift-collections/0001-CMake-Remove-top-level-binary-module-locations.patch b/Meta/CMake/patches/swift-collections/0001-CMake-Remove-top-level-binary-module-locations.patch deleted file mode 100644 index fe64feb273..0000000000 --- a/Meta/CMake/patches/swift-collections/0001-CMake-Remove-top-level-binary-module-locations.patch +++ /dev/null @@ -1,170 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Andrew Kaster -Date: Thu, 22 Aug 2024 20:51:38 -0600 -Subject: [PATCH] CMake: Remove top-level binary/module locations - ---- - CMakeLists.txt | 13 +++++-------- - Sources/BitCollections/CMakeLists.txt | 2 -- - Sources/CMakeLists.txt | 2 -- - Sources/Collections/CMakeLists.txt | 4 ++-- - Sources/DequeModule/CMakeLists.txt | 2 -- - Sources/HashTreeCollections/CMakeLists.txt | 2 -- - Sources/HeapModule/CMakeLists.txt | 2 -- - Sources/InternalCollectionsUtilities/CMakeLists.txt | 2 -- - Sources/OrderedCollections/CMakeLists.txt | 2 -- - Sources/RopeModule/CMakeLists.txt | 2 -- - 10 files changed, 7 insertions(+), 26 deletions(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 939a29e48ee386c0dac32350c6f6dfb4c4279170..2692814e02971e1469fc236a89c825a5c1547932 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -11,22 +11,19 @@ if(POLICY CMP0091) - cmake_policy(SET CMP0091 NEW) - endif() - -+if(POLICY CMP0157) -+ cmake_policy(SET CMP0157 OLD) -+endif() -+ -+ - cmake_minimum_required(VERSION 3.16) - project(SwiftCollections - LANGUAGES C Swift) - - list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) - --set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift) - set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) - --set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift) --set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) -- --set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) --set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) --set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -- - set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) - - if(CMAKE_SYSTEM_NAME STREQUAL Windows OR CMAKE_SYSTEM_NAME STREQUAL Darwin) -diff --git a/Sources/BitCollections/CMakeLists.txt b/Sources/BitCollections/CMakeLists.txt -index c5becdeec08a91978aa8b00dc2fc272299ca16b0..3f52e47220362de9c47e3e2527a2b78260d6f45e 100644 ---- a/Sources/BitCollections/CMakeLists.txt -+++ b/Sources/BitCollections/CMakeLists.txt -@@ -15,8 +15,6 @@ else() - ${COLLECTIONS_BIT_SOURCES}) - target_link_libraries(BitCollections PRIVATE - InternalCollectionsUtilities) -- set_target_properties(BitCollections PROPERTIES -- INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) - - _install_target(BitCollections) - set_property(GLOBAL APPEND PROPERTY SWIFT_COLLECTIONS_EXPORTS BitCollections) -diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt -index ad39dd9be70a3d3fd7f3176e9a607c6fa1413d82..a54e494c81a552282735bd926a05cb3d9527b169 100644 ---- a/Sources/CMakeLists.txt -+++ b/Sources/CMakeLists.txt -@@ -24,8 +24,6 @@ if(COLLECTIONS_SINGLE_MODULE) - endif() - - target_compile_definitions(${COLLECTIONS_MODULE_NAME} PRIVATE COLLECTIONS_SINGLE_MODULE) -- set_target_properties(${COLLECTIONS_MODULE_NAME} PROPERTIES -- INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) - - if(COLLECTIONS_FOUNDATION_TOOLCHAIN_MODULE) - get_swift_host_os(swift_os) -diff --git a/Sources/Collections/CMakeLists.txt b/Sources/Collections/CMakeLists.txt -index 9f534a46c80475e2ef39ba39d386be00d25b7c30..6be24ce21145f14718e90d67247d2ea56c21ffd4 100644 ---- a/Sources/Collections/CMakeLists.txt -+++ b/Sources/Collections/CMakeLists.txt -@@ -15,9 +15,9 @@ target_link_libraries(Collections PRIVATE - HeapModule - OrderedCollections - HashTreeCollections -+ InternalCollectionsUtilities - ) --set_target_properties(Collections PROPERTIES -- INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) - - _install_target(Collections) - set_property(GLOBAL APPEND PROPERTY SWIFT_COLLECTIONS_EXPORTS Collections) -+ -diff --git a/Sources/DequeModule/CMakeLists.txt b/Sources/DequeModule/CMakeLists.txt -index 07364b66e32257c098edfbfdd3204206dee56709..da1a79becc36893a90d797bee610b973c3c12853 100644 ---- a/Sources/DequeModule/CMakeLists.txt -+++ b/Sources/DequeModule/CMakeLists.txt -@@ -15,8 +15,6 @@ else() - ${COLLECTIONS_DEQUE_SOURCES}) - target_link_libraries(DequeModule PRIVATE - InternalCollectionsUtilities) -- set_target_properties(DequeModule PROPERTIES -- INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) - - _install_target(DequeModule) - set_property(GLOBAL APPEND PROPERTY SWIFT_COLLECTIONS_EXPORTS DequeModule) -diff --git a/Sources/HashTreeCollections/CMakeLists.txt b/Sources/HashTreeCollections/CMakeLists.txt -index 0329fe664fd103348f55ce34dee71da9f437dfd6..56566f36a63c834f0c7d40f787504adede820808 100644 ---- a/Sources/HashTreeCollections/CMakeLists.txt -+++ b/Sources/HashTreeCollections/CMakeLists.txt -@@ -15,8 +15,6 @@ else() - ${COLLECTIONS_HASHTREE_SOURCES}) - target_link_libraries(HashTreeCollections PRIVATE - InternalCollectionsUtilities) -- set_target_properties(HashTreeCollections PROPERTIES -- INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) - - _install_target(HashTreeCollections) - set_property(GLOBAL APPEND PROPERTY SWIFT_COLLECTIONS_EXPORTS HashTreeCollections) -diff --git a/Sources/HeapModule/CMakeLists.txt b/Sources/HeapModule/CMakeLists.txt -index a1cc57a63b5bcd140ea207298fbd0c6d48f784de..6bf9edeed5bfdeb9120869dfdbaed21a2376e3c3 100644 ---- a/Sources/HeapModule/CMakeLists.txt -+++ b/Sources/HeapModule/CMakeLists.txt -@@ -15,8 +15,6 @@ else() - ${COLLECTIONS_HEAP_SOURCES}) - target_link_libraries(HeapModule PRIVATE - InternalCollectionsUtilities) -- set_target_properties(HeapModule PROPERTIES -- INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) - - _install_target(HeapModule) - set_property(GLOBAL APPEND PROPERTY SWIFT_COLLECTIONS_EXPORTS HeapModule) -diff --git a/Sources/InternalCollectionsUtilities/CMakeLists.txt b/Sources/InternalCollectionsUtilities/CMakeLists.txt -index 808e36c2eb43f26f8009d4982e5cd095c3a3639d..f25f3da067e8d6ce540ba911a3df43d6e3b5b561 100644 ---- a/Sources/InternalCollectionsUtilities/CMakeLists.txt -+++ b/Sources/InternalCollectionsUtilities/CMakeLists.txt -@@ -13,8 +13,6 @@ else() - set(module_name InternalCollectionsUtilities) - add_library(InternalCollectionsUtilities - ${COLLECTIONS_UTILITIES_SOURCES}) -- set_target_properties(InternalCollectionsUtilities PROPERTIES -- INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) - - _install_target(InternalCollectionsUtilities) - set_property(GLOBAL APPEND PROPERTY SWIFT_COLLECTIONS_EXPORTS InternalCollectionsUtilities) -diff --git a/Sources/OrderedCollections/CMakeLists.txt b/Sources/OrderedCollections/CMakeLists.txt -index 017113861101c5acfb3f77a8feca86f1b9a6fd50..16e63aec3d0e317191b59637ef02aba9b0e76a76 100644 ---- a/Sources/OrderedCollections/CMakeLists.txt -+++ b/Sources/OrderedCollections/CMakeLists.txt -@@ -15,8 +15,6 @@ else() - ${COLLECTIONS_ORDERED_SOURCES}) - target_link_libraries(OrderedCollections PRIVATE - InternalCollectionsUtilities) -- set_target_properties(OrderedCollections PROPERTIES -- INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) - - _install_target(OrderedCollections) - set_property(GLOBAL APPEND PROPERTY SWIFT_COLLECTIONS_EXPORTS OrderedCollections) -diff --git a/Sources/RopeModule/CMakeLists.txt b/Sources/RopeModule/CMakeLists.txt -index d33fac9213f939fcfccb1f702039b421814d3dfd..19e08d235a14348dac983cb4bf1972a039ea3fbb 100644 ---- a/Sources/RopeModule/CMakeLists.txt -+++ b/Sources/RopeModule/CMakeLists.txt -@@ -15,8 +15,6 @@ else() - ${COLLECTIONS_ROPE_SOURCES}) - target_link_libraries(_RopeModule PRIVATE - InternalCollectionsUtilities) -- set_target_properties(_RopeModule PROPERTIES -- INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) - - _install_target(_RopeModule) - set_property(GLOBAL APPEND PROPERTY SWIFT_COLLECTIONS_EXPORTS _RopeModule) diff --git a/Meta/CMake/presets/CMakeBasePresets.json b/Meta/CMake/presets/CMakeBasePresets.json index 7fd4f8a52e..f3885e4532 100644 --- a/Meta/CMake/presets/CMakeBasePresets.json +++ b/Meta/CMake/presets/CMakeBasePresets.json @@ -96,25 +96,6 @@ "ENABLE_FUZZERS_LIBFUZZER": "ON", "ENABLE_ADDRESS_SANITIZER": "ON" } - }, - { - "hidden": true, - "name": "Swift_Release_base", - "displayName": "Swift Release Config", - "description": "Swift-enabled release build", - "binaryDir": "$env{LADYBIRD_SOURCE_DIR}/Build/swift", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "RelWithDebInfo", - "VCPKG_OVERLAY_TRIPLETS": "$env{LADYBIRD_SOURCE_DIR}/Meta/CMake/vcpkg/release-triplets", - "ENABLE_SWIFT": "ON", - "CMAKE_C_COMPILER": "MustBeSetManually", - "CMAKE_CXX_COMPILER": "MustBeSetManually++" - }, - "vendor": { - "jetbrains.com/clion": { - "toolchain": "Swift" - } - } } ], "buildPresets": [ diff --git a/Meta/CMake/presets/CMakeUnixPresets.json b/Meta/CMake/presets/CMakeUnixPresets.json index 6867f83e00..ea7d9039a7 100644 --- a/Meta/CMake/presets/CMakeUnixPresets.json +++ b/Meta/CMake/presets/CMakeUnixPresets.json @@ -55,13 +55,6 @@ "unix_base", "All_Debug_base" ] - }, - { - "name": "Swift_Release", - "inherits": [ - "unix_base", - "Swift_Release_base" - ] } ], "buildPresets": [ @@ -71,13 +64,6 @@ "configurePreset": "Distribution", "displayName": "Distribution Build", "description": "Build the project for distribution" - }, - { - "name": "Swift_Release", - "inherits": "base", - "configurePreset": "Swift_Release", - "displayName": "Swift Release Build", - "description": "Build the project for Swift release on Unix" } ], "testPresets": [ @@ -85,11 +71,6 @@ "name": "Distribution", "inherits": "base", "configurePreset": "Distribution" - }, - { - "name": "Swift_Release", - "inherits": "base", - "configurePreset": "Swift_Release" } ] } diff --git a/Meta/CMake/sanitizers.cmake b/Meta/CMake/sanitizers.cmake index d88d6f8f6b..b8d8382f66 100644 --- a/Meta/CMake/sanitizers.cmake +++ b/Meta/CMake/sanitizers.cmake @@ -16,8 +16,6 @@ if (ENABLE_ADDRESS_SANITIZER) else() add_cxx_compile_options(-fsanitize=address -fno-omit-frame-pointer) add_cxx_link_options(-fsanitize=address) - add_swift_compile_options(-sanitize=address) - add_swift_link_options(-sanitize=address) endif() endif() @@ -31,7 +29,7 @@ if (ENABLE_UNDEFINED_SANITIZER) add_cxx_compile_options(-fsanitize=undefined) # FIXME: Windows on ARM link_libraries(clang_rt.ubsan_standalone-x86_64.lib clang_rt.ubsan_standalone_cxx-x86_64.lib) - elseif (APPLE OR NOT ENABLE_SWIFT) + else() add_cxx_compile_options(-fsanitize=undefined -fno-omit-frame-pointer) if (UNDEFINED_BEHAVIOR_IS_FATAL) add_cxx_compile_options(-fno-sanitize-recover=undefined) @@ -40,7 +38,5 @@ if (ENABLE_UNDEFINED_SANITIZER) add_cxx_compile_options(-fno-sanitize=function) endif() add_cxx_link_options(-fsanitize=undefined) - add_swift_compile_options(-sanitize=undefined) - add_swift_link_options(-sanitize=undefined) endif() endif() diff --git a/Meta/CMake/skia.cmake b/Meta/CMake/skia.cmake index cce7406de7..4958793c87 100644 --- a/Meta/CMake/skia.cmake +++ b/Meta/CMake/skia.cmake @@ -40,5 +40,4 @@ else() set(SKIA_TARGET PkgConfig::skia) set_property(TARGET PkgConfig::skia APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS "SKCMS_DLL") endif() -swizzle_target_properties_for_swift(${SKIA_TARGET}) add_library(skia ALIAS ${SKIA_TARGET}) diff --git a/Meta/CMake/utils.cmake b/Meta/CMake/utils.cmake index 79cf066fc0..db2c6f0416 100644 --- a/Meta/CMake/utils.cmake +++ b/Meta/CMake/utils.cmake @@ -203,8 +203,3 @@ function(add_lagom_library_install_rules target_name) INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) endfunction() - -if (NOT COMMAND swizzle_target_properties_for_swift) - function(swizzle_target_properties_for_swift target) - endfunction() -endif() diff --git a/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp b/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp index 23e81519d1..0cc012c3e1 100644 --- a/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp +++ b/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp @@ -757,9 +757,6 @@ static std::optional find_cell_type_with_origin(clang::CXXRe if (base_name == "GC::Cell") return CellTypeWithOrigin { *base_record, LibJSCellMacro::Type::GCCell }; - if (base_name == "GC::ForeignCell") - return CellTypeWithOrigin { *base_record, LibJSCellMacro::Type::ForeignCell }; - if (base_name == "JS::Object") return CellTypeWithOrigin { *base_record, LibJSCellMacro::Type::JSObject }; @@ -782,9 +779,6 @@ static std::optional find_cell_type_with_origin(clang::CXXRe LibJSGCVisitor::CellMacroExpectation LibJSGCVisitor::get_record_cell_macro_expectation(clang::CXXRecordDecl const& record) { - if (record.getQualifiedNameAsString() == "GC::ForeignCell") - return { LibJSCellMacro::Type::ForeignCell, "Cell" }; - auto origin = find_cell_type_with_origin(record); assert(origin.has_value()); @@ -921,8 +915,6 @@ char const* LibJSCellMacro::type_name(Type type) switch (type) { case Type::GCCell: return "GC_CELL"; - case Type::ForeignCell: - return "FOREIGN_CELL"; case Type::JSObject: return "JS_OBJECT"; case Type::JSEnvironment: @@ -951,7 +943,6 @@ void LibJSPPCallbacks::MacroExpands(clang::Token const& name_token, clang::Macro if (auto* ident_info = name_token.getIdentifierInfo()) { static llvm::StringMap libjs_macro_types { { "GC_CELL", LibJSCellMacro::Type::GCCell }, - { "FOREIGN_CELL", LibJSCellMacro::Type::ForeignCell }, { "JS_OBJECT", LibJSCellMacro::Type::JSObject }, { "JS_ENVIRONMENT", LibJSCellMacro::Type::JSEnvironment }, { "JS_PROTOTYPE_OBJECT", LibJSCellMacro::Type::JSPrototypeObject }, diff --git a/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.h b/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.h index dc9bad2117..a9bc475f7a 100644 --- a/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.h +++ b/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.h @@ -13,7 +13,6 @@ struct LibJSCellMacro { enum class Type { GCCell, - ForeignCell, JSObject, JSEnvironment, JSPrototypeObject, diff --git a/Meta/check-newlines-at-eof.py b/Meta/check-newlines-at-eof.py index 2ff21569ce..5782399a75 100755 --- a/Meta/check-newlines-at-eof.py +++ b/Meta/check-newlines-at-eof.py @@ -5,7 +5,7 @@ import re import subprocess import sys -RE_RELEVANT_FILE_EXTENSION = re.compile("\\.(cpp|h|mm|swift|gml|html|js|css|sh|py|json|txt|cmake|gn|gni)$") +RE_RELEVANT_FILE_EXTENSION = re.compile("\\.(cpp|h|mm|gml|html|js|css|sh|py|json|txt|cmake|gn|gni)$") def should_check_file(filename): diff --git a/Meta/find_compiler.py b/Meta/find_compiler.py index f595c544d2..309223020f 100755 --- a/Meta/find_compiler.py +++ b/Meta/find_compiler.py @@ -165,34 +165,6 @@ def pick_host_compiler(platform: Platform, cc: str, cxx: str) -> tuple[str, str] sys.exit(1) -def pick_swift_compilers(platform: Platform, project_root: Path) -> tuple[Path, Path, Path]: - if platform.host_system == HostSystem.Windows: - print("Swift builds are not supported on Windows", file=sys.stderr) - sys.exit(1) - - if not shutil.which("swiftly"): - print("swiftly is required to manage Swift toolchains", file=sys.stderr) - sys.exit(1) - - swiftly_toolchain_path = run_command(["swiftly", "use", "--print-location"], return_output=True, cwd=project_root) - if not swiftly_toolchain_path: - run_command(["swiftly", "install"], exit_on_failure=True, cwd=project_root) - - swiftly_toolchain_path = run_command( - ["swiftly", "use", "--print-location"], return_output=True, exit_on_failure=True, cwd=project_root - ) - assert swiftly_toolchain_path - - swiftly_toolchain_path = Path(swiftly_toolchain_path.strip()) - swiftly_bin_dir = swiftly_toolchain_path.joinpath("usr", "bin") - - if not swiftly_toolchain_path.exists() or not swiftly_bin_dir.exists(): - print(f"swiftly toolchain path {swiftly_toolchain_path} does not exist", file=sys.stderr) - sys.exit(1) - - return swiftly_bin_dir / "clang", swiftly_bin_dir / "clang++", swiftly_bin_dir / "swiftc" - - def main(): platform = Platform() (default_cc, default_cxx) = platform.default_compiler() diff --git a/Meta/generate_clang_module_map.py b/Meta/generate_clang_module_map.py deleted file mode 100644 index 4ea5bb425a..0000000000 --- a/Meta/generate_clang_module_map.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 -""" -Generates a clang module map for a given directory -""" - -import argparse -import pathlib -import sys - -import yaml - - -def write_file_if_not_same(file_path, content): - try: - with open(file_path, "r") as f: - if f.read() == content: - return - except FileNotFoundError: - pass - - with open(file_path, "w") as f: - f.write(content) - - -def main(): - parser = argparse.ArgumentParser(epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument("directory", help="source directory to generate module map for") - parser.add_argument("--module-name", help="top-level module name") - parser.add_argument("--module-map", required=True, help="output module map file") - parser.add_argument("--vfs-map", required=True, help="output VFS map file") - parser.add_argument("--exclude-files", nargs="*", required=False, help="files to exclude in the module map") - parser.add_argument("--generated-files", nargs="*", help="extra files to include in the module map") - args = parser.parse_args() - - root = pathlib.Path(args.directory) - if not root.is_dir(): - print(f"Error: {args.directory} is not a directory", file=sys.stderr) - return 1 - pathlib.Path(args.module_map).parent.mkdir(parents=True, exist_ok=True) - pathlib.Path(args.vfs_map).parent.mkdir(parents=True, exist_ok=True) - exclude_files = set(args.exclude_files) if args.exclude_files else set() - - header_files = [f for f in root.rglob("**/*.h") if f.is_file() and f.name not in exclude_files] - module_name = args.module_name if args.module_name else root.name - - module_map = f"module {module_name} {{\n" - for header_file in header_files: - module_map += f' header "{header_file.relative_to(root)}"\n' - for generated_file in args.generated_files: - module_map += f' header "{generated_file}"\n' - module_map += " requires cplusplus\n" - module_map += " export *\n" - module_map += "}\n" - - vfs_map = { - "version": 0, - "use-external-names": False, - "roots": [ - { - "name": f"{root}/module.modulemap", - "type": "file", - "external-contents": f"{args.module_map}", - } - ], - } - - write_file_if_not_same(args.module_map, module_map) - write_file_if_not_same(args.vfs_map, yaml.dump(vfs_map)) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/Meta/gn/secondary/AK/BUILD.gn b/Meta/gn/secondary/AK/BUILD.gn index 1f940c1547..57c378c7f7 100644 --- a/Meta/gn/secondary/AK/BUILD.gn +++ b/Meta/gn/secondary/AK/BUILD.gn @@ -177,7 +177,6 @@ shared_library("AK") { "StringUtils.h", "StringView.cpp", "StringView.h", - "Swift.h", "TemporaryChange.h", "Time.cpp", "Time.h", diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/HTML/Parser/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibWeb/HTML/Parser/BUILD.gn index e47e80872c..5afd9b3bb4 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWeb/HTML/Parser/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/HTML/Parser/BUILD.gn @@ -7,7 +7,6 @@ source_set("Parser") { "HTMLParser.cpp", "HTMLToken.cpp", "HTMLTokenizer.cpp", - "HTMLTokenizerHelpers.cpp", "ListOfActiveFormattingElements.cpp", "StackOfOpenElements.cpp", ] diff --git a/Meta/ladybird.py b/Meta/ladybird.py index 0d9a3048b8..478bb788e8 100755 --- a/Meta/ladybird.py +++ b/Meta/ladybird.py @@ -18,7 +18,6 @@ from typing import Optional sys.path.append(str(Path(__file__).resolve().parent.parent)) from Meta.find_compiler import pick_host_compiler -from Meta.find_compiler import pick_swift_compilers from Meta.host_platform import HostArchitecture from Meta.host_platform import HostSystem from Meta.host_platform import Platform @@ -194,14 +193,9 @@ def configure_main(platform: Platform, preset: str, cc: str, cxx: str) -> Path: if build_preset_dir.joinpath("build.ninja").exists() or build_preset_dir.joinpath("ladybird.sln").exists(): return build_preset_dir - swiftc: Optional[str] = None validate_cmake_version() - if "Swift" in preset: - compilers = pick_swift_compilers(platform, ladybird_source_dir) - (cc, cxx, swiftc) = tuple(map(str, compilers)) - else: - (cc, cxx) = pick_host_compiler(platform, cc, cxx) + (cc, cxx) = pick_host_compiler(platform, cc, cxx) config_args = [ "cmake", @@ -215,9 +209,6 @@ def configure_main(platform: Platform, preset: str, cc: str, cxx: str) -> Path: f"-DCMAKE_CXX_COMPILER={cxx}", ] - if swiftc: - config_args.append(f"-DCMAKE_Swift_COMPILER={swiftc}") - if platform.host_system == HostSystem.Linux and platform.host_architecture == HostArchitecture.AArch64: config_args.extend(configure_skia_jemalloc()) @@ -273,7 +264,6 @@ def configure_build_env(platform: Platform, preset: str) -> tuple[Path, Path]: "Distribution": build_root_dir / "distribution", "Release": build_root_dir / "release", "Sanitizer": build_root_dir / "sanitizers", - "Swift_Release": build_root_dir / "swift", } build_preset_dir = known_presets.get(preset, None) diff --git a/Meta/lint-ci.sh b/Meta/lint-ci.sh index a6db5117b4..05bba26d89 100755 --- a/Meta/lint-ci.sh +++ b/Meta/lint-ci.sh @@ -52,11 +52,4 @@ else ((FAILURES+=1)) fi -if Meta/lint-swift.sh "$@" && git diff --exit-code -- ':*.swift'; then - echo -e "[${GREEN}OK${NC}]: Meta/lint-swift.sh" -else - echo -e "[${BOLD_RED}FAIL${NC}]: Meta/lint-swift.sh" - ((FAILURES+=1)) -fi - exit "${FAILURES}" diff --git a/Meta/lint-swift.sh b/Meta/lint-swift.sh deleted file mode 100755 index 8b0a210c6c..0000000000 --- a/Meta/lint-swift.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash - -set -e - -script_path=$(cd -P -- "$(dirname -- "$0")" && pwd -P) -cd "${script_path}/.." || exit 1 - -if [ "$#" -eq "0" ]; then - files=() - while IFS= read -r file; do - files+=("$file") - done < <( - git ls-files '*.swift' - ) -else - files=() - for file in "$@"; do - if [[ "${file}" == *".swift" ]] ; then - files+=("${file}") - fi - done -fi - -if (( ${#files[@]} )); then - if ! command -v swift-format >/dev/null 2>&1 ; then - echo "swift-format is not available, but Swift files need linting! Either skip this script, or install swift-format." - exit 1 - fi - swift-format -i "${files[@]}" - echo "Maybe some files have changed. Sorry, but swift-format doesn't indicate what happened." -else - echo "No .swift files to check." -fi diff --git a/Tests/AK/CMakeLists.txt b/Tests/AK/CMakeLists.txt index 31e7c0bae6..4f743264ea 100644 --- a/Tests/AK/CMakeLists.txt +++ b/Tests/AK/CMakeLists.txt @@ -114,12 +114,3 @@ endif() target_link_libraries(TestString PRIVATE LibUnicode) target_link_libraries(TestUtf16String PRIVATE LibUnicode) - -if (ENABLE_SWIFT) - - # FIXME: Convert to use swift-testing after resolving https://github.com/LadybirdBrowser/ladybird/issues/1201 - add_executable(TestAKBindings TestAKBindings.swift) - target_link_libraries(TestAKBindings PRIVATE AK) - target_compile_options(TestAKBindings PRIVATE -parse-as-library) - add_test(NAME TestAKBindings COMMAND TestAKBindings) -endif() diff --git a/Tests/AK/TestAKBindings.swift b/Tests/AK/TestAKBindings.swift deleted file mode 100644 index 886a83af05..0000000000 --- a/Tests/AK/TestAKBindings.swift +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -import AK -import Foundation - -protocol ConformanceMarker {} -enum CxxSequenceMarker {} -extension CxxSequenceMarker: ConformanceMarker where T: CxxSequence {} -private func isCxxSequenceType(_ type: borrowing T.Type) -> Bool { - return CxxSequenceMarker.self is ConformanceMarker.Type -} - -class StandardError: TextOutputStream { - func write(_ string: Swift.String) { - try! FileHandle.standardError.write(contentsOf: Data(string.utf8)) - } -} - -@main -struct TestAKBindings { - static func testSequenceTypesAreBound() { - var standardError = StandardError() - print("Testing CxxSequence types...", to: &standardError) - - //precondition(isCxxSequenceType(AK.StringView.self)) - precondition(isCxxSequenceType(AK.Bytes.self)) - precondition(isCxxSequenceType(AK.ReadonlyBytes.self)) - precondition(!isCxxSequenceType(AK.Utf16View.self)) - - // FIXME: Not bound for some reason - //precondition(isCxxSequenceType(AK.Utf16String.self)) - precondition(!isCxxSequenceType(AK.String.self)) - - precondition(!isCxxSequenceType(AK.Error.self)) - - print("CxxSequence types pass", to: &standardError) - } - - static func main() { - var standardError = StandardError() - print("Starting test suite...", to: &standardError) - testSequenceTypesAreBound() - - print("All tests pass", to: &standardError) - } -} diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 7b206208ed..d7782afe93 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -5,7 +5,6 @@ add_subdirectory(LibCrypto) add_subdirectory(LibDatabase) add_subdirectory(LibDiff) add_subdirectory(LibDNS) -add_subdirectory(LibGC) add_subdirectory(LibHTTP) add_subdirectory(LibJS) add_subdirectory(LibRegex) diff --git a/Tests/ClangPlugins/LibJSGCTests/Macros/classes_are_missing_expected_macros.cpp b/Tests/ClangPlugins/LibJSGCTests/Macros/classes_are_missing_expected_macros.cpp index 77e455b465..a0b214bcf5 100644 --- a/Tests/ClangPlugins/LibJSGCTests/Macros/classes_are_missing_expected_macros.cpp +++ b/Tests/ClangPlugins/LibJSGCTests/Macros/classes_are_missing_expected_macros.cpp @@ -6,7 +6,6 @@ // RUN: %clang++ -Xclang -verify %plugin_opts% -c %s -o %t 2>&1 -#include #include #include @@ -14,10 +13,6 @@ class TestCellClass : JS::Cell { }; -// expected-error@+1 {{Expected record to have a FOREIGN_CELL macro invocation}} -class TestForeignCellClass : GC::ForeignCell { -}; - // expected-error@+1 {{Expected record to have a JS_OBJECT macro invocation}} class TestObjectClass : JS::Object { }; diff --git a/Tests/ClangPlugins/LibJSGCTests/Macros/classes_have_expected_macros.cpp b/Tests/ClangPlugins/LibJSGCTests/Macros/classes_have_expected_macros.cpp index 48643b5c62..8b9420f926 100644 --- a/Tests/ClangPlugins/LibJSGCTests/Macros/classes_have_expected_macros.cpp +++ b/Tests/ClangPlugins/LibJSGCTests/Macros/classes_have_expected_macros.cpp @@ -7,7 +7,6 @@ // RUN: %clang++ -Xclang -verify %plugin_opts% -c %s -o %t 2>&1 // expected-no-diagnostics -#include #include #include @@ -15,10 +14,6 @@ class TestCellClass : JS::Cell { GC_CELL(TestCellClass, JS::Cell); }; -class TestForeignCellClass : GC::ForeignCell { - FOREIGN_CELL(TestForeignCellClass, GC::ForeignCell); -}; - class TestObjectClass : JS::Object { JS_OBJECT(TestObjectClass, JS::Object); }; diff --git a/Tests/ClangPlugins/LibJSGCTests/Macros/classes_have_incorrect_macro_types.cpp b/Tests/ClangPlugins/LibJSGCTests/Macros/classes_have_incorrect_macro_types.cpp index 364ca34c49..53aa3d7bbe 100644 --- a/Tests/ClangPlugins/LibJSGCTests/Macros/classes_have_incorrect_macro_types.cpp +++ b/Tests/ClangPlugins/LibJSGCTests/Macros/classes_have_incorrect_macro_types.cpp @@ -6,7 +6,6 @@ // RUN: %clang++ -Xclang -verify %plugin_opts% -c %s -o %t 2>&1 -#include #include #include @@ -35,16 +34,6 @@ class ObjectWithEnvironmentMacro : JS::Object { JS_ENVIRONMENT(ObjectWithEnvironmentMacro, JS::Object); }; -class CellWithForeignCellMacro : GC::Cell { - // expected-error@+1 {{Invalid GC-CELL-like macro invocation; expected GC_CELL}} - FOREIGN_CELL(CellWithForeignCellMacro, GC::Cell); -}; - -class ObjectWithForeignCellMacro : JS::Object { - // expected-error@+1 {{Invalid GC-CELL-like macro invocation; expected JS_OBJECT}} - FOREIGN_CELL(ObjectWithForeignCellMacro, JS::Object); -}; - // JS_PROTOTYPE_OBJECT can only be used in the JS namespace namespace JS { diff --git a/Tests/ClangPlugins/LibJSGCTests/Macros/wrong_classname_arg.cpp b/Tests/ClangPlugins/LibJSGCTests/Macros/wrong_classname_arg.cpp index 15c4ae150d..59eae286cb 100644 --- a/Tests/ClangPlugins/LibJSGCTests/Macros/wrong_classname_arg.cpp +++ b/Tests/ClangPlugins/LibJSGCTests/Macros/wrong_classname_arg.cpp @@ -6,7 +6,6 @@ // RUN: %clang++ -Xclang -verify %plugin_opts% -c %s -o %t 2>&1 -#include #include #include @@ -17,11 +16,6 @@ class TestCellClass : JS::Cell { GC_CELL(bad, JS::Cell); }; -class TestForeignCellClass : GC::ForeignCell { - // expected-error@+1 {{Expected first argument of FOREIGN_CELL macro invocation to be TestForeignCellClass}} - FOREIGN_CELL(bad, GC::ForeignCell); -}; - class TestObjectClass : JS::Object { // expected-error@+1 {{Expected first argument of JS_OBJECT macro invocation to be TestObjectClass}} JS_OBJECT(bad, JS::Object); diff --git a/Tests/LibCore/CMakeLists.txt b/Tests/LibCore/CMakeLists.txt index 6f15180475..ced5b45211 100644 --- a/Tests/LibCore/CMakeLists.txt +++ b/Tests/LibCore/CMakeLists.txt @@ -29,20 +29,3 @@ if(NOT WIN32) endif() target_link_libraries(TestLibCoreSharedSingleProducerCircularQueue PRIVATE LibThreading) - -if(ENABLE_SWIFT) - find_package(SwiftTesting REQUIRED) - - add_executable(TestCoreSwift - TestEventLoopActor.swift - TestEventLoop.cpp - ) - - # FIXME: Swift doesn't seem to like object libraries for @main - target_sources(TestCoreSwift PRIVATE ../Resources/SwiftTestMain.swift) - - set_target_properties(TestCoreSwift PROPERTIES SUFFIX .swift-testing) - target_include_directories(TestCoreSwift PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) - target_link_libraries(TestCoreSwift PRIVATE AK LibCore SwiftTesting::SwiftTesting) - add_test(NAME TestCoreSwift COMMAND TestCoreSwift) -endif() diff --git a/Tests/LibCore/TestEventLoopActor.swift b/Tests/LibCore/TestEventLoopActor.swift deleted file mode 100644 index ac93df0bbb..0000000000 --- a/Tests/LibCore/TestEventLoopActor.swift +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2025, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -import AK -import Core -import CoreTesting -import Testing - -actor TestEventLoopActor: EventLoopActor { - nonisolated public let executor: EventLoopExecutor - - init() { - install_thread_local_event_loop() - executor = EventLoopExecutor() - } - - nonisolated func submit(action: @escaping @Sendable () async -> Void) { - Task(executorPreference: self.executor) { - await action() - } - } -} - -@Suite -struct TestEventLoop { - @Test - func testEventLoopActor() async { - // Creates an executor around EventLoop::current() - let actor = TestEventLoopActor() - - let ev = Core.EventLoop.current() - print("Event loop at \(Unmanaged.passUnretained(ev).toOpaque())") - - let (stream, continuation) = AsyncStream.makeStream() - var iterator = stream.makeAsyncIterator() - - actor.submit { - #expect(ev == Core.EventLoop.current(), "Closure is executed on event loop") - print("Hello from event loop at \(Unmanaged.passUnretained(Core.EventLoop.current()).toOpaque())") - - continuation.yield(42) - } - - actor.submit { - #expect(ev == Core.EventLoop.current(), "Closure is executed on event loop") - Core.EventLoop.current().quit(4) - - continuation.yield(1234) - continuation.finish() - } - - let rc = ev.exec() - #expect(rc == 4) - // Values not available until event loop has processed tasks - #expect(await iterator.next() == 42) - #expect(await iterator.next() == 1234) - - #expect(ev == Core.EventLoop.current(), "Event loop exists until end of function") - } -} diff --git a/Tests/LibGC/CMakeLists.txt b/Tests/LibGC/CMakeLists.txt deleted file mode 100644 index b42845cd74..0000000000 --- a/Tests/LibGC/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -if (ENABLE_SWIFT) - find_package(SwiftTesting REQUIRED) - - add_executable(TestGCSwift - TestGCBindings.swift - TestHeap.cpp - TestInterop.cpp - ) - # FIXME: Swift doesn't seem to like object libraries for @main - target_sources(TestGCSwift PRIVATE ../Resources/SwiftTestMain.swift) - - generate_clang_module_map(TestGCSwift) - - set_target_properties(TestGCSwift PROPERTIES SUFFIX .swift-testing) - target_include_directories(TestGCSwift PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) - target_link_libraries(TestGCSwift PRIVATE AK LibGC SwiftTesting::SwiftTesting) - - get_property(testing_compile_options TARGET SwiftTesting::SwiftTesting PROPERTY INTERFACE_LINK_OPTIONS) - - add_swift_target_properties(TestGCSwift - LAGOM_LIBRARIES AK LibGC - COMPILE_OPTIONS ${testing_compile_options} -enable-experimental-feature Extern - ) - add_test(NAME TestGCSwift COMMAND TestGCSwift) -endif() diff --git a/Tests/LibGC/TestGCBindings.swift b/Tests/LibGC/TestGCBindings.swift deleted file mode 100644 index e743ee5e6e..0000000000 --- a/Tests/LibGC/TestGCBindings.swift +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -import AK -import GC -@_exported import TestGCSwiftCxx -import Testing - -public struct HeapString: HeapAllocatable { - public var string: Swift.String - - public init(cell: GC.Cell) { - self.cell = cell - self.string = "" - } - - public static func create(on heap: GC.Heap, string: Swift.String) -> GC.Cell { - // NOTE: GC must be deferred so that a collection during allocation doesn't get tripped - // up looking for the Cell pointer on the stack or in a register when it might only exist in the heap - precondition(heap.is_gc_deferred()) - let heapString = allocate(on: heap) - heapString.pointee.string = string - return heapString.pointee.cell - } - - public var cell: GC.Cell -} - -@Suite(.serialized) -struct TestGCSwiftBindings { - - @Test func createBoundString() { - let heap = test_gc_heap() - let string = heap.withDeferredGC { - return HeapString.allocate(on: heap) - } - #expect(string.pointee.string == "") - heap.collect_garbage(GC.Heap.CollectionType.CollectGarbage) - - string.pointee.string = "Hello, World!" - heap.collect_garbage(GC.Heap.CollectionType.CollectGarbage) - #expect(string.pointee.string == "Hello, World!") - - heap.collect_garbage(GC.Heap.CollectionType.CollectEverything) - } - - @Test func testInterop() { - test_interop() - } -} diff --git a/Tests/LibGC/TestHeap.cpp b/Tests/LibGC/TestHeap.cpp deleted file mode 100644 index 7b7d5b9e9f..0000000000 --- a/Tests/LibGC/TestHeap.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "TestHeap.h" -#include - -GC::Heap& test_gc_heap() -{ - // FIXME: The GC heap should become thread aware! - thread_local GC::Heap heap(nullptr, [](auto&) { }); - return heap; -} diff --git a/Tests/LibGC/TestHeap.h b/Tests/LibGC/TestHeap.h deleted file mode 100644 index 32f8adeab2..0000000000 --- a/Tests/LibGC/TestHeap.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -GC::Heap& test_gc_heap(); diff --git a/Tests/LibGC/TestInterop.cpp b/Tests/LibGC/TestInterop.cpp deleted file mode 100644 index 3771ffa0ff..0000000000 --- a/Tests/LibGC/TestInterop.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "TestInterop.h" -#include "TestHeap.h" -#include -#include -#include -#include - -#define COLLECT heap.collect_garbage(GC::Heap::CollectionType::CollectGarbage) -#define COLLECT_ALL heap.collect_garbage(GC::Heap::CollectionType::CollectEverything) - -void test_interop() -{ - auto& heap = test_gc_heap(); - - COLLECT_ALL; - - auto string = GC::ForeignRef::allocate(heap, "Hello, World!"); - - COLLECT; - - auto strings_string = std::string(string->getString()); - VERIFY(strings_string == "Hello, World!"); - - COLLECT; - - auto* cell = string->getCell(); - VERIFY(cell == static_cast(string.cell())); - - COLLECT; - - strings_string = std::string(string->getString()); - - COLLECT; - - VERIFY(strings_string == "Hello, World!"); - - COLLECT_ALL; -} diff --git a/Tests/LibGC/TestInterop.h b/Tests/LibGC/TestInterop.h deleted file mode 100644 index 79af1ec90a..0000000000 --- a/Tests/LibGC/TestInterop.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -void test_interop(); diff --git a/Tests/LibWeb/CMakeLists.txt b/Tests/LibWeb/CMakeLists.txt index dd900885c6..a9054e3344 100644 --- a/Tests/LibWeb/CMakeLists.txt +++ b/Tests/LibWeb/CMakeLists.txt @@ -21,20 +21,4 @@ endforeach() target_link_libraries(TestContentFilter PRIVATE LibURL) target_link_libraries(TestFetchURL PRIVATE LibURL) -if (ENABLE_SWIFT) - find_package(SwiftTesting REQUIRED) - - add_executable(TestLibWebSwift - TestLibWebSwiftBindings.swift - TestHTMLTokenizerSwift.swift - ) - - # FIXME: Swift doesn't seem to like object libraries for @main - target_sources(TestLibWebSwift PRIVATE ../Resources/SwiftTestMain.swift) - - set_target_properties(TestLibWebSwift PROPERTIES SUFFIX .swift-testing) - target_link_libraries(TestLibWebSwift PRIVATE AK LibWeb LibGC SwiftTesting::SwiftTesting) - add_test(NAME TestLibWebSwift COMMAND TestLibWebSwift) -endif() - add_subdirectory("test-web") diff --git a/Tests/LibWeb/TestHTMLTokenizerSwift.swift b/Tests/LibWeb/TestHTMLTokenizerSwift.swift deleted file mode 100644 index 0d0ce0434b..0000000000 --- a/Tests/LibWeb/TestHTMLTokenizerSwift.swift +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -import AK -import Testing -import Web - -@Suite -struct TestHTMLTokenizerSwift { - - @Test func tokenTypes() { - let default_token = HTMLToken() - default_token.type = .Character(codePoint: "a") - #expect(default_token.isCharacter()) - - #expect("\(default_token)" == "HTMLToken(type: Character(codePoint: a))") - } - - @Test func parserWhitespace() { - for codePoint: Character in ["\t", "\n", "\r", "\u{000C}", " "] { - let token = HTMLToken(type: .Character(codePoint: codePoint)) - #expect(token.isParserWhitespace()) - } - - for codePoint: Character in ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"] { - let token = HTMLToken(type: .Character(codePoint: codePoint)) - #expect(!token.isParserWhitespace()) - } - } - - @Test func dataStateNoInput() { - let tokenizer = HTMLTokenizer() - #expect(tokenizer.state == HTMLTokenizer.State.Data) // initial state - - let token = tokenizer.nextToken() - #expect(token?.type == .EndOfFile) - - let token2 = tokenizer.nextToken() - #expect(token2 == nil) - #expect(tokenizer.state == HTMLTokenizer.State.Data) - } - - @Test func dataStateSingleChar() { - guard let tokenizer = HTMLTokenizer(input: "X") else { - Issue.record("Failed to create tokenizer for 'X'") - return - } - #expect(tokenizer.state == HTMLTokenizer.State.Data) // initial state - - let token = tokenizer.nextToken() - #expect(token?.type == .Character(codePoint: "X")) - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .EndOfFile) - - let token3 = tokenizer.nextToken() - #expect(token3 == nil) - #expect(tokenizer.state == HTMLTokenizer.State.Data) - } - - @Test func dataStateAmpersand() { - guard let tokenizer = HTMLTokenizer(input: "&") else { - Issue.record("Failed to create tokenizer for '&'") - return - } - #expect(tokenizer.state == HTMLTokenizer.State.Data) // initial state - - let token = tokenizer.nextToken() - #expect(token?.type == .Character(codePoint: "&")) - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .EndOfFile) - - let token3 = tokenizer.nextToken() - #expect(token3 == nil) - } - - @Test func tagOpenOnly() { - guard let tokenizer = HTMLTokenizer(input: "<") else { - Issue.record("Failed to create tokenizer for '<'") - return - } - #expect(tokenizer.state == HTMLTokenizer.State.Data) // initial state - - let token = tokenizer.nextToken() - #expect(token?.type == .Character(codePoint: "<")) - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .EndOfFile) - #expect(tokenizer.state == HTMLTokenizer.State.TagOpen) - - let token3 = tokenizer.nextToken() - #expect(token3 == nil) - } - - @Test func dataStateNulChar() { - guard let tokenizer = HTMLTokenizer(input: "H\0I") else { - Issue.record("Failed to create tokenizer for 'H\\0I'") - return - } - #expect(tokenizer.state == HTMLTokenizer.State.Data) // initial state - - let token = tokenizer.nextToken() - #expect(token?.type == .Character(codePoint: "H")) - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .Character(codePoint: "\u{FFFD}")) - - let token3 = tokenizer.nextToken() - #expect(token3?.type == .Character(codePoint: "I")) - - let token4 = tokenizer.nextToken() - #expect(token4?.type == .EndOfFile) - - #expect(tokenizer.state == HTMLTokenizer.State.Data) - } - - @Test func scriptTagWithAttributes() { - guard let tokenizer = HTMLTokenizer(input: "") else { - Issue.record("Failed to create tokenizer for ''") - return - } - - let token = tokenizer.nextToken() - #expect(token?.type == .StartTag(tagName: "script", attributes: [])) - - for codePoint in "var x = 1;" { - let token = tokenizer.nextToken() - #expect(token?.type == .Character(codePoint: codePoint)) - } - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .EndTag(tagName: "script")) - - let token3 = tokenizer.nextToken() - #expect(token3?.type == .EndOfFile) - } - - @Test func simpleDivWithContent() { - guard let tokenizer = HTMLTokenizer(input: "
hi
") else { - Issue.record("Failed to create tokenizer for '
hi
'") - return - } - #expect(tokenizer.state == HTMLTokenizer.State.Data) // initial state - - let token = tokenizer.nextToken() - #expect(token?.type == .StartTag(tagName: "div", attributes: [])) - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .Character(codePoint: "h")) - - let token3 = tokenizer.nextToken() - #expect(token3?.type == .Character(codePoint: "i")) - - let token4 = tokenizer.nextToken() - #expect(token4?.type == .EndTag(tagName: "div")) - - let token5 = tokenizer.nextToken() - #expect(token5?.type == .EndOfFile) - } - - @Test func simpleDivWithContentAndAttributes() { - guard let tokenizer = HTMLTokenizer(input: "
hi
") else { - Issue.record("Failed to create tokenizer for '
hi
'") - return - } - #expect(tokenizer.state == HTMLTokenizer.State.Data) // initial state - - let token = tokenizer.nextToken() - #expect(token?.type == .StartTag(tagName: "div", attributes: [HTMLToken.Attribute(localName: "class", value: "foo")])) - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .Character(codePoint: "h")) - - let token3 = tokenizer.nextToken() - #expect(token3?.type == .Character(codePoint: "i")) - - let token4 = tokenizer.nextToken() - #expect(token4?.type == .EndTag(tagName: "div")) - - let token5 = tokenizer.nextToken() - #expect(token5?.type == .EndOfFile) - } - - @Test func severalDivsWithAttributesAndContent() { - // Explicitly use unquoted and single quotes for attribute values - guard let tokenizer = HTMLTokenizer(input: "
hi
bye
") else { - Issue.record("Failed to create tokenizer for '
hi
bye
'") - return - } - - let token = tokenizer.nextToken() - #expect(token?.type == .StartTag(tagName: "div", attributes: [HTMLToken.Attribute(localName: "class", value: "foo")])) - - for codePoint in "hi" { - let token = tokenizer.nextToken() - #expect(token?.type == .Character(codePoint: codePoint)) - } - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .EndTag(tagName: "div")) - - let token3 = tokenizer.nextToken() - #expect(token3?.type == .StartTag(tagName: "div", attributes: [HTMLToken.Attribute(localName: "class", value: "bar")])) - - for codePoint in "bye" { - let token = tokenizer.nextToken() - #expect(token?.type == .Character(codePoint: codePoint)) - } - - let token4 = tokenizer.nextToken() - #expect(token4?.type == .EndTag(tagName: "div")) - - let token5 = tokenizer.nextToken() - #expect(token5?.type == .EndOfFile) - } - - @Test func startTagWithMultipleAttributes() { - guard let tokenizer = HTMLTokenizer(input: "
hi
") else { - Issue.record("Failed to create tokenizer for '
hi
'") - return - } - - let token = tokenizer.nextToken() - #expect(token?.type == .StartTag(tagName: "div", attributes: [HTMLToken.Attribute(localName: "class", value: "foo"), HTMLToken.Attribute(localName: "id", value: "bar")])) - - for codePoint in "hi" { - let token = tokenizer.nextToken() - #expect(token?.type == .Character(codePoint: codePoint)) - } - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .EndTag(tagName: "div", attributes: [HTMLToken.Attribute(localName: "attr", value: "endTagAttributeWhee")])) - - let token3 = tokenizer.nextToken() - #expect(token3?.type == .EndOfFile) - } - - @Test func xmlDeclaration() { - guard let tokenizer = HTMLTokenizer(input: "") else { - Issue.record("Failed to create tokenizer for ''") - return - } - - let token = tokenizer.nextToken() - #expect(token?.type == .Comment(data: "?xml version=\"1.0\" encoding=\"UTF-8\"?")) - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .EndOfFile) - } - - @Test func simpleComment() { - guard let tokenizer = HTMLTokenizer(input: "") else { - Issue.record("Failed to create tokenizer for ''") - return - } - - let token = tokenizer.nextToken() - #expect(token?.type == .Comment(data: " comment ")) - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .EndOfFile) - } - - @Test func nestedComment() { - guard let tokenizer = HTMLTokenizer(input: " -->") else { - Issue.record("Failed to create tokenizer for ' -->'") - return - } - - let token = tokenizer.nextToken() - #expect(token?.type == .Comment(data: " " { - let token = tokenizer.nextToken() - #expect(token?.type == .Character(codePoint: codePoint)) - } - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .EndOfFile) - } - - @Test func commentWithScriptTagInside() { - guard let tokenizer = HTMLTokenizer(input: "") else { - Issue.record("Failed to create tokenizer for ''") - return - } - - let token = tokenizer.nextToken() - #expect(token?.type == .Comment(data: " ")) - - let token2 = tokenizer.nextToken() - #expect(token2?.type == .EndOfFile) - } -} diff --git a/Tests/LibWeb/TestLibWebSwiftBindings.swift b/Tests/LibWeb/TestLibWebSwiftBindings.swift deleted file mode 100644 index 60e666a8c7..0000000000 --- a/Tests/LibWeb/TestLibWebSwiftBindings.swift +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -import AK -import Testing -import Web - -@Suite -struct TestLibWebSwiftBindings { - - @Test func enumsAreBound() { - #expect(Web.DOM.NodeType.ELEMENT_NODE.rawValue == 1) - - #expect(Web.Bindings.NavigationType.Push.rawValue == 0) - - let end = Web.Bindings.idl_enum_to_string(Web.Bindings.ScrollLogicalPosition.End) - let end_string = Swift.String(akString: end)! - - #expect(end_string == "end") - } -} diff --git a/Tests/Resources/SwiftTestMain.swift b/Tests/Resources/SwiftTestMain.swift deleted file mode 100644 index 3b18cc5554..0000000000 --- a/Tests/Resources/SwiftTestMain.swift +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -import Foundation - -typealias EntryPoint = @convention(thin) @Sendable (_ configurationJSON: UnsafeRawBufferPointer?, _ recordHandler: @escaping @Sendable (_ recordJSON: UnsafeRawBufferPointer) -> Void) async throws -> Bool - -@_extern(c, "swt_abiv0_getEntryPoint") -func swt_abiv0_getEntryPoint() -> UnsafeRawPointer - -@main struct Runner { - static func main() async throws { - nonisolated(unsafe) let configurationJSON: UnsafeRawBufferPointer? = nil - let recordHandler: @Sendable (UnsafeRawBufferPointer) -> Void = { _ in } - - let entryPoint = unsafeBitCast(swt_abiv0_getEntryPoint(), to: EntryPoint.self) - - if try await entryPoint(configurationJSON, recordHandler) { - exit(EXIT_SUCCESS) - } else { - exit(EXIT_FAILURE) - } - } -}