From aa5c02fa7053cb7ad7dc373ddb469a9a0014edd9 Mon Sep 17 00:00:00 2001 From: Rucadi Date: Sun, 11 May 2025 23:07:40 +0200 Subject: [PATCH] Add Nix Language (#6198) --- .github/labeler.yml | 7 + etc/config/nix.defaults.properties | 16 + examples/nix/default.nix | 17 + lib/compilers/_all.ts | 1 + lib/compilers/nix.ts | 85 +++++ lib/languages.ts | 11 + static/modes/_all.ts | 1 + static/modes/nix-mode.ts | 141 ++++++++ types/languages.interfaces.ts | 1 + views/resources/logos/nix.svg | 513 +++++++++++++++++++++++++++++ 10 files changed, 793 insertions(+) create mode 100644 etc/config/nix.defaults.properties create mode 100644 examples/nix/default.nix create mode 100644 lib/compilers/nix.ts create mode 100644 static/modes/nix-mode.ts create mode 100644 views/resources/logos/nix.svg diff --git a/.github/labeler.yml b/.github/labeler.yml index cda623a34..204f71b66 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -267,6 +267,13 @@ - 'etc/config/nim.*.properties' - 'static/modes/nim-mode.ts' +'lang-nix': + - changed-files: + - any-glob-to-any-file: + - 'lib/compilers/nix.ts' + - 'etc/config/nix.*.properties' + - 'static/modes/nix-mode.ts' + 'lang-numba': - changed-files: - any-glob-to-any-file: diff --git a/etc/config/nix.defaults.properties b/etc/config/nix.defaults.properties new file mode 100644 index 000000000..7a474488b --- /dev/null +++ b/etc/config/nix.defaults.properties @@ -0,0 +1,16 @@ +# Default settings for nix +compilers=&nix +compilerType=nix + +group.nix.compilers=nixdefault +# please override this to your nix installation location in nix.local.properties +compiler.nixdefault.exe= +compiler.nixdefault.name=nix default + +defaultCompiler=nixdefault +demangler= +postProcess= +options= +supportsBinary=false +needsMulti=false +supportsExecute=false diff --git a/examples/nix/default.nix b/examples/nix/default.nix new file mode 100644 index 000000000..e73af162d --- /dev/null +++ b/examples/nix/default.nix @@ -0,0 +1,17 @@ +let + hello_world = "hello_world!"; +in +{ + string = hello_world; + integer = 1; + float = 3.141; + bool = true; + null = null; + list = [ 1 "two" false ]; + attribute-set = { + a = "hello"; + b = 2; + c = 2.718; + d = false; + }; # comments are supported +} \ No newline at end of file diff --git a/lib/compilers/_all.ts b/lib/compilers/_all.ts index a2534324f..26b60b336 100644 --- a/lib/compilers/_all.ts +++ b/lib/compilers/_all.ts @@ -108,6 +108,7 @@ export {MrustcCompiler} from './mrustc.js'; export {Msp430Compiler} from './msp430.js'; export {NasmCompiler} from './nasm.js'; export {NimCompiler} from './nim.js'; +export {NixCompiler} from './nix.js'; export {NumbaCompiler} from './numba.js'; export {NvccCompiler} from './nvcc.js'; export {NvcppCompiler} from './nvcpp.js'; diff --git a/lib/compilers/nix.ts b/lib/compilers/nix.ts new file mode 100644 index 000000000..b64b3454f --- /dev/null +++ b/lib/compilers/nix.ts @@ -0,0 +1,85 @@ +import fs from 'node:fs/promises'; +// 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 path from 'node:path'; + +import {ExecutionOptions} from '../../types/compilation/compilation.interfaces.js'; +import {BaseCompiler} from '../base-compiler.js'; + +export class NixCompiler extends BaseCompiler { + static get key() { + return 'nix'; + } + + override async runCompiler( + compiler: string, + options: string[], + inputFilename: string, + execOptions: ExecutionOptions & {env: Record}, + ) { + if (!execOptions) { + execOptions = this.getDefaultExecOptions(); + } + + execOptions.customCwd = path.dirname(inputFilename); + const dirPath = path.dirname(inputFilename); + if (!execOptions.customCwd) { + execOptions.customCwd = dirPath; + } + + const compilerExecResult = await super.runCompiler(compiler, options, inputFilename, execOptions); + if (compilerExecResult.stdout.length > 0) { + const outputFilename = this.getOutputFilename(dirPath, this.outputFilebase); + const outputText = compilerExecResult.stdout.map(line => line.text).join('\n'); + + if (options.includes('--json')) { + // Parse and pretty-print if --json is passed + await fs.writeFile(outputFilename, JSON.stringify(JSON.parse(outputText), null, 2)); + } else { + // Otherwise, write raw output (Should call nixfmt probably) + await fs.writeFile(outputFilename, outputText); + } + } + return compilerExecResult; + } + + override optionsForFilter(): any[] { + return []; + } + + override orderArguments( + options: string[], + inputFilename: string, + libIncludes: string[], + libOptions: string[], + libPaths: string[], + libLinks: string[], + userOptions: string[], + staticLibLinks: string[], + ): string[] { + return ['eval', '--extra-experimental-features', 'nix-command', '--file', this.filename(inputFilename)] + .concat(options, userOptions) + .concat(['--store', 'dummy://']); + } +} diff --git a/lib/languages.ts b/lib/languages.ts index 350bd800f..7f1f8bd74 100644 --- a/lib/languages.ts +++ b/lib/languages.ts @@ -613,6 +613,17 @@ const definitions: Record = { previewFilter: null, monacoDisassembly: null, }, + nix: { + name: 'Nix', + monaco: 'nix', + extensions: ['.nix'], + alias: [], + logoUrl: 'nix.svg', + logoUrlDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, objc: { name: 'Objective-C', monaco: 'objective-c', diff --git a/static/modes/_all.ts b/static/modes/_all.ts index 2d7f1b62c..17916c647 100644 --- a/static/modes/_all.ts +++ b/static/modes/_all.ts @@ -56,6 +56,7 @@ import './mlir-mode'; import './modula2-mode'; import './nc-mode'; import './nim-mode'; +import './nix-mode'; import './ocaml-mode'; import './odin-mode'; import './openclc-mode'; diff --git a/static/modes/nix-mode.ts b/static/modes/nix-mode.ts new file mode 100644 index 000000000..a35356927 --- /dev/null +++ b/static/modes/nix-mode.ts @@ -0,0 +1,141 @@ +// 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 * as monaco from 'monaco-editor'; + +function definition(): monaco.languages.IMonarchLanguage { + return { + defaultToken: '', + tokenPostfix: '.nix', + + keywords: ['if', 'then', 'else', 'with', 'assert', 'let', 'in', 'rec', 'inherit'], + + builtins: ['builtins', 'true', 'false', 'null'], + functions: [ + 'scopedImport', + 'import', + 'isNull', + 'abort', + 'throw', + 'baseNameOf', + 'dirOf', + 'removeAttrs', + 'map', + 'toString', + 'derivationStrict', + 'derivation', + ], + + operators: [ + 'or', + '.', + '|>', + '<|', + '==', + '!=', + '!', + '<=', + '<', + '>=', + '>', + '&&', + '||', + '->', + '//', + '?', + '++', + '-', + '*', + '/', + '+', + ], + brackets: [ + {open: '{', close: '}', token: 'delimiter.curly'}, + {open: '[', close: ']', token: 'delimiter.square'}, + {open: '(', close: ')', token: 'delimiter.parenthesis'}, + ], + + tokenizer: { + root: [ + {include: '@whitespace'}, + [/#.*$/, 'comment'], + [/\/\*([^*]|\*(?!\/))*\*\//, 'comment'], + + [/"/, {token: 'string.quote', next: '@string_double'}], + [/''/, {token: 'string.quote', next: '@string_long'}], + + [/\$\{/, {token: 'delimiter.bracket', next: '@interpolation'}], + + [/\b[0-9]+\b/, 'number'], + + [/~?[A-Za-z0-9_.\-+]+(\/[A-Za-z0-9_.\-+]+)+/, 'string.unquoted.path'], + [/<[A-Za-z0-9_.\-+]+(\/[A-Za-z0-9_.\-+]+)*>/, 'string.unquoted.spath'], + [/[A-Za-z][A-Za-z0-9+\-.]*:[A-Za-z0-9%\/\?:@&=+\$,\-_.!~\*']+/, 'string.unquoted.url'], + + [ + /[a-zA-Z_][\w'\-]*/, + { + cases: { + '@keywords': 'keyword', + '@builtins': 'constant.language', + '@functions': 'support.function', + '@operators': 'operator', + '@default': 'identifier', + }, + }, + ], + + [/[=> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + +