Skip to content

Commit 38899e7

Browse files
authored
Merge pull request #1047 from live-codes/swift
add Swift language support
2 parents cd9aeca + 8e5405e commit 38899e7

101 files changed

Lines changed: 877 additions & 3 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ A [feature-rich](https://livecodes.io/docs/features/), open-source, **client-sid
1313
[![LiveCodes: npm version](https://img.shields.io/npm/v/livecodes)](https://www.npmjs.com/package/livecodes)
1414
[![LiveCodes: npm downloads](https://img.shields.io/npm/dm/livecodes)](https://www.npmjs.com/package/livecodes)
1515
[![LiveCodes: jsdelivr downloads](https://data.jsdelivr.com/v1/package/npm/livecodes/badge?style=rounded)](https://www.jsdelivr.com/package/npm/livecodes)
16-
[![LiveCodes: languages](https://img.shields.io/badge/languages-109-blue)](https://livecodes.io/docs/languages/)
16+
[![LiveCodes: languages](https://img.shields.io/badge/languages-110-blue)](https://livecodes.io/docs/languages/)
1717
[![LiveCodes: docs](https://img.shields.io/badge/Documentation-575757?logo=gitbook&logoColor=white)](https://livecodes.io/docs/)
1818
[![LiveCodes: llms.txt](https://img.shields.io/badge/llms.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms.txt)
1919
[![LiveCodes: llms-full.txt](https://img.shields.io/badge/llms--full.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms-full.txt)

‎docs/docs/languages/swift-wasm.mdx‎

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Swift (Wasm)
2+
3+
[Swift](https://www.swift.org/) is a general-purpose programming language developed by Apple, designed for safety, performance and expressiveness.
4+
5+
In LiveCodes, Swift is compiled to WebAssembly by the Swift compiler itself, running on WebAssembly: `swift-frontend` compiles the source and LLVM's `wasm-ld` links the result, entirely in the browser. No backend is involved.
6+
7+
:::info Note
8+
9+
The native `swiftc` is a driver that spawns the compiler frontend and the linker as separate processes, and WebAssembly cannot spawn processes. Here the two run as separate WebAssembly modules in the same [result page](../features/result.mdx), driven by JavaScript. The toolchain is about 70 MB and is downloaded on the first run, which can take some time.
10+
11+
:::
12+
13+
## Usage
14+
15+
Demo:
16+
17+
import LiveCodes from '../../src/components/LiveCodes.tsx';
18+
19+
export const swiftConfig = {
20+
activeEditor: 'script',
21+
script: {
22+
language: 'swift-wasm',
23+
content: `struct Greeting {
24+
let name: String
25+
var message: String { "Hello, \\(name)!" }
26+
}\n
27+
for name in ["World", "LiveCodes", "Swift"] {
28+
print(Greeting(name: name).message)
29+
}`,
30+
},
31+
mode: 'simple',
32+
editor: 'auto',
33+
tools: {
34+
status: 'full',
35+
},
36+
};
37+
38+
<LiveCodes config={swiftConfig}></LiveCodes>
39+
40+
### Standard I/O
41+
42+
Swift code runs in the context of the [result page](../features/result.mdx). Standard output (e.g. `print`) is captured and displayed in the [console](../features/console.mdx). Standard input is passed by setting the `livecodes.swift.input` property in JavaScript and is read in the Swift code using `readLine()`.
43+
44+
### Communication with JavaScript
45+
46+
The Swift code runs in the context of the result page. A few helper properties and methods are available in the browser global `livecodes.swift` object:
47+
48+
- `livecodes.swift.input`: The standard input passed to the Swift program. It can be set before the initial run, or passed to `run` for subsequent runs.
49+
- `livecodes.swift.loaded`: A promise that resolves when the Swift environment (compiler, linker and standard library) is fully loaded (and rejects if it fails to load). Other helpers should be used after this promise resolves.
50+
- `livecodes.swift.ready`: A boolean that is `true` once the environment is loaded and a run has completed.
51+
- `livecodes.swift.output`: The standard output of the last run.
52+
- `livecodes.swift.error`: The compiler diagnostics or runtime error of the last run, if any.
53+
- `livecodes.swift.exitCode`: The exit code of the last run.
54+
- `livecodes.swift.run(input)`: Runs the code in the editor, optionally passing standard input, and returns a promise that resolves to `{ output, error, exitCode }`.
55+
56+
```js
57+
await livecodes.swift.loaded;
58+
const { output, error, exitCode } = await livecodes.swift.run(livecodes.swift.input);
59+
console.log(output);
60+
```
61+
62+
## Language Info
63+
64+
### Name
65+
66+
`swift-wasm`
67+
68+
### Aliases / Extensions
69+
70+
`swift`, `swift-wasm`, `wasm.swift`
71+
72+
### Editor
73+
74+
`script`
75+
76+
## Compiler
77+
78+
The [Swift compiler](https://github.com/swiftlang/swift) frontend (`swift-frontend`) and LLVM's `wasm-ld` linker, both compiled to WebAssembly and running in the browser. The build is provided by [`swift-toolchain-wasm`](https://github.com/tothambrus11/swift-toolchain-wasm).
79+
80+
### Version
81+
82+
Swift 6.3.3
83+
84+
## Code Formatting
85+
86+
Not supported.
87+
88+
## Limitations
89+
90+
The compiler runs on WebAssembly, which affects what it can do:
91+
92+
- Programs are single-file.
93+
- **Macros and compiler plugins are not supported.** Swift runs them as separate processes, and WebAssembly cannot spawn processes.
94+
- **The Swift-implemented optimizer passes are disabled** because C++ interop is not available for this target. This affects optimization quality, not correctness.
95+
- **A 4 GiB address space limit applies.** Single-file programs fit comfortably; very large modules may not.
96+
- The toolchain (about 70 MB) is downloaded on the first run.
97+
98+
## Example Usage
99+
100+
This example passes standard input and runs the code again on each click, using the browser global `livecodes.swift` (also check the code in the HTML editor):
101+
102+
<LiveCodes template="swift-wasm" height="80vh"></LiveCodes>
103+
104+
## Live Reload
105+
106+
By default, new code changes are sent to the result page for re-evaluation without a full page reload, avoiding the need to reinitialize the Swift WebAssembly environment. This behavior can be disabled by adding the code comment `// __livecodes_reload__` to the Swift code, which forces a full page reload.
107+
108+
This comment can be added in the [`hiddenContent` property of the editor](../configuration/configuration-object.mdx#markup) for embedded playgrounds.
109+
110+
## Starter Template
111+
112+
https://livecodes.io/?template=swift-wasm
113+
114+
## Links
115+
116+
- [Swift](https://www.swift.org/)
117+
- [The Swift Programming Language](https://docs.swift.org/swift-book/)
118+
- [Swift compiler](https://github.com/swiftlang/swift)
119+
- [swift-toolchain-wasm](https://github.com/tothambrus11/swift-toolchain-wasm)

‎docs/src/components/LanguageSliders.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export default function Sliders() {
9393
{ name: 'objc-wasm', title: 'Objective-C (Wasm)' },
9494
{ name: 'objcpp-wasm', title: 'Objective-C++ (Wasm)' },
9595
{ name: 'rust-wasm', title: 'Rust (Wasm)' },
96+
{ name: 'swift-wasm', title: 'Swift (Wasm)' },
9697
{ name: 'haskell', title: 'Haskell' },
9798
{ name: 'haskell-wasm', title: 'Haskell (Wasm)' },
9899
{ name: 'zig-wasm', title: 'Zig (Wasm)' },

‎docs/src/components/TemplateList.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const templates = [
5151
{ name: 'cpp-wasm', title: 'C++ (Wasm) Starter', thumbnail: 'cpp.svg' },
5252
{ name: 'objc-wasm', title: 'Objective-C (Wasm) Starter', thumbnail: 'objective-c.svg' },
5353
{ name: 'rust-wasm', title: 'Rust (Wasm) Starter', thumbnail: 'rust.svg' },
54+
{ name: 'swift-wasm', title: 'Swift (Wasm) Starter', thumbnail: 'swift.svg' },
5455
{ name: 'haskell', title: 'Haskell Starter', thumbnail: 'haskell.svg' },
5556
{ name: 'haskell-wasm', title: 'Haskell (Wasm) Starter', thumbnail: 'haskell.svg' },
5657
{ name: 'zig-wasm', title: 'Zig (Wasm) Starter', thumbnail: 'zig.svg' },

‎e2e/specs/starter.spec.ts‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,35 @@ test.describe('Starter Templates from UI', () => {
324324
await expect(getResult().locator('text=You clicked')).toHaveText('You clicked 3 times.');
325325
});
326326

327+
test('swift-wasm Starter', async ({ page, getTestUrl }) => {
328+
// the Swift compiler, the linker and the stdlib sysroot (~70 MB) are downloaded on
329+
// the first run
330+
test.slow();
331+
332+
await page.goto(getTestUrl());
333+
334+
const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
335+
336+
await app.click('[aria-label="Project"]');
337+
await app.click('text=New');
338+
await app.click('text=Swift (Wasm) Starter');
339+
340+
await waitForEditorFocus(app);
341+
await waitForResultUpdate();
342+
343+
// the counter stays disabled until the toolchain has loaded and run once
344+
await expect(getResult().locator('#counter-button')).toBeEnabled({ timeout: 280_000 });
345+
346+
await getResult().click('text=Click me');
347+
await getResult().click('text=Click me');
348+
await getResult().click('text=Click me');
349+
350+
await expect(getResult().locator('h1')).toHaveText('Hello, Swift!');
351+
// Each click triggers an asynchronous run, so the counter is asserted with
352+
// retries rather than read once.
353+
await expect(getResult().locator('text=You clicked')).toHaveText('You clicked 3 times.');
354+
});
355+
327356
test('c-wasm Starter', async ({ page, getTestUrl }) => {
328357
// the compiler, linker and sysroot (~29 MB) are downloaded on the first run
329358
test.slow();

‎functions/vendors/templates.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export const starterTemplates = {
5151
"cpp-wasm": "C++ (Wasm) Starter",
5252
"objc-wasm": "Objective-C (Wasm) Starter",
5353
"rust-wasm": "Rust (Wasm) Starter",
54+
"swift-wasm": "Swift (Wasm) Starter",
5455
"zig-wasm": "Zig (Wasm) Starter",
5556
"java": "Java Starter",
5657
"csharp-wasm": "C# (Wasm) Starter",

‎scripts/build.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ const iifeBuild = () =>
265265
'languages/scss/lang-scss-compiler.ts',
266266
'languages/solid/lang-solid-compiler.ts',
267267
'languages/sql/lang-sql-compiler.ts',
268+
'languages/swift-wasm/lang-swift-wasm-script.ts',
268269
'languages/sql/lang-sql-script.ts',
269270
'languages/svelte/lang-svelte-compiler.ts',
270271
'languages/tcl/lang-tcl-script.ts',

‎server/php/inc/starter-templates.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"cpp-wasm": "C++ (Wasm) Starter",
5252
"objc-wasm": "Objective-C (Wasm) Starter",
5353
"rust-wasm": "Rust (Wasm) Starter",
54+
"swift-wasm": "Swift (Wasm) Starter",
5455
"zig-wasm": "Zig (Wasm) Starter",
5556
"java": "Java Starter",
5657
"csharp-wasm": "C# (Wasm) Starter",

‎src/livecodes/UI/command-menu-actions.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ export const getCommandMenuActions = ({
307307
'cpp-wasm',
308308
'objc-wasm',
309309
'rust-wasm',
310+
'swift-wasm',
310311
'zig-wasm',
311312
'java',
312313
'csharp-wasm',
Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)