diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index f1a125f05..92f64fb86 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -81,3 +81,4 @@ From oldest to newest contributor, we would like to thank: - [Sebastian Rath](https://github.com/seb-mtl) - [Haze Booth](https://github.com/haze) - [Cassie Jones](https://github.com/porglezomp) +- [Bastien Penavayre](https://github.com/DaemonSnake) \ No newline at end of file diff --git a/etc/config/nim.defaults.properties b/etc/config/nim.defaults.properties new file mode 100644 index 000000000..a6ba56d43 --- /dev/null +++ b/etc/config/nim.defaults.properties @@ -0,0 +1,6 @@ +compilers=/usr/bin/nim +supportsBinary=true +demangler=c++filt +objdumper=objdump +compilerType=nim +binaryHideFuncRe=^(__.*|_(init|start|fini)|(de)?register_tm_clones|call_gmon_start|frame_dummy|.plt.*|.*@plt|_dl_relocate_static_pie)$ diff --git a/examples/nim/default.nim b/examples/nim/default.nim new file mode 100644 index 000000000..7f4551a1a --- /dev/null +++ b/examples/nim/default.nim @@ -0,0 +1,9 @@ +# Minimal example +# Allowed commands: +# - "compile", "compileToC", "c" to build C assambly +# - "compileToCpp", "cpp", "cc" to build C++ assambly +# - "compileToOC", "objc" to build objective-C assambly +# - "js" to output js code +# - "check" to check code validity + +echo "hello world" diff --git a/lib/compilers/argument-parsers.js b/lib/compilers/argument-parsers.js index 383aa2aa7..fe4e242c9 100644 --- a/lib/compilers/argument-parsers.js +++ b/lib/compilers/argument-parsers.js @@ -281,6 +281,13 @@ class RustParser extends BaseParser { } } +class NimParser extends BaseParser { + + static parse(compiler) { + return NimParser.getOptions(compiler, "-help").then(() => compiler); + } +} + module.exports = { Base: BaseParser, Clang: ClangParser, @@ -289,5 +296,6 @@ module.exports = { VC: VCParser, Pascal: PascalParser, ISPC: ISPCParser, - Rust: RustParser + Rust: RustParser, + Nim: NimParser, }; diff --git a/lib/compilers/nim.js b/lib/compilers/nim.js new file mode 100644 index 000000000..c24c8da1f --- /dev/null +++ b/lib/compilers/nim.js @@ -0,0 +1,118 @@ +// Copyright (c) 2019, Bastien Penavayre +// 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. + +const BaseCompiler = require('../base-compiler'), + _ = require('underscore'), + path = require('path'), + argumentParsers = require("./argument-parsers"), + fs = require('fs-extra'); + +class NimCompiler extends BaseCompiler { + constructor(info, env) { + super(info, env); + this.compiler.supportsIntel = true; + } + + cacheDir(outputFilename) { + return outputFilename + '.cache'; + } + + optionsForFilter(filters, outputFilename) { + return [ + "-o:" + outputFilename, //output file, only for js mode + "--nolinking", //disable linking, only compile to nimcache + "--nimcache:" + this.cacheDir(outputFilename) //output folder for the nimcache + ]; + } + + filterUserOptions(userOptions) { + return userOptions.filter(option => !['--run', '-r'].includes(option)); + } + + runCompiler(compiler, options, inputFilename, execOptions) { + //Allowed commands + const commands = [ + "compile", "compileToC", "c", + "compileToCpp", "cpp", "cc", + "compileToOC", "objc", + "js", + "check" + ]; + + //If none of the allowed commands is present in userOptions compile to C++ + if (_.intersection(options, commands).length === 0) { + options.unshift("compileToCpp"); + } + + return super.runCompiler(compiler, options, inputFilename, execOptions); + } + + postProcess(result, outputFilename, filters) { + let options = result.compilationOptions; + let setup = Promise.resolve(""); + const cacheDir = this.cacheDir(outputFilename); + const cleanup = () => fs.remove(cacheDir); + + if (_.intersection(options, ["js", "check"]).length !== 0) + filters.binary = false; + else { + filters.binary = true; + + const isC = ["compile", "compileToC", "c"], + isCpp = ["compileToCpp", "cpp", "cc"], + isObjC = ["compileToOC", "objc"]; + + let extension; + if (_.intersection(options, isC).length !== 0) + extension = '.c.o'; + else if (_.intersection(options, isCpp).length !== 0) + extension = '.cpp.o'; + else if (_.intersection(options, isObjC).length !== 0) + extension = '.m.o'; + + const moduleName = path.basename(result.inputFilename); + const resultName = moduleName + extension; + const objFile = path.join(cacheDir, resultName); + setup = fs.move(objFile, outputFilename); + } + + const postProcess = () => super.postProcess(result, outputFilename, filters); + + return setup.then(postProcess).finally(cleanup); + } + + getSharedLibraryPathsAsArguments(/*libraries*/) { + return []; + } + + getArgumentParser() { + return argumentParsers.Nim; + } + + isCfgCompiler(/*compilerVersion*/) { + return true; + } +} + +module.exports = NimCompiler; diff --git a/lib/languages.js b/lib/languages.js index 164b5055a..e75be3538 100644 --- a/lib/languages.js +++ b/lib/languages.js @@ -175,6 +175,12 @@ const languages = { monaco: 'ada', extensions: ['.adb', '.ads'], alias: [] + }, + nim: { + name: 'Nim', + monaco: 'nim', + extensions: ['.nim'], + alias: [] } }; diff --git a/static/modes/nim-mode.js b/static/modes/nim-mode.js new file mode 100644 index 000000000..a936e7100 --- /dev/null +++ b/static/modes/nim-mode.js @@ -0,0 +1,27 @@ +// Copyright (c) 2019, Matt Godbolt +// 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. +"use strict"; +var monaco = require('monaco-editor'); + +monaco.languages.register({id: 'nim'}); diff --git a/static/panes/editor.js b/static/panes/editor.js index c913275fc..f102eecd1 100644 --- a/static/panes/editor.js +++ b/static/panes/editor.js @@ -47,6 +47,7 @@ require('../modes/fortran-mode'); require('../modes/zig-mode'); require('../modes/nc-mode'); require('../modes/ada-mode'); +require('../modes/nim-mode'); require('selectize'); var loadSave = new loadSaveLib.LoadSave(); diff --git a/test/nim-tests.js b/test/nim-tests.js new file mode 100644 index 000000000..cb7628736 --- /dev/null +++ b/test/nim-tests.js @@ -0,0 +1,53 @@ +// Copyright (c) 2019, Bastien Penavayre +// 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. + +const chai = require('chai'); +const chaiAsPromised = require("chai-as-promised"); +const NimCompiler = require('../lib/compilers/nim'); +const CompilationEnvironment = require('../lib/compilation-env'); +const properties = require('../lib/properties'); + +chai.use(chaiAsPromised); +chai.should(); + +const languages = { + nim: {id: 'nim'} +}; + +const compilerProps = new properties.CompilerProps(languages, properties.fakeProps({})); + +describe('Nim', () => { + const ce = new CompilationEnvironment(compilerProps); + const info = { + exe: null, + remote: true, + lang: languages.nim.id + }; + + it('Nim should not allow --run/-r parameter', () => { + const compiler = new NimCompiler(info, ce); + compiler.filterUserOptions(["hello", "--run", "--something"]).should.deep.equal(["hello", "--something"]); + compiler.filterUserOptions(["hello", "-r", "--something"]).should.deep.equal(["hello", "--something"]); + }); +});