From bd80d171de2ebf53ba2e2797589e7e1dadc8f19a Mon Sep 17 00:00:00 2001 From: timo <25167+timo@users.noreply.github.com> Date: Mon, 9 Jun 2025 19:39:53 +0200 Subject: [PATCH] Add raku language and rakudo compiler (#7784) This relies on https://github.com/compiler-explorer/infra/pull/1658 to put rakudo release versions in the right spot. ![image](https://github.com/user-attachments/assets/30ba7c2b-389a-4d3f-895b-c13da5b5f072) There are more things that can be added, such as opcode tooltips, suggested options for `--target=parse`, `--target=ast`, `--target=optimize`, and probably other things I haven't thought of yet. But this pull request should be a good starting point, and fine to merge without waiting for further features. --- etc/config/raku.amazon.properties | 117 +++++++++++++++++++++++++ etc/scripts/disasms/moarvm_disasm.raku | 36 ++++++++ examples/raku/default.raku | 15 ++++ lib/compilers/_all.ts | 1 + lib/compilers/raku.ts | 85 ++++++++++++++++++ lib/languages.ts | 11 +++ types/languages.interfaces.ts | 1 + views/resources/logos/camelia.svg | 1 + 8 files changed, 267 insertions(+) create mode 100644 etc/config/raku.amazon.properties create mode 100644 etc/scripts/disasms/moarvm_disasm.raku create mode 100644 examples/raku/default.raku create mode 100644 lib/compilers/raku.ts create mode 100644 views/resources/logos/camelia.svg diff --git a/etc/config/raku.amazon.properties b/etc/config/raku.amazon.properties new file mode 100644 index 000000000..fdbe1a3de --- /dev/null +++ b/etc/config/raku.amazon.properties @@ -0,0 +1,117 @@ +compilers=&rakudo-moar +defaultCompiler=rakudo-moar-2025-05-01 +compilerType=raku + +group.rakudo-moar.compilers=rakudo-moar-2025-05-01:rakudo-moar-2025-04-01:rakudo-moar-2025-03-01:rakudo-moar-2025-02-01:rakudo-moar-2025-01-01:rakudo-moar-2024-12-01:rakudo-moar-2024-10-01:rakudo-moar-2024-09-01:rakudo-moar-2024-08-01:rakudo-moar-2024-07-01:rakudo-moar-2024-06-01:rakudo-moar-2024-05-01:rakudo-moar-2024-04-01:rakudo-moar-2024-03-01:rakudo-moar-2024-02-01:rakudo-moar-2024-01-01:rakudo-moar-2023-12-01:rakudo-moar-2023-11-01:rakudo-moar-2023-10-01:rakudo-moar-2023-10-02:rakudo-moar-2023-09-01:rakudo-moar-2023-08-01:rakudo-moar-2023-06-01:rakudo-moar-2023-04-01:rakudo-moar-2023-02-01:rakudo-moar-2022-12-01:rakudo-moar-2022-07-01:rakudo-moar-2022-06-01:rakudo-moar-2022-04-01:rakudo-moar-2022-03-01:rakudo-moar-2022-02-01:rakudo-moar-2021-12-01:rakudo-moar-2021-10-01:rakudo-moar-2021-09-01:rakudo-moar-2021-08-01:rakudo-moar-2021-07-01:rakudo-moar-2021-06-01:rakudo-moar-2021-05-01:rakudo-moar-2021-04-01:rakudo-moar-2021-03-01:rakudo-moar-2021-02-1-01:rakudo-moar-2021-02-01:rakudo-moar-2020-12-01:rakudo-moar-2020-11-01 +group.rakudo-moar.isSemVer=false +group.rakudo-moar.baseName=Rakudo MoarVM + +interpreted=true +supportsBinary=false +supportsBinaryObject=true +versionFlag=--version +versionRe=v(([0-9a-zA-Z]+))([.-]([0-9a-zA-Z]+))+ +objdumper= +demangler= +postProcess= +options= +supportsExecute=true +stubText=sub square($number) { $number * $number } +disasmScript= + +## All exes in one big block, names are further towards the bottom. +compiler.rakudo-moar-2025-05-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2025.05-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2025-04-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2025.04-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2025-03-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2025.03-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2025-02-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2025.02-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2025-01-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2025.01-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2024-12-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2024.12-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2024-10-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2024.10-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2024-09-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2024.09-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2024-08-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2024.08-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2024-07-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2024.07-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2024-06-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2024.06-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2024-05-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2024.05-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2024-04-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2024.04-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2024-03-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2024.03-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2024-02-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2024.02-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2024-01-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2024.01-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2023-12-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2023.12-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2023-11-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2023.11-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2023-10-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2023.10-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2023-10-02.exe=/opt/compiler-explorer/raku/rakudo-moar-2023.10-02-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2023-09-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2023.09-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2023-08-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2023.08-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2023-06-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2023.06-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2023-04-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2023.04-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2023-02-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2023.02-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2022-12-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2022.12-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2022-07-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2022.07-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2022-06-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2022.06-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2022-04-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2022.04-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2022-03-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2022.03-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2022-02-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2022.02-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2021-12-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2021.12-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2021-10-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2021.10-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2021-09-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2021.09-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2021-08-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2021.08-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2021-07-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2021.07-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2021-06-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2021.06-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2021-05-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2021.05-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2021-04-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2021.04-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2021-03-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2021.03-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2021-02-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2021.02-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2020-12-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2020.12-01-linux-x86_64-gcc/bin/rakudo +compiler.rakudo-moar-2020-11-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2020.11-01-linux-x86_64-gcc/bin/rakudo + +# The one release that doesn't have the same length. +compiler.rakudo-moar-2021-02-1-01.exe=/opt/compiler-explorer/raku/rakudo-moar-2021.02.1-01-linux-x86_64-gcc/bin/rakudo + + +# Names for all the compilers + +compiler.rakudo-moar-2025-05-01.name=Rakudo 2025.05 MoarVM +compiler.rakudo-moar-2025-04-01.name=Rakudo 2025.04 MoarVM +compiler.rakudo-moar-2025-03-01.name=Rakudo 2025.03 MoarVM +compiler.rakudo-moar-2025-02-01.name=Rakudo 2025.02 MoarVM +compiler.rakudo-moar-2025-01-01.name=Rakudo 2025.01 MoarVM +compiler.rakudo-moar-2024-12-01.name=Rakudo 2024.12 MoarVM +compiler.rakudo-moar-2024-10-01.name=Rakudo 2024.10 MoarVM +compiler.rakudo-moar-2024-09-01.name=Rakudo 2024.09 MoarVM +compiler.rakudo-moar-2024-08-01.name=Rakudo 2024.08 MoarVM +compiler.rakudo-moar-2024-07-01.name=Rakudo 2024.07 MoarVM +compiler.rakudo-moar-2024-06-01.name=Rakudo 2024.06 MoarVM +compiler.rakudo-moar-2024-05-01.name=Rakudo 2024.05 MoarVM +compiler.rakudo-moar-2024-04-01.name=Rakudo 2024.04 MoarVM +compiler.rakudo-moar-2024-03-01.name=Rakudo 2024.03 MoarVM +compiler.rakudo-moar-2024-02-01.name=Rakudo 2024.02 MoarVM +compiler.rakudo-moar-2024-01-01.name=Rakudo 2024.01 MoarVM +compiler.rakudo-moar-2023-12-01.name=Rakudo 2023.12 MoarVM +compiler.rakudo-moar-2023-11-01.name=Rakudo 2023.11 MoarVM +compiler.rakudo-moar-2023-10-01.name=Rakudo 2023.10 MoarVM +compiler.rakudo-moar-2023-10-02.name=Rakudo 2023.10-02 MoarVM +compiler.rakudo-moar-2023-09-01.name=Rakudo 2023.09 MoarVM +compiler.rakudo-moar-2023-08-01.name=Rakudo 2023.08 MoarVM +compiler.rakudo-moar-2023-06-01.name=Rakudo 2023.06 MoarVM +compiler.rakudo-moar-2023-04-01.name=Rakudo 2023.04 MoarVM +compiler.rakudo-moar-2023-02-01.name=Rakudo 2023.02 MoarVM +compiler.rakudo-moar-2022-12-01.name=Rakudo 2022.12 MoarVM +compiler.rakudo-moar-2022-07-01.name=Rakudo 2022.07 MoarVM +compiler.rakudo-moar-2022-06-01.name=Rakudo 2022.06 MoarVM +compiler.rakudo-moar-2022-04-01.name=Rakudo 2022.04 MoarVM +compiler.rakudo-moar-2022-03-01.name=Rakudo 2022.03 MoarVM +compiler.rakudo-moar-2022-02-01.name=Rakudo 2022.02 MoarVM +compiler.rakudo-moar-2021-12-01.name=Rakudo 2021.12 MoarVM +compiler.rakudo-moar-2021-10-01.name=Rakudo 2021.10 MoarVM +compiler.rakudo-moar-2021-09-01.name=Rakudo 2021.09 MoarVM +compiler.rakudo-moar-2021-08-01.name=Rakudo 2021.08 MoarVM +compiler.rakudo-moar-2021-07-01.name=Rakudo 2021.07 MoarVM +compiler.rakudo-moar-2021-06-01.name=Rakudo 2021.06 MoarVM +compiler.rakudo-moar-2021-05-01.name=Rakudo 2021.05 MoarVM +compiler.rakudo-moar-2021-04-01.name=Rakudo 2021.04 MoarVM +compiler.rakudo-moar-2021-03-01.name=Rakudo 2021.03 MoarVM +compiler.rakudo-moar-2021-02-01.name=Rakudo 2021.02 MoarVM +compiler.rakudo-moar-2020-12-01.name=Rakudo 2020.12 MoarVM +compiler.rakudo-moar-2020-11-01.name=Rakudo 2020.11 MoarVM + +compiler.rakudo-moar-2021-02-1-01.name=Rakudo 2021.02.1 MoarVM diff --git a/etc/scripts/disasms/moarvm_disasm.raku b/etc/scripts/disasms/moarvm_disasm.raku new file mode 100644 index 000000000..5dbf1d06d --- /dev/null +++ b/etc/scripts/disasms/moarvm_disasm.raku @@ -0,0 +1,36 @@ +sub tempname { + my $lastex; + for ^1000 { + my $name = $*TMPDIR.child("rakudo_disassembly_" ~ (|("a".."z"),|("A".."Z"),|("0".."9")).roll(8).join("") ~ ".moarvm"); + try { + $name.IO.open(:create, :exclusive).close(); + CATCH { default { $lastex = $!; next } } + } + return $name; + } + die "Could not come up with a free temp name file? $lastex.Str()"; +} + +sub MAIN($rakudoexe, $outputfile, *@extra_args) { + my $code = @extra_args.pop; + + # If the user passes --target, we don't want to run the output through + # the moar --dump program. + if @extra_args && @extra_args.any.starts-with("--target=") { + my $output = qqx/ $rakudoexe @extra_args[0] $code /; + $outputfile.IO.spurt($output); + return; + } + + # Store the moar bytecode result + my $tempfile = tempname; + my $moarexe = $rakudoexe.IO.sibling("moar"); + + qqx/ $rakudoexe --target=mbc --output=$tempfile $code /; + + my $output = qqx[ $moarexe --dump $tempfile ]; + + $outputfile.IO.spurt($output); + + LEAVE { .IO.unlink with $tempfile } +} diff --git a/examples/raku/default.raku b/examples/raku/default.raku new file mode 100644 index 000000000..a95840476 --- /dev/null +++ b/examples/raku/default.raku @@ -0,0 +1,15 @@ + +sub square($number) { + $number * $number +} + +multi sub MAIN(Int $foo) { + say "When no one was looking, Lex Luthor took $foo cakes."; + say "The square of that is &square($foo) cakes."; + say "It's also roughly as much as $($foo div 10) tens."; + say "And that's terrible."; +} + +multi sub MAIN() { + say "You can pass a number on the commandline if you like!" +} diff --git a/lib/compilers/_all.ts b/lib/compilers/_all.ts index 2ccf7c4bb..47e732caa 100644 --- a/lib/compilers/_all.ts +++ b/lib/compilers/_all.ts @@ -129,6 +129,7 @@ export {QNXCompiler} from './qnx.js'; export {R8Compiler} from './r8.js'; export {RGACompiler} from './rga.js'; export {RacketCompiler} from './racket.js'; +export {RakuCompiler} from './raku.js'; export {RubyCompiler} from './ruby.js'; export {RustCompiler} from './rust.js'; export {RustcCgGCCCompiler} from './rustc-cg-gcc.js'; diff --git a/lib/compilers/raku.ts b/lib/compilers/raku.ts new file mode 100644 index 000000000..d4ccc8a03 --- /dev/null +++ b/lib/compilers/raku.ts @@ -0,0 +1,85 @@ +// Copyright (c) 2025, Compiler Explorer Authors +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import type {AsmResultSource, ParsedAsmResultLine} from '../../types/asmresult/asmresult.interfaces.js'; +import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js'; +import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js'; +import {BaseCompiler} from '../base-compiler.js'; +import {CompilationEnvironment} from '../compilation-env.js'; +import {resolvePathFromAppRoot} from '../utils.js'; + +export class RakuCompiler extends BaseCompiler { + private readonly disasmScriptPath: string; + private readonly exepath: string; + + constructor(compilerInfo: PreliminaryCompilerInfo, env: CompilationEnvironment) { + super(compilerInfo, env); + this.compiler.demangler = ''; + this.demanglerClass = null; + this.disasmScriptPath = resolvePathFromAppRoot('etc', 'scripts', 'disasms', 'moarvm_disasm.raku'); + this.exepath = this.compiler.exe; + } + + static get key() { + return 'raku'; + } + + override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string) { + return [this.disasmScriptPath, this.exepath, outputFilename]; + } + + override async processAsm(result, filters: ParseFiltersAndOutputOptions, options: string[]) { + const lineRe = /^ {5}annotation: ([^:]*):(\d+)$/; + const frameHeadRe = /^ {2}Frame_(\d+) :$/; + + const bytecodeLines = result.asm.split('\n'); + + const bytecodeResult: ParsedAsmResultLine[] = []; + let lastLineNo: number | null = null; + let sourceLoc: AsmResultSource | null = null; + + for (const line of bytecodeLines) { + const matchLine = line.match(lineRe); + const matchFrame = line.match(frameHeadRe); + + if (matchFrame) { + lastLineNo = null; + sourceLoc = {line: null, file: null}; + } else if (matchLine) { + const lineno = Number.parseInt(matchLine[2]); + sourceLoc = {line: lineno, file: null}; + lastLineNo = lineno; + } else if (line) { + sourceLoc = {line: lastLineNo, file: null}; + } else { + sourceLoc = {line: null, file: null}; + lastLineNo = null; + } + + bytecodeResult.push({text: line, source: sourceLoc}); + } + + return {asm: bytecodeResult}; + } +} diff --git a/lib/languages.ts b/lib/languages.ts index a9135303e..a3a622a87 100644 --- a/lib/languages.ts +++ b/lib/languages.ts @@ -748,6 +748,17 @@ const definitions: Record = { previewFilter: null, monacoDisassembly: 'scheme', }, + raku: { + name: 'Raku', + monaco: 'perl', + extensions: ['.raku', '.rakutest', '.rakumod', '.rakudoc'], + alias: ['Perl 6'], + logoUrl: 'camelia.svg', + logoUrlDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, ruby: { name: 'Ruby', monaco: 'ruby', diff --git a/types/languages.interfaces.ts b/types/languages.interfaces.ts index fb59af649..fce163822 100644 --- a/types/languages.interfaces.ts +++ b/types/languages.interfaces.ts @@ -88,6 +88,7 @@ export type LanguageKey = | 'python' | 'ptx' | 'racket' + | 'raku' | 'ruby' | 'rust' | 'sail' diff --git a/views/resources/logos/camelia.svg b/views/resources/logos/camelia.svg new file mode 100644 index 000000000..556094d30 --- /dev/null +++ b/views/resources/logos/camelia.svg @@ -0,0 +1 @@ +TM \ No newline at end of file