Swift implementation
| SwiftPM package / import | Responsibility | Dependencies |
|---|---|---|
GameEventScriptRuntime |
Immutable values and Programs, .gesb codecs/validation, GESA dumping, Host, VM, random streams, extensions and external types |
Swift standard library and platform math library |
GameEventScriptCompiler |
Source lexer/parser, validation, lowering, optimization, register allocation, immutable Programs and debug sections | Runtime |
GameEventScriptSwiftBridge |
Native closure adapters, typed value conversion, KeyPath/external-type bindings and an optional synchronized Host runner | Runtime; Foundation for the runner |
GameEventScriptSyntaxHighlighter |
GES/GESA UTF-16 spans, TextMate scopes, incremental states and ANSI rendering | Foundation |
GameEventScriptConformance |
Internal observation adapter, codec probes and native implementation tests | Runtime and Compiler |
GameEventScriptTool / ges executable |
Compile/check/run/dump, interactive console, filesystem and terminal adapters | Runtime, Compiler, SyntaxHighlighter, Foundation and POSIX |
Runtime and Compiler APIs are synchronous, fileless, and independent of a test framework.
The optional SwiftBridge macro target uses the official swift-syntax build dependency.
The independent Python runner owns Markdown,
assertions and reports. ges-conformance-adapter executes requests against Swift
and returns raw observations; ges-conformance-probe supports codec interoperability.
Both executables are internal tooling. There is no Swift Conformance library product.
Compiler depends only on Runtime. The native Swift ges CLI
is the user-facing tool.
Build and verify
For application dependencies, use the repository-root SwiftPM package. It exposes Runtime, Compiler, SwiftBridge and SyntaxHighlighter as four selectable library products with one shared version. The packages below this directory remain local development entry points; CLI and Conformance are internal to the repository distribution. See the package release guide for Xcode installation, tagged consumer verification and release preparation.
The root package also reuses the native SwiftBridge, bridge-macro and highlighter
test targets. From the repository root, run
swift test --scratch-path artifacts/swift/root-tests --disable-build-manifest-caching --configuration release.
These tests are visible to SwiftPM and Swift Package Index without becoming
library products. Full language/host Conformance runs through Python and the internal Swift adapter.
Xcode workspace
GameEventScript.xcworkspace opens Runtime,
Compiler, SwiftBridge, SyntaxHighlighter, Conformance and the CLI together. The workspace references the local
SwiftPM packages directly; their Package.swift manifests remain the build configuration.
There are no duplicate .xcodeproj targets or source lists to maintain.
Open it from the repository root:
./scripts/open-swift-xcode.shThe launcher configures this workspace’s local Xcode preferences so Derived Data
and build products stay below artifacts/swift/xcode, then opens Xcode. It preserves
other preferences and does not change global Xcode settings. These user settings
are ignored by Git; the workspace and shared test scheme are tracked. After the
first setup, the workspace can also be opened directly in Finder.
Select My Mac and one of the GameEventScriptRuntime,
GameEventScriptCompiler, GameEventScriptSwiftBridge, GameEventScriptSyntaxHighlighter, GameEventScriptConformance or GameEventScriptTool
schemes to build with Cmd+B. The shared GameEventScriptTool scheme builds the
ges executable: Cmd+R launches it with --help, Cmd+U runs its native CLI
tests, and Profile uses the Release executable. Change CLI arguments under
Product → Scheme → Edit Scheme → Run → Arguments. For relative input paths,
set the working directory under Run → Options or pass absolute paths.
SwiftPM is the CLI’s build system; its executable package is not a public library
dependency. The shared GameEventScriptConformance
scheme runs the native Compiler, register and Bridge integration tests with Cmd+U in Debug. The
GameEventScriptSwiftBridge scheme runs its native tests independently.
Before the first full test run, execute
./scripts/test-swift.sh once to prepare the C#-compiled interoperability fixtures
in artifacts/swift/runtime-fixtures; refresh them after corpus changes.
The ges-conformance-adapter executable is also available as a scheme; Python
starts it using the JSON observation protocol. Performance measurements continue to use the
separate Release script and calibrated profile.
For a headless Xcode test run:
./scripts/open-swift-xcode.sh --configure-onlyxcodebuild -workspace implementation/swift/GameEventScript.xcworkspace \ -scheme GameEventScriptConformance -destination 'platform=macOS' \ -derivedDataPath artifacts/swift/xcode -parallel-testing-enabled NO testSwiftPM verification
The local SwiftBridge package explicitly requires macOS 10.15 for SwiftSyntax.
The root distribution (including ges), CLI and Conformance packages
require macOS 10.15.4 or newer for the executable adapters’ throwing Foundation
file-handle I/O. The standalone Runtime, Compiler and SyntaxHighlighter packages
do not inherit these package requirements.
All entry points are in the repository’s scripts directory and can also be
invoked by absolute path from another working directory:
| Command | Purpose |
|---|---|
./scripts/clean.sh [--dry-run] [--artifacts-only] |
Remove repository build outputs; preview with --dry-run (scope) |
./scripts/build-swift.sh |
Build every SwiftPM package independently in Release; no .NET dependency |
./scripts/build-swift.sh --configuration debug |
Build the same packages in Debug |
./scripts/format-swift.sh |
Check 250-column formatting and one blank line around callable/type declarations |
./scripts/format-swift.sh --fix |
Apply formatting to manifests, Sources, Tests and the spacing helper |
python3 scripts/test-swift-spacing.py |
Verify syntax-aware declaration spacing and preservation of comments/strings |
./scripts/test-swift-tool.sh |
Verify CLI adapters, real process I/O and terminal editing without .NET |
./scripts/test-swift-bridge.sh |
Verify native Swift adapters and Compiler/Runtime binding integration without .NET |
./scripts/install-swift-tool.sh |
Build all packages and install/update the native ges CLI |
./scripts/uninstall-swift-tool.sh |
Remove the owned Swift CLI installation |
./scripts/test-swift.sh |
Export C# interoperability fixtures, run native tests, strict shared Conformance and bidirectional numeric text roundtrips |
python3 scripts/test-number-text-roundtrip.py |
Verify exact C# ↔ Swift Number/Quantity/Percentage text exchange with deterministic inputs |
./scripts/test-swift-performance.sh |
Verify the calibrated Release performance profile |
python3 scripts/verify-swift-api.py |
Verify approved public API snapshots and public Swift documentation |
python3 scripts/test-swift-api.py |
Verify the documentation gate’s positive and negative controls |
python3 scripts/test-swift-incremental.py |
Verify added/renamed/removed dependency sources and unchanged-build object reuse |
python3 scripts/verify-swift-dependencies.py |
Verify direct target dependencies for imports, including native tests |
python3 scripts/verify-swift-bytecode.py |
Verify the shared opcode/operand registry |
./scripts/open-swift-xcode.sh |
Configure local build paths and open the Xcode workspace |
Isolated package-consumer, incremental-build and CLI process checks delete their
temporary build trees after success. The latest logs remain in latest-logs under
artifacts/swift-package, artifacts/swift-incremental-tests and
artifacts/swift/tool-process-tests, respectively. Failed or interrupted checks
print and retain their workspace for diagnosis. Existing workspaces and reusable
build caches are not automatically deleted.
Build outputs use artifacts/swift/runtime, compiler, swiftbridge, conformance and tool;
the Conformance directory is shared with the existing test scripts. Build and
format scripts discover local packages from their manifests, so added packages
participate without duplicating source lists. Formatting excludes generated
artifacts and Xcode’s user state. Public SwiftPM consumption uses the root
package and a published version tag. The CLI installer defaults to $HOME/.local/bin and supports --tool-path DIRECTORY;
see the CLI guide for installation and updates.
Build/test scripts use the toolchain’s default build system (Swift Build with
Swift 6.4), without changing the public packages’ minimum tool versions.
They regenerate the SwiftPM build plan with
--disable-build-manifest-caching. This ensures new, renamed or removed files in
local dependency packages are discovered, including a new Runtime file while
building Compiler. Compiled objects and module caches remain incremental; no
Clean is performed during installation. Use the same option for manual native
SwiftPM builds after source-structure changes. The incremental CI test exercises
these changes in disposable packages and verifies object reuse on an unchanged build.
Swift CI skips native verification only when all changes are confined to the
website, guides or the explicit root documentation allowlist. Specifications,
Conformance cases, implementation files, scripts, manifests, workflows and unknown
paths still require every check. Manual workflow runs always verify everything;
the required verify check fails if change selection fails. Run
python3 scripts/test-ci-swift-scope.py to exercise these selection rules.
Local-package and API build directories are cached by OS, architecture, Swift/Xcode toolchain and build configuration. Tests and symbol extraction still execute on cache hits. The tagged distribution consumers, root distribution tests and incremental-build controls always use fresh isolated workspaces. The first run after a cache miss remains a full build; subsequent runs can reuse dependencies. Newer revisions cancel obsolete CI runs for the same branch or pull request.
Use Swift 6.0 or newer. The complete verification script additionally uses .NET 10 for independent cross-language binary inputs:
./scripts/test-swift.shpython3 scripts/verify-swift-api.pyThe script checks the explicit opcode/operand registry against C#, builds Swift in Release, compiles the original Markdown sources natively, and runs the strict Conformance report. Separately it exports C#-compiled binary inputs and verifies them against the same Markdown expectations in the Swift Runtime. Those manifests include both binary SHA-256 and complete Markdown-document SHA-256; no expected results are exported from C#. Neither Compiler nor Runtime depends on .NET.
Every authored public declaration has a /// documentation comment, including
properties, initializers, enum cases, protocol requirements and bridge extensions.
These comments are available in Xcode Quick Help and Swift symbol graphs. The API
gate rejects missing or empty comments and comments merely inherited from another
module for handwritten implementations. Compiler-synthesized members are excluded.
The API gate compares all four library packages’ declared exported symbols with
api/*.approved.txt. Update snapshots explicitly after reviewing API changes:
python3 scripts/verify-swift-api.py --updateVerified on 2026-09-23 with Swift 6.4 on macOS arm64, Release:
- 1,679/1,679 behavior checks from the original 96 Markdown documents pass with native Swift compilation, including 172 expected compilation failures, 15 bytecode constraints, three metadata cases, and all eleven source-based GESA snapshots.
- The ordinary hardware-independent report passes 1,648 cases and skips 31 optional performance measurements. The last calibrated performance run passed all 31 measured workloads.
- The Swift 6.4/macOS 26/Apple M3 Max profile measures cumulative allocations and elapsed time. All sixteen warmed dispatch variants have zero allocations. See Performance.md for scope, references and reproduction.
- All 60 shared binary cases pass, including canonical runtime-segment comparisons against Swift compiler output, malformed inputs, rewrites, fixture execution and four GESA snapshots of identical binary inputs.
- Independent Runtime verification passes 1,363/1,363 cases with C# inputs.
- Nineteen Conformance/adapter/bootstrap tests pass, including the Markdown bootstrap fixtures, compiler ownership/options and resource-limit failure paths.
The CapabilityMatrix records the exact corpus identity and report locations.
Run all correctness cases with native Swift compilation, without .NET:
swift build --package-path implementation/swift/GameEventScriptConformance \ --scratch-path artifacts/swift/conformance --disable-build-manifest-caching -c releasepython3 conformance/runner/main.py run --kind supported \ --output artifacts/swift/conformance-results/ConformanceResults.json \ --adapter artifacts/swift/conformance/release/ges-conformance-adapterPython writes the canonical ConformanceResults.json report. The full test script
also checks all 31 performance scenarios’ behavior with native compilation,
without measuring them, in PerformanceCorrectness.json. This preserves the old
native compiler corpus coverage on every CI host.
After exporting C# inputs, python3 scripts/test-swift-runtime.py verifies their
binary and source-document hashes and writes RuntimeResults.json, explicitly
identifying C# compiler inputs. No native compiler fallback is allowed in that run.
Adapter transport tests live in GameEventScriptConformance/adapter/tests.
Generated inputs, reports and build products stay under ignored artifacts.
Compile source text
Add GameEventScriptCompiler as a local SwiftPM dependency/product in the same
way as Runtime below. The builder accepts texts and optional diagnostic source
names; it performs no file I/O:
import GameEventScriptCompilerimport GameEventScriptRuntime
let program = try GameEventScriptBuilder.create() .addScript(""" module example function double(_ value as :Number) be value + value on Main(args) { emit ConsoleOut(double(21)) } """, sourceName: "example.ges") .compile()let bytes = try GameEventScriptProgramWriter.bytes(program)// The embedding can save bytes, or load program directly into a Host.Repeated addScript calls compile sources jointly. compile() can be repeated;
previously returned Programs remain immutable. Debug symbols, source maps and
source archives are included by default. Use .withDebugInfo(.none) for compact
output, .withProgramVersion(...) to set the portable version, and
.withExternalTypeCatalog(...) for declarative external types. Runtime bindings
remain separate. GameEventScriptCompileError.diagnostics exposes stable phase,
code, symbol and source location. Invalid public options throw API errors.
Consume the Runtime
Add the package to a local SwiftPM consumer:
.package(path: "/path/to/GameEventScript/implementation/swift/GameEventScriptRuntime")Add its product to the consuming target:
.product(name: "GameEventScriptRuntime", package: "GameEventScriptRuntime")Load bytes supplied by the embedding and execute messages:
import GameEventScriptRuntime
final class Output: GameEventScriptNativeMessageHandler { func handle(_ message: GameEventScriptMessage, context: GameEventScriptContext) throws { // Deliver message.arguments to your product; Runtime performs no I/O. }}
func execute(_ bytes: [UInt8]) throws -> (start: GameEventScriptStartResult, execution: GameEventScriptExecutionResult?) { let program = try GameEventScriptProgramReader.read(bytes) let host = try GameEventScriptHost.createBuilder().withRandomSeed(123).build() let output = try GameEventScriptMessageSignature(name: "Done", parameters: ["value"]) _ = try host.subscribe(output, handler: Output()) let instance = try host.load(program) defer { instance.detach() } let startup = try host.start() guard host.isReady else { return (startup, nil) } host.receive(try GameEventScriptMessage(name: "Start", arguments: [ GameEventScriptMessageArgument(name: "value", value: .integer(42)) ])) let result = try host.runToCompletion() return (startup, result)}executeFrame(opcodeBudget:) allows bounded stepping and resumption. The host
retains subscriptions and loaded Programs until explicitly detached; discarding
a handle does not unsubscribe it. Enqueue-time snapshots and dispatch ordering
match the shared Host contract. Configure through createBuilder(), then build, load all Programs and call
start(). Start runs only the initial group; its emitted messages wait for normal
pumping. A later Load with initialization has a pending instance startResult until its queued init
finishes. A failed late init removes that instance, its outputs and captured
deliveries without resetting host readiness. See Host runtime for the full contract.
Programs and collections use immutable Swift value semantics and copy-on-write storage. Unicode-scalar identity, exact Int64 ranges, Binary64 values, units, and ordered argument labels follow the shared specifications. VM entry reads arguments by index; frame/register storage and callback objects are reused. Callbacks and argument borrows are synchronous and must not be retained.
Public SwiftPM consumption uses one repository-root Git dependency after a version tag has been published; no Swift registry upload is required. See the Swift embedding guide. The individual packages can also be consumed by local path for development.
Native Swift integration
The optional SwiftBridge guide provides examples for closure subscriptions, ordered message arguments, strict native value conversion, extension registries, KeyPath-based external types and the synchronized Host runner. Its library uses Runtime plus an internal SwiftSyntax-based build-time macro target; compiler catalogs use Runtime’s declarative interfaces. Existing portable protocols remain usable without any Bridge dependency.
Declaration spacing
Swift formatting uses a 250-character target width and respects existing line
breaks. Deliberately multiline function bodies remain multiline; compact bodies
may stay on one line. This also preserves existing breaks elsewhere.
lineBreakBeforeEachArgument places each parameter/argument on its own line
when a list wraps; fitting lists may remain on one line. Functions, methods, initializers, deinitializers,
subscripts and type declarations (including extensions) are separated from
neighbouring items by exactly one blank line. Documentation comments and
attributes stay with their declaration; no blank line is inserted immediately
after an opening brace. Consecutive stored properties remain grouped.
swift-format controls wrapping and maximum blank lines. The formatting script
also uses the active toolchain’s SwiftParser/SwiftSyntax modules to enforce
declaration spacing without rewriting string contents. Its compiled helper is
cached under artifacts/swift/formatting; it adds no package dependency. Both
formatting and the helper’s regression controls run in Swift CI.
Explicit message JSON exchange
The Runtime provides GameEventScriptMessageJson for optional product transport.
Use Serialize/Deserialize in C#, or serialize/deserialize in Swift, for
messages; the corresponding SerializeValue/serializeValue methods encode a
standalone value. Decoding reconstructs immutable data and never runs Record or
native constructors. External objects export as typed Record snapshots. Local
Publish does not serialize; configure encoding explicitly at your I/O boundary.
The message format defines the envelope and errors.
The CI API gate uses python3 scripts/verify-swift-api.py --reuse-local-builds
after test-swift.sh. SwiftPM refreshes the existing Release conformance, Bridge and
highlighter builds before fresh symbol extraction; approved snapshots and
documentation checks are unchanged. Without this option, the API gate retains
its independent per-package Debug builds.
Swift CI runs isolated tagged-package consumers in parallel with native tests,
Conformance and API verification. The required verify job aggregates native,
distribution and Linux-highlighter results and rejects failed scope selection or
unexpected skipped jobs. Clean consumer build directories remain uncached.
Known Card Lab browser assets can skip native Swift CI because the Website workflow still builds and tests the native example and WASM application. New files, build scripts, package manifests and Swift sources require full native verification; manual workflow runs always select every check.
The shared verification script also runs bounded, deterministic .gesb reader
mutations through the existing C# and Swift adapters without additional builds.
See Binary reader fuzzing
for seeds, resource limits, watchdogs and failure reproduction.
Generated valid-program roundtrip properties use the same already-built probes. An independent V1 encoder checks exact field preservation and canonicalization, followed by actual C# ↔ Swift binary exchange.