diff --git a/.agents/skills/livecodes/language-support/references/languages.md b/.agents/skills/livecodes/language-support/references/languages.md index ec7ad2679a..2927816918 100644 --- a/.agents/skills/livecodes/language-support/references/languages.md +++ b/.agents/skills/livecodes/language-support/references/languages.md @@ -108,47 +108,48 @@ Enabled via `processors` config: ### Backend Languages -| Name | Aliases | Notes | -| --------------------------- | -------------------------------------------------- | ----------------------------------------------------- | -| Python | `python`, `py` | Brython (Python -> JS) | -| Python (Wasm) | `pyodide`, `python-wasm`, `py-wasm` | Pyodide runtime (~15MB) | -| Ruby | `ruby`, `rb` | Opal (Ruby -> JS) | -| Ruby (Wasm) | `ruby-wasm`, `wasm.rb` | Ruby WASM | -| Go | `go`, `golang` | Gopherjs (Go -> JS) | -| Go (Wasm) | `go-wasm`, `wasm.go` | Go WASM | -| PHP | `php` | Uniter (PHP -> JS) | -| PHP | `php`, `php-wasm`, `wasm.php` | PHP WASM | -| C (Wasm) | `c-wasm`, `cwasm`, `wasm.c`, `c` | Clang WASM | -| C++ | `cpp`, | JSCPP interpreter | -| C++ (Wasm) | `cpp-wasm`, `clang`, `wasm.cpp` | Clang WASM | -| Objective-C | `objc-wasm`, `objc`, `wasm.m` | Clang WASM | -| Objective-C++ | `objcpp-wasm`, `objcpp`, `wasm.mm` | Clang WASM | -| Java | `java` | Java runtime | -| C# | `csharp-wasm`, `cs`, `cs-wasm`, `wasm.cs` | C# WASM | -| VB.NET | `vb-wasm`, `vb`, `vbnet`, `wasm.vb` | VB.NET WASM | -| F# | `fsharp`, `fs`, `fsx` | Fable (F# -> JS) | -| F# (Wasm) | `fsharp-wasm`, `fs-wasm`, `wasm.fs` | .NET WASM | -| R | `r`, `rlang`, `rstats`, `r-wasm` | R WASM | -| Lua | `lua`, `lua-wasm`, `luawasm`, `wasm.lua` | Lua WASM | -| Teal | `teal`, `tl` | Typed Lua | -| Fennel | `fennel`, `fnl` | Lua lisp | -| Julia | `julia`, `jl` | Julia runtime | -| Scheme | `scheme`, `scm` | BiwaScheme | -| Common Lisp | `commonlisp`, `common-lisp`, `lisp` | Common Lisp | -| ClojureScript (Cherry) | `clojurescript-cherry`, `cljs-cherry` | Cherry transpiler; imports npm packages as ES modules | -| ClojureScript (self-hosted) | `clojurescript-selfhosted`, `cljs-selfhosted` | Official ClojureScript compiler; no npm imports | -| Perl | `perl`, `pl`, `pm` | Perl runtime | -| Pascal | `pascal`, `pas`, `pp`, `pas2js` | pas2js (Pascal -> JS, WASM) | -| Ada (Wasm) | `ada`, `ada-wasm`, `adb`, `ads`, `hac`, `wasm.ada` | HAC (Ada -> WASM) | -| Gleam | `gleam` | Gleam language | -| Elm | `elm` | Elm compiler (WASM) | -| Haskell | `haskell`, `hs`, `lhs` | MicroHs (not GHC) | -| Haskell (Wasm) | `haskell-wasm`, `hs-wasm`, `wasm.hs`, `hswasm` | GHC WASM | -| Rust (Wasm) | `rust-wasm`, `rs-wasm`, `wasm.rs` | Rust WASM | -| Swift (Wasm) | `swift-wasm`, `swift`, `wasm.swift` | Swift WASM | -| Zig (Wasm) | `zig-wasm`, `zig` | Zig WASM | -| Tcl | `tcl` | Tcl interpreter | -| WebAssembly | `wat`, `wast`, `wasm`, `webassembly` | WAT format | +| Name | Aliases | Notes | +| --------------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------- | +| Python | `python`, `py` | Brython (Python -> JS) | +| Python (Wasm) | `pyodide`, `python-wasm`, `py-wasm` | Pyodide runtime (~15MB) | +| Ruby | `ruby`, `rb` | Opal (Ruby -> JS) | +| Ruby (Wasm) | `ruby-wasm`, `wasm.rb` | Ruby WASM | +| Go | `go`, `golang` | Gopherjs (Go -> JS) | +| Go (Wasm) | `go-wasm`, `wasm.go` | Go WASM | +| PHP | `php` | Uniter (PHP -> JS) | +| PHP | `php`, `php-wasm`, `wasm.php` | PHP WASM | +| C (Wasm) | `c-wasm`, `cwasm`, `wasm.c`, `c` | Clang WASM | +| C++ | `cpp`, | JSCPP interpreter | +| C++ (Wasm) | `cpp-wasm`, `clang`, `wasm.cpp` | Clang WASM | +| Objective-C | `objc-wasm`, `objc`, `wasm.m` | Clang WASM | +| Objective-C++ | `objcpp-wasm`, `objcpp`, `wasm.mm` | Clang WASM | +| Java | `java` | Java runtime | +| C# | `csharp-wasm`, `cs`, `cs-wasm`, `wasm.cs` | C# WASM | +| VB.NET | `vb-wasm`, `vb`, `vbnet`, `wasm.vb` | VB.NET WASM | +| F# | `fsharp`, `fs`, `fsx` | Fable (F# -> JS) | +| F# (Wasm) | `fsharp-wasm`, `fs-wasm`, `wasm.fs` | .NET WASM | +| R | `r`, `rlang`, `rstats`, `r-wasm` | R WASM | +| Lua | `lua`, `lua-wasm`, `luawasm`, `wasm.lua` | Lua WASM | +| Teal | `teal`, `tl` | Typed Lua | +| Fennel | `fennel`, `fnl` | Lua lisp | +| Julia | `julia`, `jl` | Julia runtime | +| Scheme | `scheme`, `scm` | BiwaScheme | +| Common Lisp | `commonlisp`, `common-lisp`, `lisp` | Common Lisp | +| ClojureScript (Cherry) | `clojurescript-cherry`, `cljs-cherry` | Cherry transpiler; imports npm packages as ES modules | +| ClojureScript (self-hosted) | `clojurescript-selfhosted`, `cljs-selfhosted` | Official ClojureScript compiler; no npm imports | +| Perl | `perl`, `pl`, `pm` | Perl runtime | +| Pascal | `pascal`, `pas`, `pp`, `pas2js` | pas2js (Pascal -> JS, WASM) | +| Ada (Wasm) | `ada`, `ada-wasm`, `adb`, `ads`, `hac`, `wasm.ada` | HAC (Ada -> WASM) | +| Gleam | `gleam` | Gleam language | +| Elm | `elm` | Elm compiler (WASM) | +| Haskell | `haskell`, `hs`, `lhs` | MicroHs (not GHC) | +| Haskell (Wasm) | `haskell-wasm`, `hs-wasm`, `wasm.hs`, `hswasm` | GHC WASM | +| Rust (Wasm) | `rust-wasm`, `rs-wasm`, `wasm.rs` | Rust WASM | +| Swift (Wasm) | `swift-wasm`, `swift`, `wasm.swift` | Swift WASM | +| Zig (Wasm) | `zig-wasm`, `zig` | Zig WASM | +| Tcl | `tcl` | Tcl interpreter | +| WebAssembly | `wat`, `wast`, `wasm`, `webassembly` | WAT format | +| Assembly (Wasm) | `assembly-wasm`, `assembly`, `asm`, `asm-wasm`, `x86`, `x86-64`, `nasm`, `wasm.asm` | Keystone + Unicorn (WASM), x86-64 assembly | ### Data & Logic Languages diff --git a/README.md b/README.md index dff28ff934..f9caeb6746 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ A [feature-rich](https://livecodes.io/docs/features/), open-source, **client-sid [![LiveCodes: npm version](https://img.shields.io/npm/v/livecodes)](https://www.npmjs.com/package/livecodes) [![LiveCodes: npm downloads](https://img.shields.io/npm/dm/livecodes)](https://www.npmjs.com/package/livecodes) [![LiveCodes: jsdelivr downloads](https://data.jsdelivr.com/v1/package/npm/livecodes/badge?style=rounded)](https://www.jsdelivr.com/package/npm/livecodes) -[![LiveCodes: languages](https://img.shields.io/badge/languages-112-blue)](https://livecodes.io/docs/languages/) +[![LiveCodes: languages](https://img.shields.io/badge/languages-113-blue)](https://livecodes.io/docs/languages/) [![LiveCodes: docs](https://img.shields.io/badge/Documentation-575757?logo=gitbook&logoColor=white)](https://livecodes.io/docs/) [![LiveCodes: llms.txt](https://img.shields.io/badge/llms.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms.txt) [![LiveCodes: llms-full.txt](https://img.shields.io/badge/llms--full.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms-full.txt) diff --git a/docs/docs/languages/assembly-wasm.mdx b/docs/docs/languages/assembly-wasm.mdx new file mode 100644 index 0000000000..2994bdedcf --- /dev/null +++ b/docs/docs/languages/assembly-wasm.mdx @@ -0,0 +1,147 @@ +# Assembly (Wasm) + +[x86-64 assembly](https://en.wikipedia.org/wiki/X86_assembly_language) is the low-level language of the machine: instructions are handed to the CPU as-is, with no compiler in between. + +In LiveCodes, assembly is assembled by [Keystone](https://www.keystone-engine.org/) and executed by [Unicorn](https://www.unicorn-engine.org/) — a real assembler and a real CPU emulator, both compiled to WebAssembly and running entirely in the browser. No backend is involved. + +:::info Note + +The browser has no operating system for a program to talk to, so a small set of Linux-style `syscall`s is served by the page: `read` (`0`), `write` (`1`) and `exit` (`60`, also `exit_group` at `231`). Everything else returns `-ENOSYS`. There is no libc, no dynamic linking and no filesystem. + +::: + +## Usage + +Demo (a 64-bit division loop that prints the sum of 1..100): + +import LiveCodes from '../../src/components/LiveCodes.tsx'; + +export const assemblyConfig = { + activeEditor: 'script', + script: { + language: 'assembly-wasm', + content: `; Prints the sum of 1..100 using a real 64-bit division loop. + + xor rax, rax ; total = 0 + mov rcx, 100 ; count = 100 + +accumulate: + add rax, rcx + dec rcx + jnz accumulate ; rax = 5050 + + lea rdi, [rip + buf + 31] + mov byte ptr [rdi], 10 ; trailing newline + mov rbx, 10 ; divisor + +digit: + dec rdi + xor rdx, rdx + div rbx ; rdx:rax / 10 -> quotient in rax, remainder in rdx + add dl, 48 ; remainder -> ASCII + mov byte ptr [rdi], dl + test rax, rax + jnz digit + + lea rdx, [rip + buf + 32] + sub rdx, rdi ; length = end - start + mov rax, 1 ; write(1, digits, length) + mov rsi, rdi + mov rdi, 1 + syscall + + mov rax, 60 ; exit(0) + xor rdi, rdi + syscall + +buf: + .zero 32`, + }, + mode: 'simple', + editor: 'auto', + tools: { + status: 'full', + }, +}; + + + +### Standard I/O + +Assembly code runs in the context of the [result page](../features/result.mdx). Standard output (the `write` syscall) is captured and displayed in the [console](../features/console.mdx). Standard input (the `read` syscall) is passed by setting the `livecodes.assemblyWasm.input` property in JavaScript. + +### Communication with JavaScript + +The assembly code runs in the context of the result page. A few helper properties and methods are available in the browser global `livecodes.assemblyWasm` object (also available as `livecodes.asm`): + +- `livecodes.assemblyWasm.input`: The standard input passed to the program. It can be set before the initial run, or passed to `run` for subsequent runs. +- `livecodes.assemblyWasm.loaded`: A promise that resolves when the assembler and the emulator are fully loaded (and rejects if they fail to load). Other helpers should be used after this promise resolves. +- `livecodes.assemblyWasm.output`: The standard output of the last run. +- `livecodes.assemblyWasm.error`: The assembly diagnostics or runtime error of the last run, if any. +- `livecodes.assemblyWasm.exitCode`: The exit code of the last run. +- `livecodes.assemblyWasm.run(input)`: Assembles and runs the code in the editor, optionally passing standard input, and returns a promise that resolves to `{ output, error, exitCode }`. + +```js +await livecodes.assemblyWasm.loaded; +const { output, error, exitCode } = await livecodes.assemblyWasm.run(livecodes.assemblyWasm.input); +console.log(output); +``` + +## Language Info + +### Name + +`assembly-wasm` + +### Aliases / Extensions + +`assembly`, `asm`, `asm-wasm`, `assembly-wasm`, `x86`, `x86-64`, `nasm`, `wasm.asm` + +### Editor + +`script` + +## Compiler + +[Keystone](https://www.keystone-engine.org/) assembles the source to x86-64 machine code and [Unicorn](https://www.unicorn-engine.org/) executes it. Both are compiled to WebAssembly and loaded at run time by [`@live-codes/assembly-wasm`](https://www.npmjs.com/package/@live-codes/assembly-wasm), which bundles neither of them. + +### Version + +`keystone`: 0.9.2, `unicorn`: 2.1.4 + +## Code Formatting + +Not supported. + +## Limitations + +- **x86-64, Intel syntax only.** Keystone and Unicorn both support other architectures; only x86-64 is wired up. +- **A syscall shim, not Linux.** Only `read`, `write` and `exit` (and its alias `exit_group`) are served. There is no libc, no filesystem and no `argv` or environment. +- **Two memory regions.** The program and its data are mapped at `0x1000000` (64 KiB, and execution starts at the first byte), and the stack at `0x2000000` (64 KiB). There is no linker and no memory allocation. +- **Integers are decimal.** Write `0x` for hexadecimal and `0b` for binary. Keystone reads an unprefixed integer as hexadecimal, so the source is re-based before it is assembled; a leading zero is decimal too, and there is no implicit octal. +- **Comments.** `;` is accepted (as are `#` and `//`), and a `;` inside a string is data. +- **A program that never exits is stopped** after 10,000,000 instructions, which at the emulator's speed (a few million instructions per second) takes a few seconds. This is the only limit on a runaway loop: the emulator's own wall-clock timeout needs threads, which this WebAssembly build does not have. +- **About 5 MB is downloaded** on the first run, and cached afterwards. + +## Example Usage + +This example passes standard input and runs the code again on each click, using the browser global `livecodes.assemblyWasm` (also check the code in the HTML editor): + + + +## Live Reload + +By default, new code changes are sent to the result page for re-assembly and execution without a full page reload, avoiding the need to load the runtimes again. This behavior can be disabled by adding the comment `; __livecodes_reload__` to the assembly code, which forces a full page reload. + +This comment can be added in the [`hiddenContent` property of the editor](../configuration/configuration-object.mdx#markup) for embedded playgrounds. + +## Starter Template + +https://livecodes.io/?template=assembly-wasm + +## Links + +- [Keystone assembler framework](https://www.keystone-engine.org/) +- [Unicorn CPU emulator framework](https://www.unicorn-engine.org/) +- [X86 Assembly (Wikibooks)](https://en.wikibooks.org/wiki/X86_Assembly) +- [@live-codes/assembly-wasm](https://www.npmjs.com/package/@live-codes/assembly-wasm) diff --git a/docs/src/components/LanguageSliders.tsx b/docs/src/components/LanguageSliders.tsx index 68fcdd031d..956e0935b8 100644 --- a/docs/src/components/LanguageSliders.tsx +++ b/docs/src/components/LanguageSliders.tsx @@ -119,6 +119,7 @@ export default function Sliders() { { name: 'pascal', title: 'Pascal' }, { name: 'assemblyscript', title: 'AssemblyScript' }, { name: 'wat', title: 'WAT' }, + { name: 'assembly-wasm', title: 'Assembly (Wasm)' }, { name: 'sql', title: 'SQL' }, { name: 'postgresql', title: 'PostgreSQL' }, { name: 'prolog', title: 'Prolog' }, diff --git a/docs/src/components/TemplateList.tsx b/docs/src/components/TemplateList.tsx index d28479e831..7db8a59c35 100644 --- a/docs/src/components/TemplateList.tsx +++ b/docs/src/components/TemplateList.tsx @@ -78,6 +78,7 @@ const templates = [ { name: 'markdown', title: 'Markdown Starter', thumbnail: 'markdown.svg' }, { name: 'assemblyscript', title: 'AssemblyScript Starter', thumbnail: 'assemblyscript.svg' }, { name: 'wat', title: 'WebAssembly Text Starter', thumbnail: 'webassembly.svg' }, + { name: 'assembly-wasm', title: 'Assembly (Wasm) Starter', thumbnail: 'assembly.svg' }, { name: 'sql', title: 'SQL Starter', thumbnail: 'sqlite.svg' }, { name: 'postgresql', title: 'PostgreSQL Starter', thumbnail: 'postgresql.svg' }, { name: 'prolog', title: 'Prolog Starter', thumbnail: 'tau-prolog.svg' }, diff --git a/e2e/specs/starter.spec.ts b/e2e/specs/starter.spec.ts index 1a9c8f1bdb..5ef88c2b79 100644 --- a/e2e/specs/starter.spec.ts +++ b/e2e/specs/starter.spec.ts @@ -835,6 +835,32 @@ test.describe('Starter Templates from UI', () => { expect(counterText).toBe('You clicked 3 times.'); }); + test('Assembly (Wasm) Starter', async ({ page, getTestUrl }) => { + // the assembler and the emulator (~5 MB) are downloaded on the first run + test.slow(); + + await page.goto(getTestUrl()); + + const { app, getResult, waitForResultUpdate } = await getLoadedApp(page); + + await app.click('[aria-label="Project"]'); + await app.click('text=New'); + await app.click('text=Assembly (Wasm) Starter'); + + await waitForEditorFocus(app); + await waitForResultUpdate(); + + // the counter stays disabled until the runtimes have loaded and run once + await expect(getResult().locator('#counter-button')).toBeEnabled({ timeout: 120_000 }); + + await getResult().click('text=Click me'); + await getResult().click('text=Click me'); + await getResult().click('text=Click me'); + + await expect(getResult().locator('h1')).toHaveText('Hello, Assembly!'); + await expect(getResult().locator('text=You clicked')).toHaveText('You clicked 3 times.'); + }); + test('Bootstrap Starter', async ({ page, getTestUrl }) => { await page.goto(getTestUrl()); @@ -1447,6 +1473,28 @@ test.describe('Starter Templates from URL', () => { expect(counterText).toBe('You clicked 3 times.'); }); + test('Assembly (Wasm) Starter (in URL)', async ({ page, getTestUrl }) => { + // the assembler and the emulator (~5 MB) are downloaded on the first run + test.slow(); + + await page.goto(getTestUrl({ template: 'assembly-wasm' })); + + const { app, getResult, waitForResultUpdate } = await getLoadedApp(page); + + await waitForEditorFocus(app); + await waitForResultUpdate(); + + // the counter stays disabled until the runtimes have loaded and run once + await expect(getResult().locator('#counter-button')).toBeEnabled({ timeout: 120_000 }); + + await getResult().click('text=Click me'); + await getResult().click('text=Click me'); + await getResult().click('text=Click me'); + + await expect(getResult().locator('h1')).toHaveText('Hello, Assembly!'); + await expect(getResult().locator('text=You clicked')).toHaveText('You clicked 3 times.'); + }); + test('ReScript Starter (in URL)', async ({ page, getTestUrl }) => { test.fixme(); diff --git a/functions/vendors/templates.js b/functions/vendors/templates.js index 4965caaf86..2313e9b4ca 100644 --- a/functions/vendors/templates.js +++ b/functions/vendors/templates.js @@ -77,6 +77,7 @@ export const starterTemplates = { "pascal": "Pascal Starter", "assemblyscript": "AssemblyScript Starter", "wat": "WebAssembly Text Starter", + "assembly-wasm": "Assembly (Wasm) Starter", "sql": "SQL Starter", "postgresql": "PostgreSQL Starter", "prolog": "Prolog Starter", diff --git a/scripts/build.js b/scripts/build.js index 4076296545..a08e3f1385 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -269,6 +269,7 @@ const iifeBuild = () => 'languages/sql/lang-sql-compiler.ts', 'languages/swift-wasm/lang-swift-wasm-script.ts', 'languages/ada-wasm/lang-ada-wasm-script.ts', + 'languages/assembly-wasm/lang-assembly-wasm-script.ts', 'languages/sql/lang-sql-script.ts', 'languages/svelte/lang-svelte-compiler.ts', 'languages/tcl/lang-tcl-script.ts', diff --git a/server/php/inc/starter-templates.json b/server/php/inc/starter-templates.json index 59211a6c48..058e77398d 100644 --- a/server/php/inc/starter-templates.json +++ b/server/php/inc/starter-templates.json @@ -77,6 +77,7 @@ "pascal": "Pascal Starter", "assemblyscript": "AssemblyScript Starter", "wat": "WebAssembly Text Starter", + "assembly-wasm": "Assembly (Wasm) Starter", "sql": "SQL Starter", "postgresql": "PostgreSQL Starter", "prolog": "Prolog Starter", diff --git a/src/livecodes/UI/command-menu-actions.ts b/src/livecodes/UI/command-menu-actions.ts index de483b577a..1ea5817699 100644 --- a/src/livecodes/UI/command-menu-actions.ts +++ b/src/livecodes/UI/command-menu-actions.ts @@ -333,6 +333,7 @@ export const getCommandMenuActions = ({ 'pascal', 'assemblyscript', 'wat', + 'assembly-wasm', 'sql', 'postgresql', 'prolog', diff --git a/src/livecodes/assets/templates/assembly.svg b/src/livecodes/assets/templates/assembly.svg new file mode 100644 index 0000000000..8db957b287 --- /dev/null +++ b/src/livecodes/assets/templates/assembly.svg @@ -0,0 +1,11 @@ + + + + + + + + + + x86 + diff --git a/src/livecodes/html/language-info.html b/src/livecodes/html/language-info.html index c1dc7d4ec2..39874d1926 100644 --- a/src/livecodes/html/language-info.html +++ b/src/livecodes/html/language-info.html @@ -73,6 +73,47 @@

AsciiDoc

+
+

Assembly (Wasm)

+
+ x86-64 assembly assembled by + Keystone and + executed by + Unicorn, both + compiled to WebAssembly and running entirely in the browser. +
+ +

AssemblyScript

diff --git a/src/livecodes/i18n/locales/ar/language-info.lokalise.json b/src/livecodes/i18n/locales/ar/language-info.lokalise.json index 820f11e47e..24d66cc510 100644 --- a/src/livecodes/i18n/locales/ar/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/ar/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "يتم تجميع تعليمات x86-64 بواسطة Keystone وتنفيذها بواسطة Unicorn، وكلاهما مُجمَّع إلى WebAssembly ويعمل بالكامل داخل المتصفح." + }, + "assemblyWasm.link": { + "translation": " الموقع الرسمي لـ Keystone الموقع الرسمي لـ Unicorn تجميع X86 (ويكيبوكس) وثائق LiveCodes تحميل قالب البدء " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "لغة شبيهة بـ TypeScript لـ WebAssembly." }, diff --git a/src/livecodes/i18n/locales/ar/language-info.ts b/src/livecodes/i18n/locales/ar/language-info.ts index 16dd949bed..f9e3135c14 100644 --- a/src/livecodes/i18n/locales/ar/language-info.ts +++ b/src/livecodes/i18n/locales/ar/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>الموقع الرسمي لـ AsciiDoc <3> <4>الموقع الرسمي لـ Asciidoctor <5> <6>وثائق Asciidoctor <7> <8>تعلم X في Y دقائق، حيث X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'يتم تجميع تعليمات x86-64 بواسطة <1>Keystone وتنفيذها بواسطة <2>Unicorn، وكلاهما مُجمَّع إلى WebAssembly ويعمل بالكامل داخل المتصفح.', + link: '<1> <2>الموقع الرسمي لـ Keystone <3> <4>الموقع الرسمي لـ Unicorn <5> <6>تجميع X86 (ويكيبوكس) <7> <8>وثائق LiveCodes <9> <10>تحميل قالب البدء ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'لغة شبيهة بـ TypeScript لـ WebAssembly.', link: '<1> <2>الموقع الرسمي لـ AssemblyScript <3> <4>وثائق AssemblyScript <5> <6>تحميل القالب الأولي ', diff --git a/src/livecodes/i18n/locales/ar/translation.lokalise.json b/src/livecodes/i18n/locales/ar/translation.lokalise.json index af9cd63c23..b02834b394 100644 --- a/src/livecodes/i18n/locales/ar/translation.lokalise.json +++ b/src/livecodes/i18n/locales/ar/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "قالب Angular" }, + "templates.starter.assembly-wasm": { + "translation": "قالب Assembly (Wasm)" + }, "templates.starter.assemblyscript": { "translation": "قالب AssemblyScript" }, diff --git a/src/livecodes/i18n/locales/ar/translation.ts b/src/livecodes/i18n/locales/ar/translation.ts index f5850a8907..b3a1ed9853 100644 --- a/src/livecodes/i18n/locales/ar/translation.ts +++ b/src/livecodes/i18n/locales/ar/translation.ts @@ -977,6 +977,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'قالب Ada (Wasm)', angular: 'قالب Angular', + 'assembly-wasm': 'قالب Assembly (Wasm)', assemblyscript: 'قالب AssemblyScript', astro: 'قالب Astro', backbone: 'قالب Backbone', diff --git a/src/livecodes/i18n/locales/bn/language-info.lokalise.json b/src/livecodes/i18n/locales/bn/language-info.lokalise.json index a00baa7d34..64c4f25dc2 100644 --- a/src/livecodes/i18n/locales/bn/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/bn/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "x86-64 অ্যাসেম্বলি Keystone দ্বারা অ্যাসেম্বল করা হয় এবং Unicorn দ্বারা চালিত হয়, উভয়ই WebAssembly-তে কম্পাইল করা হয় এবং সম্পূর্ণভাবে ব্রাউজারে চলে।" + }, + "assemblyWasm.link": { + "translation": " Keystone অফিসিয়াল ওয়েবসাইট Unicorn অফিসিয়াল ওয়েবসাইট X86 অ্যাসেম্বলি (উইকিবই) লাইভকোডস ডকুমেন্টেশন স্টার্টার টেমপ্লেট লোড করুন " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "WebAssembly-এর জন্য TypeScript-এর মতো একটি ভাষা।" }, diff --git a/src/livecodes/i18n/locales/bn/language-info.ts b/src/livecodes/i18n/locales/bn/language-info.ts index f0e077f321..ae0df20a7f 100644 --- a/src/livecodes/i18n/locales/bn/language-info.ts +++ b/src/livecodes/i18n/locales/bn/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>AsciiDoc অফিসিয়াল ওয়েবসাইট <3> <4>Asciidoctor অফিসিয়াল ওয়েবসাইট <5> <6>Asciidoctor ডকুমেন্টেশন <7> <8>Y মিনিটে X শিখুন, যেখানে X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'x86-64 অ্যাসেম্বলি <1>Keystone দ্বারা অ্যাসেম্বল করা হয় এবং <2>Unicorn দ্বারা চালিত হয়, উভয়ই WebAssembly-তে কম্পাইল করা হয় এবং সম্পূর্ণভাবে ব্রাউজারে চলে।', + link: '<1> <2>Keystone অফিসিয়াল ওয়েবসাইট <3> <4>Unicorn অফিসিয়াল ওয়েবসাইট <5> <6>X86 অ্যাসেম্বলি (উইকিবই) <7> <8>লাইভকোডস ডকুমেন্টেশন <9> <10>স্টার্টার টেমপ্লেট লোড করুন ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'WebAssembly-এর জন্য TypeScript-এর মতো একটি ভাষা।', link: '<1> <2>AssemblyScript অফিসিয়াল ওয়েবসাইট <3> <4>AssemblyScript ডকুমেন্টেশন <5> <6>স্টার্টার টেমপ্লেট লোড করুন ', diff --git a/src/livecodes/i18n/locales/bn/translation.lokalise.json b/src/livecodes/i18n/locales/bn/translation.lokalise.json index 6a5f6bb154..5a2977c506 100644 --- a/src/livecodes/i18n/locales/bn/translation.lokalise.json +++ b/src/livecodes/i18n/locales/bn/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Angular স্টার্টার" }, + "templates.starter.assembly-wasm": { + "translation": "Assembly (Wasm) স্টার্টার" + }, "templates.starter.assemblyscript": { "translation": "AssemblyScript স্টার্টার" }, diff --git a/src/livecodes/i18n/locales/bn/translation.ts b/src/livecodes/i18n/locales/bn/translation.ts index 3e687e4e2a..00143090f9 100644 --- a/src/livecodes/i18n/locales/bn/translation.ts +++ b/src/livecodes/i18n/locales/bn/translation.ts @@ -977,6 +977,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Ada (Wasm) স্টার্টার', angular: 'Angular স্টার্টার', + 'assembly-wasm': 'Assembly (Wasm) স্টার্টার', assemblyscript: 'AssemblyScript স্টার্টার', astro: 'Astro স্টার্টার', backbone: 'Backbone স্টার্টার', diff --git a/src/livecodes/i18n/locales/de/language-info.lokalise.json b/src/livecodes/i18n/locales/de/language-info.lokalise.json index f2d167c930..c2300e23ac 100644 --- a/src/livecodes/i18n/locales/de/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/de/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "x86-64-Assembly wird von Keystone assembliert und von Unicorn ausgeführt; beide sind zu WebAssembly kompiliert und laufen vollständig im Browser." + }, + "assemblyWasm.link": { + "translation": " Offizielle Website von Keystone Offizielle Website von Unicorn X86-Assembly (Wikibooks) LiveCodes-Dokumentation Starter-Vorlage laden " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "Eine TypeScript-ähnliche Sprache für WebAssembly." }, diff --git a/src/livecodes/i18n/locales/de/language-info.ts b/src/livecodes/i18n/locales/de/language-info.ts index 9d3dae2fc7..9dd8c20ae2 100644 --- a/src/livecodes/i18n/locales/de/language-info.ts +++ b/src/livecodes/i18n/locales/de/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>AsciiDoc offizielle Website <3> <4>Asciidoctor offizielle Website <5> <6>Asciidoctor Dokumentation <7> <8>Lerne X in Y Minuten, wobei X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'x86-64-Assembly wird von <1>Keystone assembliert und von <2>Unicorn ausgeführt; beide sind zu WebAssembly kompiliert und laufen vollständig im Browser.', + link: '<1> <2>Offizielle Website von Keystone <3> <4>Offizielle Website von Unicorn <5> <6>X86-Assembly (Wikibooks) <7> <8>LiveCodes-Dokumentation <9> <10>Starter-Vorlage laden ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'Eine TypeScript-ähnliche Sprache für WebAssembly.', link: '<1> <2>AssemblyScript offizielle Website <3> <4>AssemblyScript Dokumentation <5> <6>Starter-Vorlage laden ', diff --git a/src/livecodes/i18n/locales/de/translation.lokalise.json b/src/livecodes/i18n/locales/de/translation.lokalise.json index 3e852bac76..d7328176fa 100644 --- a/src/livecodes/i18n/locales/de/translation.lokalise.json +++ b/src/livecodes/i18n/locales/de/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Angular-Starter" }, + "templates.starter.assembly-wasm": { + "translation": "Assembly (Wasm)-Starter" + }, "templates.starter.assemblyscript": { "translation": "AssemblyScript-Starter" }, diff --git a/src/livecodes/i18n/locales/de/translation.ts b/src/livecodes/i18n/locales/de/translation.ts index 1df12f7cb7..7ddcbb9e51 100644 --- a/src/livecodes/i18n/locales/de/translation.ts +++ b/src/livecodes/i18n/locales/de/translation.ts @@ -979,6 +979,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Ada (Wasm)-Starter', angular: 'Angular-Starter', + 'assembly-wasm': 'Assembly (Wasm)-Starter', assemblyscript: 'AssemblyScript-Starter', astro: 'Astro-Starter', backbone: 'Backbone-Starter', diff --git a/src/livecodes/i18n/locales/en/language-info.lokalise.json b/src/livecodes/i18n/locales/en/language-info.lokalise.json index 5db1650b71..f5011ad020 100644 --- a/src/livecodes/i18n/locales/en/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/en/language-info.lokalise.json @@ -36,6 +36,18 @@ "notes": "", "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "notes": "### ###\n\n\n### ###\n\n\n", + "translation": "x86-64 assembly assembled by Keystone and executed by Unicorn, both compiled to WebAssembly and running entirely in the browser." + }, + "assemblyWasm.link": { + "notes": "### ###\n
  • \n\n### ###\n\n\n### ###\n
  • \n\n### ###\n\n\n### ###\n
  • \n\n### ###\n\n\n### ###\n
  • \n\n### ###\n\n\n### ###\n
  • \n\n### ###\n\n\n", + "translation": " Keystone official website Unicorn official website X86 Assembly (Wikibooks) LiveCodes Documentation Load starter template " + }, + "assemblyWasm.name": { + "notes": "", + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "notes": "", "translation": "A TypeScript-like language for WebAssembly." diff --git a/src/livecodes/i18n/locales/en/language-info.ts b/src/livecodes/i18n/locales/en/language-info.ts index c3bddc3222..4315e876a3 100644 --- a/src/livecodes/i18n/locales/en/language-info.ts +++ b/src/livecodes/i18n/locales/en/language-info.ts @@ -25,6 +25,11 @@ const languageInfo = { link: '<1> <2>AsciiDoc official website <3> <4>Asciidoctor official website <5> <6>Asciidoctor documentation <7> <8>Learn X in Y minutes, where X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'x86-64 assembly assembled by <1>Keystone and executed by <2>Unicorn, both compiled to WebAssembly and running entirely in the browser.', + link: '<1> <2>Keystone official website <3> <4>Unicorn official website <5> <6>X86 Assembly (Wikibooks) <7> <8>LiveCodes Documentation <9> <10>Load starter template ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'A TypeScript-like language for WebAssembly.', link: '<1> <2>AssemblyScript official website <3> <4>AssemblyScript documentation <5> <6>Load starter template ', diff --git a/src/livecodes/i18n/locales/en/translation.lokalise.json b/src/livecodes/i18n/locales/en/translation.lokalise.json index a71d37884b..2a6eb9c881 100644 --- a/src/livecodes/i18n/locales/en/translation.lokalise.json +++ b/src/livecodes/i18n/locales/en/translation.lokalise.json @@ -2552,6 +2552,10 @@ "notes": "", "translation": "Angular Starter" }, + "templates.starter.assembly-wasm": { + "notes": "", + "translation": "Assembly (Wasm) Starter" + }, "templates.starter.assemblyscript": { "notes": "", "translation": "AssemblyScript Starter" diff --git a/src/livecodes/i18n/locales/en/translation.ts b/src/livecodes/i18n/locales/en/translation.ts index 122cc11c0e..747a090e42 100644 --- a/src/livecodes/i18n/locales/en/translation.ts +++ b/src/livecodes/i18n/locales/en/translation.ts @@ -984,6 +984,7 @@ const translation = { starter: { 'ada-wasm': 'Ada (Wasm) Starter', angular: 'Angular Starter', + 'assembly-wasm': 'Assembly (Wasm) Starter', assemblyscript: 'AssemblyScript Starter', astro: 'Astro Starter', backbone: 'Backbone Starter', diff --git a/src/livecodes/i18n/locales/es/language-info.lokalise.json b/src/livecodes/i18n/locales/es/language-info.lokalise.json index 7079f07103..c50938599b 100644 --- a/src/livecodes/i18n/locales/es/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/es/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "El código ensamblador x86-64 se ensambla mediante Keystone y se ejecuta mediante Unicorn, ambos compilados a WebAssembly y ejecutándose íntegramente en el navegador." + }, + "assemblyWasm.link": { + "translation": " Página web oficial de Keystone Página web oficial de Unicorn Ensamblador X86 (Wikibooks) Documentación de LiveCodes Cargar plantilla de inicio " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "Un lenguaje similar a TypeScript para WebAssembly." }, diff --git a/src/livecodes/i18n/locales/es/language-info.ts b/src/livecodes/i18n/locales/es/language-info.ts index 7db4fa255a..e94adaaa34 100644 --- a/src/livecodes/i18n/locales/es/language-info.ts +++ b/src/livecodes/i18n/locales/es/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>Sitio web oficial de AsciiDoc <3> <4>Sitio web oficial de Asciidoctor <5> <6>Documentación de Asciidoctor <7> <8>Aprende X en Y minutos, donde X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'El código ensamblador x86-64 se ensambla mediante <1>Keystone y se ejecuta mediante <2>Unicorn, ambos compilados a WebAssembly y ejecutándose íntegramente en el navegador.', + link: '<1> <2>Página web oficial de Keystone <3> <4>Página web oficial de Unicorn <5> <6>Ensamblador X86 (Wikibooks) <7> <8>Documentación de LiveCodes <9> <10>Cargar plantilla de inicio ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'Un lenguaje similar a TypeScript para WebAssembly.', link: '<1> <2>Sitio web oficial de AssemblyScript <3> <4>Documentación de AssemblyScript <5> <6>Cargar plantilla inicial ', diff --git a/src/livecodes/i18n/locales/es/translation.lokalise.json b/src/livecodes/i18n/locales/es/translation.lokalise.json index 96ce08763d..6f04665844 100644 --- a/src/livecodes/i18n/locales/es/translation.lokalise.json +++ b/src/livecodes/i18n/locales/es/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Inicio Angular" }, + "templates.starter.assembly-wasm": { + "translation": "Inicio Assembly (Wasm)" + }, "templates.starter.assemblyscript": { "translation": "Inicio AssemblyScript" }, diff --git a/src/livecodes/i18n/locales/es/translation.ts b/src/livecodes/i18n/locales/es/translation.ts index 05bb61973e..0a4e249d19 100644 --- a/src/livecodes/i18n/locales/es/translation.ts +++ b/src/livecodes/i18n/locales/es/translation.ts @@ -977,6 +977,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Inicio Ada (Wasm)', angular: 'Inicio Angular', + 'assembly-wasm': 'Inicio Assembly (Wasm)', assemblyscript: 'Inicio AssemblyScript', astro: 'Inicio Astro', backbone: 'Inicio Backbone', diff --git a/src/livecodes/i18n/locales/fa/language-info.lokalise.json b/src/livecodes/i18n/locales/fa/language-info.lokalise.json index e16ffb22aa..694fd8eff2 100644 --- a/src/livecodes/i18n/locales/fa/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/fa/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "اسمبلی x86-64 توسط Keystone اسمبل می‌شود و توسط Unicorn اجرا می‌شود؛ هر دو به WebAssembly کامپایل شده و کاملاً در مرورگر اجرا می‌شوند." + }, + "assemblyWasm.link": { + "translation": " وب‌سایت رسمی Keystone وب‌سایت رسمی Unicorn اسمبلی X86 (ویکی‌کتاب) مستندات لایوکدز بارگذاری قالب شروع " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "یک زبان شبیه به TypeScript برای WebAssembly." }, diff --git a/src/livecodes/i18n/locales/fa/language-info.ts b/src/livecodes/i18n/locales/fa/language-info.ts index d360fb09bc..d3c2a78414 100644 --- a/src/livecodes/i18n/locales/fa/language-info.ts +++ b/src/livecodes/i18n/locales/fa/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>وب‌سایت رسمی AsciiDoc <3> <4>وب‌سایت رسمی Asciidoctor <5> <6>مستندات Asciidoctor <7> <8>یادگیری X در Y دقیقه، جایی که X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'اسمبلی x86-64 توسط <1>Keystone اسمبل می‌شود و توسط <2>Unicorn اجرا می‌شود؛ هر دو به WebAssembly کامپایل شده و کاملاً در مرورگر اجرا می‌شوند.', + link: '<1> <2>وب‌سایت رسمی Keystone <3> <4>وب‌سایت رسمی Unicorn <5> <6>اسمبلی X86 (ویکی‌کتاب) <7> <8>مستندات لایوکدز <9> <10>بارگذاری قالب شروع ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'یک زبان شبیه به TypeScript برای WebAssembly.', link: '<1> <2>وب‌سایت رسمی AssemblyScript <3> <4>مستندات AssemblyScript <5> <6>بارگذاری قالب شروع کننده ', diff --git a/src/livecodes/i18n/locales/fa/translation.lokalise.json b/src/livecodes/i18n/locales/fa/translation.lokalise.json index f1ba2a5c35..50f2f283e4 100644 --- a/src/livecodes/i18n/locales/fa/translation.lokalise.json +++ b/src/livecodes/i18n/locales/fa/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "شروع کننده انگولار" }, + "templates.starter.assembly-wasm": { + "translation": "شروع کننده Assembly (Wasm)" + }, "templates.starter.assemblyscript": { "translation": "شروع کننده AssemblyScript" }, diff --git a/src/livecodes/i18n/locales/fa/translation.ts b/src/livecodes/i18n/locales/fa/translation.ts index 25a2546bc0..8e3d1e7fbf 100644 --- a/src/livecodes/i18n/locales/fa/translation.ts +++ b/src/livecodes/i18n/locales/fa/translation.ts @@ -978,6 +978,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'شروع کننده Ada (Wasm)', angular: 'شروع کننده انگولار', + 'assembly-wasm': 'شروع کننده Assembly (Wasm)', assemblyscript: 'شروع کننده AssemblyScript', astro: 'شروع کننده Astro', backbone: 'شروع کننده Backbone', diff --git a/src/livecodes/i18n/locales/fr/language-info.lokalise.json b/src/livecodes/i18n/locales/fr/language-info.lokalise.json index 070d5efd5f..9df6ba33ad 100644 --- a/src/livecodes/i18n/locales/fr/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/fr/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "Le code assembleur x86-64 est assemblé par Keystone et exécuté par Unicorn, tous deux compilés en WebAssembly et s'exécutant entièrement dans le navigateur." + }, + "assemblyWasm.link": { + "translation": " Site officiel de Keystone Site officiel d'Unicorn Assembleur X86 (Wikibooks) Documentation LiveCodes Charger un modèle de démarrage " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "Un langage similaire à TypeScript pour WebAssembly." }, diff --git a/src/livecodes/i18n/locales/fr/language-info.ts b/src/livecodes/i18n/locales/fr/language-info.ts index 5720cbac93..9a6469fd01 100644 --- a/src/livecodes/i18n/locales/fr/language-info.ts +++ b/src/livecodes/i18n/locales/fr/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: "<1> <2>Site officiel d'AsciiDoc <3> <4>Site officiel d'Asciidoctor <5> <6>Documentation d'Asciidoctor <7> <8>Apprenez X en Y minutes, où X=asciidoc ", name: 'AsciiDoc', }, + assemblyWasm: { + desc: "Le code assembleur x86-64 est assemblé par <1>Keystone et exécuté par <2>Unicorn, tous deux compilés en WebAssembly et s'exécutant entièrement dans le navigateur.", + link: "<1> <2>Site officiel de Keystone <3> <4>Site officiel d'Unicorn <5> <6>Assembleur X86 (Wikibooks) <7> <8>Documentation LiveCodes <9> <10>Charger un modèle de démarrage ", + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'Un langage similaire à TypeScript pour WebAssembly.', link: "<1> <2>Site officiel d'AssemblyScript <3> <4>Documentation d'AssemblyScript <5> <6>Charger le modèle de démarrage ", diff --git a/src/livecodes/i18n/locales/fr/translation.lokalise.json b/src/livecodes/i18n/locales/fr/translation.lokalise.json index 99ab92313e..3c9ae859fd 100644 --- a/src/livecodes/i18n/locales/fr/translation.lokalise.json +++ b/src/livecodes/i18n/locales/fr/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Démarrage Angular" }, + "templates.starter.assembly-wasm": { + "translation": "Démarrage Assembly (Wasm)" + }, "templates.starter.assemblyscript": { "translation": "Démarrage AssemblyScript" }, diff --git a/src/livecodes/i18n/locales/fr/translation.ts b/src/livecodes/i18n/locales/fr/translation.ts index e9313af30b..4c755179c7 100644 --- a/src/livecodes/i18n/locales/fr/translation.ts +++ b/src/livecodes/i18n/locales/fr/translation.ts @@ -979,6 +979,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Démarrage Ada (Wasm)', angular: 'Démarrage Angular', + 'assembly-wasm': 'Démarrage Assembly (Wasm)', assemblyscript: 'Démarrage AssemblyScript', astro: 'Démarrage Astro', backbone: 'Démarrage Backbone', diff --git a/src/livecodes/i18n/locales/hi/language-info.lokalise.json b/src/livecodes/i18n/locales/hi/language-info.lokalise.json index bce912676e..98246a1fe0 100644 --- a/src/livecodes/i18n/locales/hi/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/hi/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "x86-64 असेंबली को Keystone द्वारा असेंबल किया जाता है और Unicorn द्वारा निष्पादित किया जाता है, दोनों को WebAssembly में संकलित किया जाता है और पूरी तरह से ब्राउज़र में चलाया जाता है।" + }, + "assemblyWasm.link": { + "translation": " Keystone आधिकारिक वेबसाइट Unicorn आधिकारिक वेबसाइट X86 असेंबली (विकिबुक्स) लाइवकोड्स दस्तावेज़ीकरण स्टार्टर टेम्पलेट लोड करें " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "WebAssembly के लिए TypeScript जैसी भाषा।" }, diff --git a/src/livecodes/i18n/locales/hi/language-info.ts b/src/livecodes/i18n/locales/hi/language-info.ts index 2094b7d8d8..d647bad026 100644 --- a/src/livecodes/i18n/locales/hi/language-info.ts +++ b/src/livecodes/i18n/locales/hi/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>AsciiDoc आधिकारिक वेबसाइट <3> <4>Asciidoctor आधिकारिक वेबसाइट <5> <6>Asciidoctor दस्तावेज़ीकरण <7> <8>X को Y मिनटों में सीखें, जहां X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'x86-64 असेंबली को <1>Keystone द्वारा असेंबल किया जाता है और <2>Unicorn द्वारा निष्पादित किया जाता है, दोनों को WebAssembly में संकलित किया जाता है और पूरी तरह से ब्राउज़र में चलाया जाता है।', + link: '<1> <2>Keystone आधिकारिक वेबसाइट <3> <4>Unicorn आधिकारिक वेबसाइट <5> <6>X86 असेंबली (विकिबुक्स) <7> <8>लाइवकोड्स दस्तावेज़ीकरण <9> <10>स्टार्टर टेम्पलेट लोड करें ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'WebAssembly के लिए TypeScript जैसी भाषा।', link: '<1> <2>AssemblyScript आधिकारिक वेबसाइट <3> <4>AssemblyScript दस्तावेज़ीकरण <5> <6>स्टार्टर टेम्पलेट लोड करें ', diff --git a/src/livecodes/i18n/locales/hi/translation.lokalise.json b/src/livecodes/i18n/locales/hi/translation.lokalise.json index 2231e31456..d81fc34e0a 100644 --- a/src/livecodes/i18n/locales/hi/translation.lokalise.json +++ b/src/livecodes/i18n/locales/hi/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Angular स्टार्टर" }, + "templates.starter.assembly-wasm": { + "translation": "Assembly (Wasm) स्टार्टर" + }, "templates.starter.assemblyscript": { "translation": "AssemblyScript स्टार्टर" }, diff --git a/src/livecodes/i18n/locales/hi/translation.ts b/src/livecodes/i18n/locales/hi/translation.ts index edba0eb9a4..66520c90b8 100644 --- a/src/livecodes/i18n/locales/hi/translation.ts +++ b/src/livecodes/i18n/locales/hi/translation.ts @@ -977,6 +977,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Ada (Wasm) स्टार्टर', angular: 'Angular स्टार्टर', + 'assembly-wasm': 'Assembly (Wasm) स्टार्टर', assemblyscript: 'AssemblyScript स्टार्टर', astro: 'Astro स्टार्टर', backbone: 'Backbone स्टार्टर', diff --git a/src/livecodes/i18n/locales/hu/language-info.lokalise.json b/src/livecodes/i18n/locales/hu/language-info.lokalise.json index 42ae79553b..391304fef1 100644 --- a/src/livecodes/i18n/locales/hu/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/hu/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "Az x86-64 assembly-t a Keystone állítja össze és az Unicorn hajtja végre; mindkettő WebAssembly-re van fordítva, és teljes egészében a böngészőben fut." + }, + "assemblyWasm.link": { + "translation": " A Keystone hivatalos weboldala Az Unicorn hivatalos weboldala X86 assembly (Wikibooks) LiveCodes dokumentáció Indító sablon betöltése " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "TypeScript-szerű nyelv WebAssembly-hez." }, diff --git a/src/livecodes/i18n/locales/hu/language-info.ts b/src/livecodes/i18n/locales/hu/language-info.ts index 4c8674eb98..303d6fcca6 100644 --- a/src/livecodes/i18n/locales/hu/language-info.ts +++ b/src/livecodes/i18n/locales/hu/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>AsciiDoc hivatalos weboldal <3> <4>Asciidoctor hivatalos weboldal <5> <6>Asciidoctor dokumentáció <7> <8>Tanulj X-et Y perc alatt, ahol X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'Az x86-64 assembly-t a <1>Keystone állítja össze és az <2>Unicorn hajtja végre; mindkettő WebAssembly-re van fordítva, és teljes egészében a böngészőben fut.', + link: '<1> <2>A Keystone hivatalos weboldala <3> <4>Az Unicorn hivatalos weboldala <5> <6>X86 assembly (Wikibooks) <7> <8>LiveCodes dokumentáció <9> <10>Indító sablon betöltése ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'TypeScript-szerű nyelv WebAssembly-hez.', link: '<1> <2>AssemblyScript hivatalos weboldal <3> <4>AssemblyScript dokumentáció <5> <6>Kezdő sablon betöltése ', diff --git a/src/livecodes/i18n/locales/hu/translation.lokalise.json b/src/livecodes/i18n/locales/hu/translation.lokalise.json index 98d100676c..6a3364c1d3 100644 --- a/src/livecodes/i18n/locales/hu/translation.lokalise.json +++ b/src/livecodes/i18n/locales/hu/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Angular kezdő" }, + "templates.starter.assembly-wasm": { + "translation": "Assembly (Wasm) kezdő" + }, "templates.starter.assemblyscript": { "translation": "AssemblyScript kezdő" }, diff --git a/src/livecodes/i18n/locales/hu/translation.ts b/src/livecodes/i18n/locales/hu/translation.ts index 5b9629efa8..0aeb141498 100644 --- a/src/livecodes/i18n/locales/hu/translation.ts +++ b/src/livecodes/i18n/locales/hu/translation.ts @@ -978,6 +978,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Ada (Wasm) kezdő', angular: 'Angular kezdő', + 'assembly-wasm': 'Assembly (Wasm) kezdő', assemblyscript: 'AssemblyScript kezdő', astro: 'Astro kezdő', backbone: 'Backbone kezdő', diff --git a/src/livecodes/i18n/locales/id/language-info.lokalise.json b/src/livecodes/i18n/locales/id/language-info.lokalise.json index de3ab82699..6b37b8bf0c 100644 --- a/src/livecodes/i18n/locales/id/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/id/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "Assembly x86-64 dirakit oleh Keystone dan dijalankan oleh Unicorn, keduanya dikompilasi ke WebAssembly dan dijalankan sepenuhnya di dalam browser." + }, + "assemblyWasm.link": { + "translation": " Situs web resmi Keystone Situs web resmi Unicorn Assembly X86 (Wikibooks) Dokumentasi LiveCodes Muat templat awal " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "Bahasa seperti TypeScript untuk WebAssembly." }, diff --git a/src/livecodes/i18n/locales/id/language-info.ts b/src/livecodes/i18n/locales/id/language-info.ts index 09729fe896..e0132ccb91 100644 --- a/src/livecodes/i18n/locales/id/language-info.ts +++ b/src/livecodes/i18n/locales/id/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>Situs web resmi AsciiDoc <3> <4>Situs web resmi Asciidoctor <5> <6>Dokumentasi Asciidoctor <7> <8>Pelajari X dalam Y menit, dengan X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'Assembly x86-64 dirakit oleh <1>Keystone dan dijalankan oleh <2>Unicorn, keduanya dikompilasi ke WebAssembly dan dijalankan sepenuhnya di dalam browser.', + link: '<1> <2>Situs web resmi Keystone <3> <4>Situs web resmi Unicorn <5> <6>Assembly X86 (Wikibooks) <7> <8>Dokumentasi LiveCodes <9> <10>Muat templat awal ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'Bahasa seperti TypeScript untuk WebAssembly.', link: '<1> <2>Situs web resmi AssemblyScript <3> <4>Dokumentasi AssemblyScript <5> <6>Muat template pemula ', diff --git a/src/livecodes/i18n/locales/id/translation.lokalise.json b/src/livecodes/i18n/locales/id/translation.lokalise.json index c72cfa7e22..69e8f87aaf 100644 --- a/src/livecodes/i18n/locales/id/translation.lokalise.json +++ b/src/livecodes/i18n/locales/id/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Pemula Angular" }, + "templates.starter.assembly-wasm": { + "translation": "Pemula Assembly (Wasm)" + }, "templates.starter.assemblyscript": { "translation": "Pemula AssemblyScript" }, diff --git a/src/livecodes/i18n/locales/id/translation.ts b/src/livecodes/i18n/locales/id/translation.ts index ef255caf7f..95e06641a4 100644 --- a/src/livecodes/i18n/locales/id/translation.ts +++ b/src/livecodes/i18n/locales/id/translation.ts @@ -977,6 +977,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Pemula Ada (Wasm)', angular: 'Pemula Angular', + 'assembly-wasm': 'Pemula Assembly (Wasm)', assemblyscript: 'Pemula AssemblyScript', astro: 'Pemula Astro', backbone: 'Pemula Backbone', diff --git a/src/livecodes/i18n/locales/it/language-info.lokalise.json b/src/livecodes/i18n/locales/it/language-info.lokalise.json index ed07ca73cb..a1739a5d64 100644 --- a/src/livecodes/i18n/locales/it/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/it/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "L'assembly x86-64 viene assemblato da Keystone ed eseguito da Unicorn, entrambi compilati in WebAssembly ed eseguiti interamente nel browser." + }, + "assemblyWasm.link": { + "translation": " Sito web ufficiale di Keystone Sito web ufficiale di Unicorn Assembly X86 (Wikibooks) Documentazione di LiveCodes Carica il modello di partenza " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "Un linguaggio simile a TypeScript per WebAssembly." }, diff --git a/src/livecodes/i18n/locales/it/language-info.ts b/src/livecodes/i18n/locales/it/language-info.ts index b140707bae..234af4ecc3 100644 --- a/src/livecodes/i18n/locales/it/language-info.ts +++ b/src/livecodes/i18n/locales/it/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>Sito ufficiale di AsciiDoc <3> <4>Sito ufficiale di Asciidoctor <5> <6>Documentazione di Asciidoctor <7> <8>Impara X in Y minuti, dove X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: "L'assembly x86-64 viene assemblato da <1>Keystone ed eseguito da <2>Unicorn, entrambi compilati in WebAssembly ed eseguiti interamente nel browser.", + link: '<1> <2>Sito web ufficiale di Keystone <3> <4>Sito web ufficiale di Unicorn <5> <6>Assembly X86 (Wikibooks) <7> <8>Documentazione di LiveCodes <9> <10>Carica il modello di partenza ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'Un linguaggio simile a TypeScript per WebAssembly.', link: '<1> <2>Sito ufficiale di AssemblyScript <3> <4>Documentazione di AssemblyScript <5> <6>Carica il modello di partenza ', diff --git a/src/livecodes/i18n/locales/it/translation.lokalise.json b/src/livecodes/i18n/locales/it/translation.lokalise.json index ad7d655938..f7e259999a 100644 --- a/src/livecodes/i18n/locales/it/translation.lokalise.json +++ b/src/livecodes/i18n/locales/it/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Starter Angular" }, + "templates.starter.assembly-wasm": { + "translation": "Starter Assembly (Wasm)" + }, "templates.starter.assemblyscript": { "translation": "Starter AssemblyScript" }, diff --git a/src/livecodes/i18n/locales/it/translation.ts b/src/livecodes/i18n/locales/it/translation.ts index cbf90a73bf..0358572363 100644 --- a/src/livecodes/i18n/locales/it/translation.ts +++ b/src/livecodes/i18n/locales/it/translation.ts @@ -978,6 +978,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Starter Ada (Wasm)', angular: 'Starter Angular', + 'assembly-wasm': 'Starter Assembly (Wasm)', assemblyscript: 'Starter AssemblyScript', astro: 'Starter Astro', backbone: 'Starter Backbone', diff --git a/src/livecodes/i18n/locales/ja/language-info.lokalise.json b/src/livecodes/i18n/locales/ja/language-info.lokalise.json index 0aabae175e..ab663ecb8a 100644 --- a/src/livecodes/i18n/locales/ja/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/ja/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "x86-64 アセンブリは Keystone によってアセンブルされ、Unicorn によって実行されます。どちらも WebAssembly にコンパイルされ、完全にブラウザ内で動作します。" + }, + "assemblyWasm.link": { + "translation": " Keystone 公式サイト Unicorn 公式サイト X86 アセンブリ(Wikibooks) LiveCodes ドキュメント スターターテンプレートを読み込む " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "WebAssembly 用の TypeScript に似た言語。" }, diff --git a/src/livecodes/i18n/locales/ja/language-info.ts b/src/livecodes/i18n/locales/ja/language-info.ts index 2f7d88d67a..d98b215e23 100644 --- a/src/livecodes/i18n/locales/ja/language-info.ts +++ b/src/livecodes/i18n/locales/ja/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>AsciiDoc 公式ウェブサイト <3> <4>Asciidoctor 公式ウェブサイト <5> <6>Asciidoctor ドキュメント <7> <8>X分でYを学ぶ、X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'x86-64 アセンブリは <1>Keystone によってアセンブルされ、<2>Unicorn によって実行されます。どちらも WebAssembly にコンパイルされ、完全にブラウザ内で動作します。', + link: '<1> <2>Keystone 公式サイト <3> <4>Unicorn 公式サイト <5> <6>X86 アセンブリ(Wikibooks) <7> <8>LiveCodes ドキュメント <9> <10>スターターテンプレートを読み込む ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'WebAssembly 用の TypeScript に似た言語。', link: '<1> <2>AssemblyScript 公式ウェブサイト <3> <4>AssemblyScript ドキュメント <5> <6>スターターテンプレートを読み込む ', diff --git a/src/livecodes/i18n/locales/ja/translation.lokalise.json b/src/livecodes/i18n/locales/ja/translation.lokalise.json index 50769d050b..ed3507a305 100644 --- a/src/livecodes/i18n/locales/ja/translation.lokalise.json +++ b/src/livecodes/i18n/locales/ja/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Angularスターター" }, + "templates.starter.assembly-wasm": { + "translation": "Assembly(Wasm)スターター" + }, "templates.starter.assemblyscript": { "translation": "AssemblyScriptスターター" }, diff --git a/src/livecodes/i18n/locales/ja/translation.ts b/src/livecodes/i18n/locales/ja/translation.ts index ab76fc8009..cc63e6d7eb 100644 --- a/src/livecodes/i18n/locales/ja/translation.ts +++ b/src/livecodes/i18n/locales/ja/translation.ts @@ -978,6 +978,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Ada(Wasm)スターター', angular: 'Angularスターター', + 'assembly-wasm': 'Assembly(Wasm)スターター', assemblyscript: 'AssemblyScriptスターター', astro: 'Astroスターター', backbone: 'Backboneスターター', diff --git a/src/livecodes/i18n/locales/nl/language-info.lokalise.json b/src/livecodes/i18n/locales/nl/language-info.lokalise.json index c1c023a598..8c3055253e 100644 --- a/src/livecodes/i18n/locales/nl/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/nl/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "x86-64-assembly wordt geassembleerd door Keystone en uitgevoerd door Unicorn, beide gecompileerd naar WebAssembly en draaien volledig in de browser." + }, + "assemblyWasm.link": { + "translation": " Officiële website van Keystone Officiële website van Unicorn X86-assembly (Wikibooks) LiveCodes-documentatie Starterssjabloon laden " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "Een TypeScript-achtige taal voor WebAssembly." }, diff --git a/src/livecodes/i18n/locales/nl/language-info.ts b/src/livecodes/i18n/locales/nl/language-info.ts index 4f2c590baa..f0f6aba81e 100644 --- a/src/livecodes/i18n/locales/nl/language-info.ts +++ b/src/livecodes/i18n/locales/nl/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>AsciiDoc officiële website <3> <4>Asciidoctor officiële website <5> <6>Asciidoctor documentatie <7> <8>Leer X in Y minuten, waarbij X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'x86-64-assembly wordt geassembleerd door <1>Keystone en uitgevoerd door <2>Unicorn, beide gecompileerd naar WebAssembly en draaien volledig in de browser.', + link: '<1> <2>Officiële website van Keystone <3> <4>Officiële website van Unicorn <5> <6>X86-assembly (Wikibooks) <7> <8>LiveCodes-documentatie <9> <10>Starterssjabloon laden ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'Een TypeScript-achtige taal voor WebAssembly.', link: '<1> <2>AssemblyScript officiële website <3> <4>AssemblyScript documentatie <5> <6>Startsjabloon laden ', diff --git a/src/livecodes/i18n/locales/nl/translation.lokalise.json b/src/livecodes/i18n/locales/nl/translation.lokalise.json index 36a6391edd..e3c5513aca 100644 --- a/src/livecodes/i18n/locales/nl/translation.lokalise.json +++ b/src/livecodes/i18n/locales/nl/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Angular-starter" }, + "templates.starter.assembly-wasm": { + "translation": "Assembly (Wasm)-starter" + }, "templates.starter.assemblyscript": { "translation": "AssemblyScript-starter" }, diff --git a/src/livecodes/i18n/locales/nl/translation.ts b/src/livecodes/i18n/locales/nl/translation.ts index 0a2241555e..762d4b36ef 100644 --- a/src/livecodes/i18n/locales/nl/translation.ts +++ b/src/livecodes/i18n/locales/nl/translation.ts @@ -978,6 +978,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Ada (Wasm)-starter', angular: 'Angular-starter', + 'assembly-wasm': 'Assembly (Wasm)-starter', assemblyscript: 'AssemblyScript-starter', astro: 'Astro-starter', backbone: 'Backbone-starter', diff --git a/src/livecodes/i18n/locales/pt/language-info.lokalise.json b/src/livecodes/i18n/locales/pt/language-info.lokalise.json index 290c3cb799..24e1a64883 100644 --- a/src/livecodes/i18n/locales/pt/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/pt/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "O código assembly x86-64 é montado pelo Keystone e executado pelo Unicorn, ambos compilados para WebAssembly e executados na íntegra no navegador." + }, + "assemblyWasm.link": { + "translation": " Site oficial do Keystone Site oficial do Unicorn Assembly X86 (Wikibooks) Documentação do LiveCodes Carregar modelo inicial " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "Uma linguagem semelhante ao TypeScript para WebAssembly." }, diff --git a/src/livecodes/i18n/locales/pt/language-info.ts b/src/livecodes/i18n/locales/pt/language-info.ts index 6933f3ad5b..2f261bc6ad 100644 --- a/src/livecodes/i18n/locales/pt/language-info.ts +++ b/src/livecodes/i18n/locales/pt/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>Site oficial do AsciiDoc <3> <4>Site oficial do Asciidoctor <5> <6>Documentação do Asciidoctor <7> <8>Aprenda X em Y minutos, onde X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'O código assembly x86-64 é montado pelo <1>Keystone e executado pelo <2>Unicorn, ambos compilados para WebAssembly e executados na íntegra no navegador.', + link: '<1> <2>Site oficial do Keystone <3> <4>Site oficial do Unicorn <5> <6>Assembly X86 (Wikibooks) <7> <8>Documentação do LiveCodes <9> <10>Carregar modelo inicial ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'Uma linguagem semelhante ao TypeScript para WebAssembly.', link: '<1> <2>Site oficial do AssemblyScript <3> <4>Documentação do AssemblyScript <5> <6>Carregar modelo inicial ', diff --git a/src/livecodes/i18n/locales/pt/translation.lokalise.json b/src/livecodes/i18n/locales/pt/translation.lokalise.json index d7e8b93092..3e79d9e4f9 100644 --- a/src/livecodes/i18n/locales/pt/translation.lokalise.json +++ b/src/livecodes/i18n/locales/pt/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Iniciante Angular" }, + "templates.starter.assembly-wasm": { + "translation": "Iniciante Assembly (Wasm)" + }, "templates.starter.assemblyscript": { "translation": "Iniciante AssemblyScript" }, diff --git a/src/livecodes/i18n/locales/pt/translation.ts b/src/livecodes/i18n/locales/pt/translation.ts index c23ab654e1..f62e9b413a 100644 --- a/src/livecodes/i18n/locales/pt/translation.ts +++ b/src/livecodes/i18n/locales/pt/translation.ts @@ -978,6 +978,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Iniciante Ada (Wasm)', angular: 'Iniciante Angular', + 'assembly-wasm': 'Iniciante Assembly (Wasm)', assemblyscript: 'Iniciante AssemblyScript', astro: 'Iniciante Astro', backbone: 'Iniciante Backbone', diff --git a/src/livecodes/i18n/locales/ru/language-info.lokalise.json b/src/livecodes/i18n/locales/ru/language-info.lokalise.json index 0cef7fe3d8..4165231bb9 100644 --- a/src/livecodes/i18n/locales/ru/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/ru/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "Ассемблерный код x86-64 собирается с помощью Keystone и выполняется с помощью Unicorn, оба скомпилированы в WebAssembly и работают полностью в браузере." + }, + "assemblyWasm.link": { + "translation": " Официальный сайт Keystone Официальный сайт Unicorn Ассемблер X86 (Wikibooks) Документация LiveCodes Загрузить стартовый шаблон " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "Язык, подобный TypeScript, для WebAssembly." }, diff --git a/src/livecodes/i18n/locales/ru/language-info.ts b/src/livecodes/i18n/locales/ru/language-info.ts index 6b189fd2d4..55bb228a4c 100644 --- a/src/livecodes/i18n/locales/ru/language-info.ts +++ b/src/livecodes/i18n/locales/ru/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>Официальный сайт AsciiDoc <3> <4>Официальный сайт Asciidoctor <5> <6>Документация Asciidoctor <7> <8>Изучите X за Y минут, где X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'Ассемблерный код x86-64 собирается с помощью <1>Keystone и выполняется с помощью <2>Unicorn, оба скомпилированы в WebAssembly и работают полностью в браузере.', + link: '<1> <2>Официальный сайт Keystone <3> <4>Официальный сайт Unicorn <5> <6>Ассемблер X86 (Wikibooks) <7> <8>Документация LiveCodes <9> <10>Загрузить стартовый шаблон ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'Язык, подобный TypeScript, для WebAssembly.', link: '<1> <2>Официальный сайт AssemblyScript <3> <4>Документация AssemblyScript <5> <6>Загрузить стартовый шаблон ', diff --git a/src/livecodes/i18n/locales/ru/translation.lokalise.json b/src/livecodes/i18n/locales/ru/translation.lokalise.json index 549d74a7f8..9f48b67701 100644 --- a/src/livecodes/i18n/locales/ru/translation.lokalise.json +++ b/src/livecodes/i18n/locales/ru/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Стартер Angular" }, + "templates.starter.assembly-wasm": { + "translation": "Стартер Assembly (Wasm)" + }, "templates.starter.assemblyscript": { "translation": "Стартер AssemblyScript" }, diff --git a/src/livecodes/i18n/locales/ru/translation.ts b/src/livecodes/i18n/locales/ru/translation.ts index 307c978e6e..2836e79de6 100644 --- a/src/livecodes/i18n/locales/ru/translation.ts +++ b/src/livecodes/i18n/locales/ru/translation.ts @@ -977,6 +977,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Стартер Ada (Wasm)', angular: 'Стартер Angular', + 'assembly-wasm': 'Стартер Assembly (Wasm)', assemblyscript: 'Стартер AssemblyScript', astro: 'Стартер Astro', backbone: 'Стартер Backbone', diff --git a/src/livecodes/i18n/locales/tr/language-info.lokalise.json b/src/livecodes/i18n/locales/tr/language-info.lokalise.json index f326d8aa2f..8d0dfb505b 100644 --- a/src/livecodes/i18n/locales/tr/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/tr/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "x86-64 assembly kodu Keystone tarafından derlenir ve Unicorn tarafından yürütülür; her ikisi de WebAssembly’ye derlenir ve tamamen tarayıcı içinde çalışır." + }, + "assemblyWasm.link": { + "translation": " Keystone resmi web sitesi Unicorn resmi web sitesi X86 Assembly (Wikibooks) LiveCodes Belgeleri Başlangıç şablonunu yükle " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "WebAssembly için TypeScript benzeri bir dil." }, diff --git a/src/livecodes/i18n/locales/tr/language-info.ts b/src/livecodes/i18n/locales/tr/language-info.ts index 1942c15793..4ac3888403 100644 --- a/src/livecodes/i18n/locales/tr/language-info.ts +++ b/src/livecodes/i18n/locales/tr/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>AsciiDoc resmi web sitesi <3> <4>Asciidoctor resmi web sitesi <5> <6>Asciidoctor dokümantasyonu <7> <8>Y Dakikada X Öğrenin, X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'x86-64 assembly kodu <1>Keystone tarafından derlenir ve <2>Unicorn tarafından yürütülür; her ikisi de WebAssembly’ye derlenir ve tamamen tarayıcı içinde çalışır.', + link: '<1> <2>Keystone resmi web sitesi <3> <4>Unicorn resmi web sitesi <5> <6>X86 Assembly (Wikibooks) <7> <8>LiveCodes Belgeleri <9> <10>Başlangıç şablonunu yükle ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'WebAssembly için TypeScript benzeri bir dil.', link: '<1> <2>AssemblyScript resmi web sitesi <3> <4>AssemblyScript dokümantasyonu <5> <6>Başlangıç şablonunu yükle ', diff --git a/src/livecodes/i18n/locales/tr/translation.lokalise.json b/src/livecodes/i18n/locales/tr/translation.lokalise.json index 157cab32f4..1e27dd6857 100644 --- a/src/livecodes/i18n/locales/tr/translation.lokalise.json +++ b/src/livecodes/i18n/locales/tr/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Angular Başlangıç" }, + "templates.starter.assembly-wasm": { + "translation": "Assembly (Wasm) Başlangıç" + }, "templates.starter.assemblyscript": { "translation": "AssemblyScript Başlangıç" }, diff --git a/src/livecodes/i18n/locales/tr/translation.ts b/src/livecodes/i18n/locales/tr/translation.ts index 822b77f928..53150fdfd6 100644 --- a/src/livecodes/i18n/locales/tr/translation.ts +++ b/src/livecodes/i18n/locales/tr/translation.ts @@ -978,6 +978,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Ada (Wasm) Başlangıç', angular: 'Angular Başlangıç', + 'assembly-wasm': 'Assembly (Wasm) Başlangıç', assemblyscript: 'AssemblyScript Başlangıç', astro: 'Astro Başlangıç', backbone: 'Backbone Başlangıç', diff --git a/src/livecodes/i18n/locales/ur/language-info.lokalise.json b/src/livecodes/i18n/locales/ur/language-info.lokalise.json index a3a84ff70e..31c9125847 100644 --- a/src/livecodes/i18n/locales/ur/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/ur/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "ایسکی ڈاک" }, + "assemblyWasm.desc": { + "translation": "x86-64 اسمبلی Keystone کے ذریعے اسمبل کی جاتی ہے اور Unicorn کے ذریعے چلائی جاتی ہے، دونوں WebAssembly میں مرتب کیے گئے ہیں اور مکمل طور پر براؤزر میں چلتے ہیں۔" + }, + "assemblyWasm.link": { + "translation": " Keystone آفیشل ویب سائٹ Unicorn آفیشل ویب سائٹ X86 اسمبلی (ویکی کتب) لائیو کوڈز دستاویزات ابتدائی سانچہ لوڈ کریں " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "ویب اسمبلی کے لیے ٹائپ اسکرپٹ جیسی زبان۔" }, diff --git a/src/livecodes/i18n/locales/ur/language-info.ts b/src/livecodes/i18n/locales/ur/language-info.ts index 3c4f6d8e0e..13d630c56b 100644 --- a/src/livecodes/i18n/locales/ur/language-info.ts +++ b/src/livecodes/i18n/locales/ur/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>ایسکی ڈاک کی سرکاری ویب سائٹ <3> <4>ایسکی ڈاکٹر کی سرکاری ویب سائٹ <5> <6>ایسکی ڈاکٹر کی دستاویزات <7> <8>X کو Y منٹ میں سیکھیں، جہاں X = ایسکی ڈاک ', name: 'ایسکی ڈاک', }, + assemblyWasm: { + desc: 'x86-64 اسمبلی <1>Keystone کے ذریعے اسمبل کی جاتی ہے اور <2>Unicorn کے ذریعے چلائی جاتی ہے، دونوں WebAssembly میں مرتب کیے گئے ہیں اور مکمل طور پر براؤزر میں چلتے ہیں۔', + link: '<1> <2>Keystone آفیشل ویب سائٹ <3> <4>Unicorn آفیشل ویب سائٹ <5> <6>X86 اسمبلی (ویکی کتب) <7> <8>لائیو کوڈز دستاویزات <9> <10>ابتدائی سانچہ لوڈ کریں ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: 'ویب اسمبلی کے لیے ٹائپ اسکرپٹ جیسی زبان۔', link: '<1> <2>اسمبلی اسکرپٹ کی سرکاری ویب سائٹ <3> <4>اسمبلی اسکرپٹ کی دستاویزات <5> <6>ابتدائی سانچہ لوڈ کریں ', diff --git a/src/livecodes/i18n/locales/ur/translation.lokalise.json b/src/livecodes/i18n/locales/ur/translation.lokalise.json index 199dbf0648..afd752a9fc 100644 --- a/src/livecodes/i18n/locales/ur/translation.lokalise.json +++ b/src/livecodes/i18n/locales/ur/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "اینگولر شروعاتی" }, + "templates.starter.assembly-wasm": { + "translation": "اسمبلی (واسم) شروعاتی" + }, "templates.starter.assemblyscript": { "translation": "اسمبلی اسکرپٹ شروعاتی" }, diff --git a/src/livecodes/i18n/locales/ur/translation.ts b/src/livecodes/i18n/locales/ur/translation.ts index b459e186c4..3626affbca 100644 --- a/src/livecodes/i18n/locales/ur/translation.ts +++ b/src/livecodes/i18n/locales/ur/translation.ts @@ -977,6 +977,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Ada (واسم) شروعاتی', angular: 'اینگولر شروعاتی', + 'assembly-wasm': 'اسمبلی (واسم) شروعاتی', assemblyscript: 'اسمبلی اسکرپٹ شروعاتی', astro: 'ایسٹرو شروعاتی', backbone: 'بیک بون شروعاتی', diff --git a/src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json b/src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json index f0709416d2..75e3cc94d4 100644 --- a/src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json @@ -27,6 +27,15 @@ "asciidoc.name": { "translation": "AsciiDoc" }, + "assemblyWasm.desc": { + "translation": "x86-64 汇编由 Keystone 汇编,并由 Unicorn 执行,二者均编译为 WebAssembly 并完全在浏览器中运行。" + }, + "assemblyWasm.link": { + "translation": " Keystone 官方网站 Unicorn 官方网站 X86 汇编(Wikibooks) LiveCodes 文档 加载入门模板 " + }, + "assemblyWasm.name": { + "translation": "Assembly (Wasm)" + }, "assemblyscript.desc": { "translation": "一种类似于 TypeScript 的 WebAssembly 语言。" }, diff --git a/src/livecodes/i18n/locales/zh-CN/language-info.ts b/src/livecodes/i18n/locales/zh-CN/language-info.ts index 3da244a757..7a0599b0ad 100644 --- a/src/livecodes/i18n/locales/zh-CN/language-info.ts +++ b/src/livecodes/i18n/locales/zh-CN/language-info.ts @@ -18,6 +18,11 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1> <2>AsciiDoc 官方网站 <3> <4>Asciidoctor 官方网站 <5> <6>Asciidoctor 文档 <7> <8>在 Y 分钟内学习 X,其中 X=asciidoc ', name: 'AsciiDoc', }, + assemblyWasm: { + desc: 'x86-64 汇编由 <1>Keystone 汇编,并由 <2>Unicorn 执行,二者均编译为 WebAssembly 并完全在浏览器中运行。', + link: '<1> <2>Keystone 官方网站 <3> <4>Unicorn 官方网站 <5> <6>X86 汇编(Wikibooks) <7> <8>LiveCodes 文档 <9> <10>加载入门模板 ', + name: 'Assembly (Wasm)', + }, assemblyscript: { desc: '一种类似于 TypeScript 的 WebAssembly 语言。', link: '<1> <2>AssemblyScript 官方网站 <3> <4>AssemblyScript 文档 <5> <6>加载启动模板 ', diff --git a/src/livecodes/i18n/locales/zh-CN/translation.lokalise.json b/src/livecodes/i18n/locales/zh-CN/translation.lokalise.json index 8f275b7779..07b4f929b8 100644 --- a/src/livecodes/i18n/locales/zh-CN/translation.lokalise.json +++ b/src/livecodes/i18n/locales/zh-CN/translation.lokalise.json @@ -1914,6 +1914,9 @@ "templates.starter.angular": { "translation": "Angular 启动模板" }, + "templates.starter.assembly-wasm": { + "translation": "Assembly(Wasm)启动模板" + }, "templates.starter.assemblyscript": { "translation": "AssemblyScript 启动模板" }, diff --git a/src/livecodes/i18n/locales/zh-CN/translation.ts b/src/livecodes/i18n/locales/zh-CN/translation.ts index 11c6918b95..efe5773dd6 100644 --- a/src/livecodes/i18n/locales/zh-CN/translation.ts +++ b/src/livecodes/i18n/locales/zh-CN/translation.ts @@ -975,6 +975,7 @@ const translation: I18nTranslation = { starter: { 'ada-wasm': 'Ada(WASM)启动模板', angular: 'Angular 启动模板', + 'assembly-wasm': 'Assembly(Wasm)启动模板', assemblyscript: 'AssemblyScript 启动模板', astro: 'Astro 启动模板', backbone: 'Backbone 启动模板', diff --git a/src/livecodes/languages/assembly-wasm/__tests__/lang-assembly-wasm.spec.ts b/src/livecodes/languages/assembly-wasm/__tests__/lang-assembly-wasm.spec.ts new file mode 100644 index 0000000000..bf1227f12a --- /dev/null +++ b/src/livecodes/languages/assembly-wasm/__tests__/lang-assembly-wasm.spec.ts @@ -0,0 +1,40 @@ +import type { CompileOptions, Compiler, Config } from '../../../models'; +import { assemblyWasm } from '../lang-assembly-wasm'; + +describe('assembly-wasm', () => { + const compiler = assemblyWasm.compiler as Compiler; + + test('has the expected name, title and extensions', () => { + expect(assemblyWasm.name).toBe('assembly-wasm'); + expect(assemblyWasm.title).toBe('Assembly (Wasm)'); + expect(assemblyWasm.extensions).toEqual( + expect.arrayContaining(['asm', 'assembly', 'x86', 'x86-64', 'nasm', 'wasm.asm']), + ); + }); + + test('uses the script editor with the text/assembly script type', () => { + expect(assemblyWasm.editor).toBe('script'); + expect(compiler.scriptType).toBe('text/assembly'); + expect(compiler.compiledCodeLanguage).toBe('assembly-wasm'); + expect(compiler.liveReload).toBe(true); + }); + + test('loads only the runner script on the page (the runtimes live in a worker)', () => { + const scripts = + typeof compiler.scripts === 'function' + ? compiler.scripts({ baseUrl: 'base/', config: {} as Config, compiled: '' }) + : compiler.scripts; + expect(scripts).toEqual(['base/{{hash:lang-assembly-wasm-script.js}}']); + }); + + test('compiler factory is the identity (assembly happens in the runner)', async () => { + const fn = await compiler.factory({} as Config, ''); + const code = 'mov rax, 60\nxor rdi, rdi\nsyscall'; + expect(await fn(code, {} as CompileOptions as any)).toBe(code); + }); + + test('advertises editor support for x86 assembly', () => { + expect(assemblyWasm.editorSupport?.monaco?.language).toBe('asm'); + expect(assemblyWasm.editorSupport?.codejar?.language).toBe('nasm'); + }); +}); diff --git a/src/livecodes/languages/assembly-wasm/index.ts b/src/livecodes/languages/assembly-wasm/index.ts new file mode 100644 index 0000000000..a839c2c129 --- /dev/null +++ b/src/livecodes/languages/assembly-wasm/index.ts @@ -0,0 +1 @@ +export * from './lang-assembly-wasm'; diff --git a/src/livecodes/languages/assembly-wasm/lang-assembly-wasm-script.ts b/src/livecodes/languages/assembly-wasm/lang-assembly-wasm-script.ts new file mode 100644 index 0000000000..0b1d063490 --- /dev/null +++ b/src/livecodes/languages/assembly-wasm/lang-assembly-wasm-script.ts @@ -0,0 +1,309 @@ +/* eslint-disable no-console */ +import { createWorkerFromContent, getErrorMessage } from '../../utils/utils'; +import { + assemblyWasmBaseUrl, + keystoneJsUrl, + keystoneJsWasmUrl, + unicornJsX86Url, +} from '../../vendors'; + +// x86-64 assembly is assembled and executed by @live-codes/assembly-wasm, which loads +// Keystone (the assembler) and Unicorn (the CPU emulator) as separate WebAssembly +// runtimes. That package bundles neither of them, so the URLs are passed here — see +// `vendors.ts`. +// +// It runs in a dedicated worker: the emulator is synchronous, and a program that loops +// would otherwise block the result page. The guest's `syscall`s are served by the +// package, so `write` becomes stdout and `read` reads the input box. + +const SCRIPT_TYPE = 'text/assembly'; + +const BOOT_TIMEOUT_MS = 2 * 60_000; + +interface WorkerRunResult { + output: string; + errors: string[]; + exitCode: number | null; +} + +interface RunResult { + input: string; + output: string | null; + error: string | null; + exitCode: number | null; +} + +interface Runner { + ensureReady: () => Promise; + run: (code: string, input: string) => Promise; + destroy: () => void; +} + +interface AssemblyWasmApi { + ready: boolean; + failed: boolean; + input: string; + output: string | null; + error: string | null; + exitCode: number | null; + loaded: Promise; + init: Promise | null; + runner?: Runner; + run: (input?: string) => Promise; +} + +declare const window: Window & { + livecodes: Record; +}; + +const withTimeout = ( + promise: Promise, + ms: number, + message: string, + onTimeout?: () => void, +): Promise => + new Promise((resolve, reject) => { + const timer = setTimeout(() => { + onTimeout?.(); + reject(new Error(message)); + }, ms); + promise.then( + (value) => { + clearTimeout(timer); + resolve(value); + }, + (error) => { + clearTimeout(timer); + reject(error); + }, + ); + }); + +const getWorkerSrc = () => ` +importScripts(${JSON.stringify(assemblyWasmBaseUrl + 'dist/assembly-wasm.global.js')}); + +let compiler = null; + +const getCompiler = () => { + compiler = + compiler || + self.assemblyWasm.createCompiler({ + keystoneUrl: ${JSON.stringify(keystoneJsUrl)}, + keystoneWasmUrl: ${JSON.stringify(keystoneJsWasmUrl)}, + unicornUrl: ${JSON.stringify(unicornJsX86Url)}, + }); + return compiler; +}; + +addEventListener('message', async (event) => { + const { id, code, input } = event.data; + try { + const result = await (await getCompiler()).run(code, input); + postMessage({ + id, + result: { + output: result.output, + errors: result.errors, + exitCode: result.exitCode, + }, + }); + } catch (error) { + postMessage({ id, error: String((error && error.message) || error) }); + } +}); + +getCompiler().then( + () => postMessage({ type: 'ready' }), + (error) => postMessage({ type: 'error', message: String((error && error.message) || error) }), +); +`; + +interface Pending { + resolve: (result: WorkerRunResult) => void; + reject: (error: Error) => void; +} + +const createRunner = (): Runner => { + let worker: Worker | null = null; + let ready: Promise | null = null; + let settleReady: ((error?: Error) => void) | null = null; + let pending: Record = {}; + let nextId = 1; + + const failAll = (error: Error) => { + for (const id of Object.keys(pending)) { + pending[Number(id)].reject(error); + } + pending = {}; + }; + + const teardown = (error?: Error) => { + worker?.terminate(); + worker = null; + ready = null; + settleReady?.(error); + settleReady = null; + if (error) failAll(error); + }; + + const onMessage = (event: MessageEvent) => { + const message = event.data ?? {}; + if (message.type === 'ready') { + settleReady?.(); + settleReady = null; + return; + } + if (message.type === 'error') { + // The runtime failed to load (network, or the browser is unsupported). + teardown(new Error(message.message)); + return; + } + const request = pending[message.id]; + if (!request) return; + delete pending[message.id]; + if (message.error != null) { + request.reject(new Error(message.error)); + } else { + request.resolve(message.result); + } + }; + + const spawn = () => { + ready = new Promise((resolve, reject) => { + settleReady = (error?: Error) => (error ? reject(error) : resolve()); + }); + worker = createWorkerFromContent(getWorkerSrc()); + worker.onmessage = onMessage; + worker.onerror = (event) => + teardown(new Error(`The Assembly worker crashed: ${event.message}`)); + }; + + /** Spawn the worker if needed and resolve once the runtime has loaded. */ + const ensureReady = async () => { + if (!ready) spawn(); + await ready; + }; + + const run = (code: string, input: string) => + ensureReady().then( + () => + new Promise((resolve, reject) => { + const id = nextId++; + pending[id] = { resolve, reject }; + worker?.postMessage({ id, code, input }); + }), + ); + + return { ensureReady, run, destroy: () => teardown() }; +}; + +const setResult = ( + input: string, + output: string | null, + error: string | null, + exitCode: number | null, +): RunResult => { + assemblyWasm.input = input; + assemblyWasm.output = output; + assemblyWasm.error = error; + assemblyWasm.exitCode = exitCode; + assemblyWasm.ready = true; + + if (error != null) { + console.error(error); + } else if (output != null) { + console.log(output); + } + return { input, output, error, exitCode }; +}; + +window.livecodes.assemblyWasm ??= {} as AssemblyWasmApi; + +const assemblyWasm = window.livecodes.assemblyWasm; +assemblyWasm.ready = false; +assemblyWasm.failed = false; + +/** Start (once) downloading the runtimes, showing the loading indicator while it happens. */ +const ensureLoaded = (runner: Runner): Promise => { + let init = assemblyWasm.init; + if (!init) { + assemblyWasm.failed = false; + init = (async () => { + parent.postMessage({ type: 'loading', payload: true }, '*'); + try { + await withTimeout( + runner.ensureReady(), + BOOT_TIMEOUT_MS, + 'Timed out while loading the Assembly runtimes.', + () => runner.destroy(), + ); + } finally { + parent.postMessage({ type: 'loading', payload: false }, '*'); + } + })().catch((error: Error) => { + // Reset so a later run can retry the download. + assemblyWasm.init = null; + assemblyWasm.failed = true; + throw error; + }); + // The failure is surfaced through `run`; do not also report it unhandled. + init.catch(() => undefined); + assemblyWasm.init = init; + } + return init; +}; + +assemblyWasm.loaded = new Promise((resolve, reject) => { + const interval = setInterval(() => { + if (assemblyWasm.failed) { + clearInterval(interval); + reject(new Error(assemblyWasm.error || 'Failed to initialize the assembler')); + } else if (assemblyWasm.ready) { + clearInterval(interval); + resolve(); + } + }, 50); +}); + +assemblyWasm.run = async (input?: string) => { + const stdin = `${input ?? assemblyWasm.input ?? ''}`; + assemblyWasm.input = stdin; + + let code = ''; + document.querySelectorAll(`script[type="${SCRIPT_TYPE}"]`).forEach((script) => { + code += `${script.innerHTML}\n`; + }); + if (!code.trim()) return setResult(stdin, null, null, 0); + + // Park the runner on the persisted namespace so a live reload reuses the warm + // worker instead of loading the runtimes again. + const runner = (assemblyWasm.runner = assemblyWasm.runner || createRunner()); + + try { + await ensureLoaded(runner); + } catch (error) { + return setResult(stdin, null, `Error: ${getErrorMessage(error)}`, 1); + } + + try { + const result = await runner.run(code, stdin); + // `errors` holds the assembler's diagnostics and any runtime fault, and is empty + // when the program assembled and exited cleanly. + const errors = (result.errors || []).filter(Boolean); + if (errors.length) { + return setResult(stdin, null, errors.join('\n'), result.exitCode ?? 1); + } + return setResult(stdin, result.output ?? '', null, result.exitCode ?? 0); + } catch (error) { + return setResult(stdin, null, `Error: ${getErrorMessage(error)}`, 1); + } +}; + +// Alias, so both `livecodes.assemblyWasm` and `livecodes.asm` are available in markup. +window.livecodes.asm = assemblyWasm; + +window.addEventListener('load', async () => { + parent.postMessage({ type: 'loading', payload: true }, '*'); + await assemblyWasm.run(assemblyWasm.input); + parent.postMessage({ type: 'loading', payload: false }, '*'); +}); diff --git a/src/livecodes/languages/assembly-wasm/lang-assembly-wasm.ts b/src/livecodes/languages/assembly-wasm/lang-assembly-wasm.ts new file mode 100644 index 0000000000..49bacb681d --- /dev/null +++ b/src/livecodes/languages/assembly-wasm/lang-assembly-wasm.ts @@ -0,0 +1,30 @@ +import type { LanguageSpecs } from '../../models'; +import { monacoLanguagesBaseUrl } from '../../vendors'; + +/** + * x86-64 assembly, assembled by Keystone and executed by Unicorn (both compiled to + * WebAssembly and loaded at run time by `@live-codes/assembly-wasm`). + * + * The source is not transformed at compile time: it is handed to the result page in a + * `text/assembly` script tag and assembled and run there by `lang-assembly-wasm-script.ts`. + */ +export const assemblyWasm: LanguageSpecs = { + name: 'assembly-wasm', + title: 'Assembly (Wasm)', + longTitle: 'x86-64 Assembly (Wasm)', + compiler: { + factory: () => async (code) => code, + scripts: ({ baseUrl }) => [baseUrl + '{{hash:lang-assembly-wasm-script.js}}'], + scriptType: 'text/assembly', + compiledCodeLanguage: 'assembly-wasm', + liveReload: true, + }, + extensions: ['asm', 'assembly', 'asm-wasm', 'assembly-wasm', 'x86', 'x86-64', 'nasm', 'wasm.asm'], + editor: 'script', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'asm.js', language: 'asm' }, + // Prism's `nasm` grammar is an Intel-syntax x86 assembly highlighter. + codejar: { language: 'nasm' }, + }, + largeDownload: true, +}; diff --git a/src/livecodes/languages/languages.ts b/src/livecodes/languages/languages.ts index 36e5fe549b..b5956ef373 100644 --- a/src/livecodes/languages/languages.ts +++ b/src/livecodes/languages/languages.ts @@ -2,6 +2,7 @@ import type { LanguageSpecs } from '../models'; import { adaWasm } from './ada-wasm'; import { artTemplate } from './art-template'; import { asciidoc } from './asciidoc'; +import { assemblyWasm } from './assembly-wasm'; import { assemblyscript } from './assemblyscript'; import { astro } from './astro'; import { babel } from './babel'; @@ -194,6 +195,7 @@ export const languages: LanguageSpecs[] = [ pascal, assemblyscript, wat, + assemblyWasm, sql, postgresql, prolog, diff --git a/src/livecodes/models.ts b/src/livecodes/models.ts index 5be16541a8..18985c3877 100644 --- a/src/livecodes/models.ts +++ b/src/livecodes/models.ts @@ -220,6 +220,7 @@ export interface Compiler { | 'text/go-wasm' | 'text/swift-wasm' | 'text/ada-wasm' + | 'text/assembly' | 'application/json' | 'application/lua' | 'text/fennel' @@ -268,6 +269,8 @@ export type TemplateAlias = | 'rs' | 'swift' | 'ada' + | 'asm' + | 'x86' | 'hs' | 'hs-wasm' | 'pl' diff --git a/src/livecodes/templates/starter/assembly-wasm-starter.ts b/src/livecodes/templates/starter/assembly-wasm-starter.ts new file mode 100644 index 0000000000..37dd9dafc7 --- /dev/null +++ b/src/livecodes/templates/starter/assembly-wasm-starter.ts @@ -0,0 +1,162 @@ +import type { Template } from '../../models'; + +export const assemblyWasmStarter: Template = { + name: 'assembly-wasm', + aliases: ['asm', 'x86'], + title: window.deps.translateString('templates.starter.assembly-wasm', 'Assembly (Wasm) Starter'), + thumbnail: 'assets/templates/assembly.svg', + activeEditor: 'script', + markup: { + language: 'html', + content: ` +
    +

    Hello, World!

    + +

    You clicked 0 times.

    + +
    + + +`.trimStart(), + }, + style: { + language: 'css', + content: ` +.container, +.container button { + text-align: center; + font: 1em sans-serif; +} +.logo { + width: 150px; +} +`.trimStart(), + }, + script: { + language: 'assembly-wasm', + content: ` +; Reads a number on standard input, increments it and prints the result. +; The page passes the current count as input, so every run is a fresh program. + + xor rax, rax ; read(0, inbuf, 16) + xor rdi, rdi + lea rsi, [rip + inbuf] + mov rdx, 16 + syscall + + lea rsi, [rip + inbuf] ; parse the number, which may be negative + xor rbx, rbx + mov r8, 1 + movzx rcx, byte ptr [rsi] + cmp cl, 45 ; '-' + jne parse + mov r8, -1 + inc rsi +parse: + movzx rcx, byte ptr [rsi] + sub cl, 48 + cmp cl, 9 + ja parsed + imul rbx, rbx, 10 + add rbx, rcx + inc rsi + jmp parse +parsed: + imul rbx, r8 ; apply the sign + inc rbx ; this run's count + + mov rax, 1 ; write(1, title, 9) + mov rdi, 1 + lea rsi, [rip + title] + mov rdx, 9 + syscall + + lea rdi, [rip + outbuf + 16] + mov byte ptr [rdi], 10 ; trailing newline + mov rax, rbx + mov r10, 10 +tostring: + xor rdx, rdx + div r10 + add dl, 48 + dec rdi + mov byte ptr [rdi], dl + test rax, rax + jnz tostring + + lea rdx, [rip + outbuf + 17] + sub rdx, rdi ; the digits and the newline + mov rsi, rdi + mov rax, 1 ; write(1, digits, length) + mov rdi, 1 + syscall + + mov rax, 60 ; exit(0) + xor rdi, rdi + syscall + +title: + .ascii "Assembly" + .byte 10 +inbuf: + .zero 16 +outbuf: + .zero 17 +`.trimStart(), + }, +}; diff --git a/src/livecodes/templates/starter/index.ts b/src/livecodes/templates/starter/index.ts index eef0e7fde5..58f46841e0 100644 --- a/src/livecodes/templates/starter/index.ts +++ b/src/livecodes/templates/starter/index.ts @@ -2,6 +2,7 @@ import { adaWasmStarter } from './ada-wasm-starter'; import { angularStarter } from './angular-starter'; +import { assemblyWasmStarter } from './assembly-wasm-starter'; import { assemblyscriptStarter } from './assemblyscript-starter'; import { astroStarter } from './astro-starter'; import { backboneStarter } from './backbone-starter'; @@ -162,6 +163,7 @@ export const starterTemplates = [ pascalStarter, assemblyscriptStarter, watStarter, + assemblyWasmStarter, sqlStarter, postgresqlStarter, prologStarter, diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 001f809d6c..1e22247936 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -15,6 +15,8 @@ export const asciidocUrl = /* @__PURE__ */ getUrl( '@asciidoctor/core@2.2.8/dist/browser/asciidoctor.js', ); +export const assemblyWasmBaseUrl = /* @__PURE__ */ getUrl('@live-codes/assembly-wasm@0.1.0/'); + export const assemblyscriptLoaderUrl = /* @__PURE__ */ getUrl( '@assemblyscript/loader@0.27.29/umd/index.js', ); @@ -307,6 +309,17 @@ export const jsZipUrl = /* @__PURE__ */ getUrl('jszip@3.10.1/dist/jszip.js'); export const juliaWasmBaseUrl = /* @__PURE__ */ getUrl('@chriskoch/julia-wasm@1.0.4'); +// The x86-64 assembler and CPU emulator behind the `assembly-wasm` language. Both are +// published separately and are loaded at run time by @live-codes/assembly-wasm, which +// deliberately bundles neither of them. +export const keystoneJsUrl = /* @__PURE__ */ getUrl( + '@alexaltea/keystone-js@0.9.2/dist/keystone.js', +); + +export const keystoneJsWasmUrl = /* @__PURE__ */ getUrl( + '@alexaltea/keystone-js@0.9.2/dist/keystone.wasm', +); + export const liquidJsUrl = /* @__PURE__ */ getUrl('liquidjs@10.14.0/dist/liquid.browser.min.js'); export const localforageUrl = /* @__PURE__ */ getUrl('localforage@1.10.0/dist/localforage.min.js'); @@ -346,7 +359,7 @@ export const monacoBaseUrl = /* @__PURE__ */ getUrl('@live-codes/monaco-editor@0 export const monacoEmacsUrl = /* @__PURE__ */ getUrl('monaco-emacs@0.3.0/dist/monaco-emacs.js'); export const monacoLanguagesBaseUrl = /* @__PURE__ */ getUrl( - '@live-codes/monaco-languages@0.3.8/dist/', + '@live-codes/monaco-languages@0.3.9/dist/', ); export const monacoThemesBaseUrl = /* @__PURE__ */ getUrl('monaco-themes@0.4.4/themes/'); @@ -513,6 +526,10 @@ export const twigUrl = /* @__PURE__ */ getUrl('twig@1.17.1/twig.min.js'); export const typescriptVersion = '5.9.3'; export const typescriptUrl = getUrl(`typescript@${typescriptVersion}/lib/typescript.js`); +export const unicornJsX86Url = /* @__PURE__ */ getUrl( + '@alexaltea/unicorn-js@2.1.4/dist/unicorn_x86.js', +); + export const uniterUrl = /* @__PURE__ */ getUrl('uniter@2.18.0/dist/uniter.js'); export const vbWasmBaseUrl = /* @__PURE__ */ getUrl('@live-codes/vb-wasm@0.1.1/'); diff --git a/src/sdk/models.ts b/src/sdk/models.ts index d5557dacfd..b9e13aeaa0 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -287,6 +287,14 @@ export type Language = | 'webassembly' | 'wasm' | 'Binary' + | 'assembly-wasm' + | 'assembly' + | 'asm' + | 'asm-wasm' + | 'x86' + | 'x86-64' + | 'nasm' + | 'wasm.asm' | 'sql' | 'sqlite' | 'sqlite3' @@ -489,6 +497,7 @@ export type TemplateName = | 'markdown' | 'assemblyscript' | 'wat' + | 'assembly-wasm' | 'sql' | 'postgresql' | 'prolog' diff --git a/storybook/_stories/EmbedOptions/template.ts b/storybook/_stories/EmbedOptions/template.ts index e734bf29f5..25427ce6a6 100644 --- a/storybook/_stories/EmbedOptions/template.ts +++ b/storybook/_stories/EmbedOptions/template.ts @@ -82,6 +82,7 @@ const storyDef: StoryDef = { Pascal: { props: { template: 'pascal' } }, AssemblyScript: { props: { template: 'assemblyscript' }, storyName: 'AssemblyScript' }, WebAssemblyText: { props: { template: 'wat' }, storyName: 'WebAssembly Text' }, + AssemblyWasm: { props: { template: 'assembly-wasm' }, storyName: 'Assembly (Wasm)' }, SQL: { props: { template: 'sql' } }, PostgreSQL: { props: { template: 'postgresql' } }, Prolog: { props: { template: 'prolog' } }, diff --git a/vendor-licenses.md b/vendor-licenses.md index 77e959ca41..b1fbab4d56 100644 --- a/vendor-licenses.md +++ b/vendor-licenses.md @@ -10,6 +10,8 @@ art-template: [MIT License](https://github.com/aui/art-template/blob/71333a3a6df Asciidoctor.js: [MIT License](https://github.com/asciidoctor/asciidoctor.js/blob/9d57b34084966f35d5c542ae4feed4941bf57903/LICENSE) +Assembly (Wasm): [MIT License](https://github.com/live-codes/browser-assembly/blob/main/packages/assembly-wasm/LICENSE) (the [@live-codes/assembly-wasm](https://www.npmjs.com/package/@live-codes/assembly-wasm) package, which bundles neither of the runtimes it loads; see Keystone and Unicorn) + AssemblyScript: [Apache License 2.0](https://github.com/AssemblyScript/assemblyscript/blob/a0c27fadd027a32542420160deff04dc31e10f59/LICENSE) Astring: [MIT License](https://github.com/davidbonnet/astring/blob/8ac784be966a20eda44de32f79db1a6e44832659/LICENSE) @@ -136,6 +138,8 @@ JSCPP: [MIT License](https://github.com/felixhao28/JSCPP/blob/befbd6b48666007151 JSZip: [MIT License](https://github.com/Stuk/jszip/blob/3db5fdc85586ef6c26d15b503c45ce8e42905d77/LICENSE.markdown) +Keystone: [GPL-2.0 license](https://github.com/keystone-engine/keystone/blob/master/COPYING) (assembles the x86-64 machine code for Assembly (Wasm). Loaded at run time from its own package, not bundled by LiveCodes) + konnors-ninja-keys: [MIT License](https://github.com/KonnorRogers/konnors-ninja-keys/blob/6dde465ab2c64329c4284a1f95d9d7501acdb86a/LICENSE) Less: [Apache License 2.0](https://github.com/less/less.js/blob/870f9b2d8136bfbcdc9e1293bb0def51b54f9276/LICENSE) @@ -316,6 +320,8 @@ Twig.js: [BSD 2-Clause License](https://github.com/twigjs/twig.js/blob/59d991d35 TypeScript: [Apache License 2.0](https://github.com/microsoft/TypeScript/blob/8523ca4fa392b5b3d7ff28058503a12ef8569c7f/LICENSE.txt) +Unicorn: [GPL-2.0 license](https://github.com/unicorn-engine/unicorn/blob/master/COPYING) (executes the x86-64 machine code for Assembly (Wasm). Loaded at run time from its own package, not bundled by LiveCodes) + Uniter: [MIT License](https://github.com/asmblah/uniter/blob/304fa1108393f4238fa4fb09c5cfad30a7690493/MIT-LICENSE.txt) UnoCSS: [MIT License](https://github.com/unocss/unocss/blob/f375524d9bca3f2f8b445b322ec0fc3eb124ec3c/LICENSE)