diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index d1ff773e4..165a77ecd 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -101,3 +101,4 @@ From oldest to newest contributor, we would like to thank: - [Shivam Gupta](https://github.com/xgupta) - [Tamir Bahar](https://github.com/tmr232) - [Daniel Below](https://github.com/DanielBelow) +- [Oleksandr Muliar](https://github.com/msdinit) diff --git a/etc/config/scala.amazon.properties b/etc/config/scala.amazon.properties new file mode 100644 index 000000000..6e7e8ae15 --- /dev/null +++ b/etc/config/scala.amazon.properties @@ -0,0 +1,26 @@ +compilers=&scala +compilerType=scala +versionFlag=-version +objdumper=/opt/compiler-explorer/jdk-16.0.1/bin/javap +instructionSet=java +defaultCompiler=scalac2136 +demangler= +postProcess= +options= +supportsBinary=false +needsMulti=false +supportsExecute=false + +group.scala.compilers=scalac2136:scalac21214:scalac300 +group.scala.groupName=Scala +group.scala.baseName=scalac +group.scala.isSemVer=true +compiler.scalac2136.exe=/opt/compiler-explorer/scala-2.13.6/bin/scalac +compiler.scalac2136.semver=2.13.6 +compiler.scalac2136.java_home=/opt/compiler-explorer/jdk-16.0.1 +compiler.scalac21214.exe=/opt/compiler-explorer/scala-2.12.14/bin/scalac +compiler.scalac21214.semver=2.12.14 +compiler.scalac21214.java_home=/opt/compiler-explorer/jdk-16.0.1 +compiler.scalac300.exe=/opt/compiler-explorer/scala3-3.0.0/bin/scalac +compiler.scalac300.semver=3.0.0 +compiler.scalac300.java_home=/opt/compiler-explorer/jdk-16.0.1 diff --git a/etc/config/scala.defaults.properties b/etc/config/scala.defaults.properties new file mode 100644 index 000000000..e754c6c84 --- /dev/null +++ b/etc/config/scala.defaults.properties @@ -0,0 +1,18 @@ +# Default settings for Scala/JVM +compilers=&scala +compilerType=scala +versionFlag=-version +objdumper=javap +instructionSet=java + +group.scala.compilers=scalacdefault +compiler.scalacdefault.exe=/usr/bin/scalac +compiler.scalacdefault.name=scalac default + +defaultCompiler=scalacdefault +demangler= +postProcess= +options= +supportsBinary=false +needsMulti=false +supportsExecute=false diff --git a/examples/scala/default.scala b/examples/scala/default.scala new file mode 100644 index 000000000..b4ca4439f --- /dev/null +++ b/examples/scala/default.scala @@ -0,0 +1,5 @@ +// Type your code here, or load an example. +object Square { + def square(num: Int): Int = + num * num +} diff --git a/lib/compilers/_all.js b/lib/compilers/_all.js index 0bfe6e25b..c72b1a417 100644 --- a/lib/compilers/_all.js +++ b/lib/compilers/_all.js @@ -59,6 +59,7 @@ export { PtxAssembler } from './ptxas'; export { PythonCompiler } from './python'; export { RustCompiler } from './rust'; export { MrustcCompiler } from './mrustc'; +export { ScalaCompiler } from './scala'; export { SdccCompiler } from './sdcc'; export { SwiftCompiler } from './swift'; export { TenDRACompiler } from './tendra'; diff --git a/lib/compilers/argument-parsers.js b/lib/compilers/argument-parsers.js index 750e9c2ef..f1be78e9d 100644 --- a/lib/compilers/argument-parsers.js +++ b/lib/compilers/argument-parsers.js @@ -185,6 +185,13 @@ export class KotlinParser extends BaseParser { } } +export class ScalaParser extends BaseParser { + static async parse(compiler) { + await ScalaParser.getOptions(compiler, '-help'); + return compiler; + } +} + export class VCParser extends BaseParser { static async parse(compiler) { await VCParser.getOptions(compiler, '/help'); diff --git a/lib/compilers/scala.js b/lib/compilers/scala.js new file mode 100644 index 000000000..a0cec3a33 --- /dev/null +++ b/lib/compilers/scala.js @@ -0,0 +1,76 @@ +// Copyright (c) 2021, 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 { ScalaParser } from './argument-parsers'; +import { JavaCompiler } from './java'; + +export class ScalaCompiler extends JavaCompiler { + static get key() { + return 'scala'; + } + + getDefaultExecOptions() { + const execOptions = super.getDefaultExecOptions(); + const javaHome = this.compilerProps(`compiler.${this.compiler.id}.java_home`); + if (javaHome) { + execOptions.env.JAVA_HOME = javaHome; + } + + return execOptions; + } + + filterUserOptions(userOptions) { + // filter options without extra arguments + userOptions = userOptions.filter(option => + option !== '-Xscript'); + + const oneArgForbiddenList = new Set([ + // -d directory + // Destination for generated class files + '-d', + ]); + + // filter options with one argument + return super.filterUserOptionsWithArg(userOptions, oneArgForbiddenList); + } + + optionsForFilter(filters) { + // Forcibly enable javap + filters.binary = true; + + const scala2Opts = [ + '-Xlint:_', + ]; + + const scala3Opts = [ + '-deprecation', + ]; + + return this.compiler.semver.startsWith('3') ? scala3Opts : scala2Opts; + } + + getArgumentParser() { + return ScalaParser; + } +} diff --git a/lib/languages.js b/lib/languages.js index bbaca8da3..d1f2e2411 100644 --- a/lib/languages.js +++ b/lib/languages.js @@ -130,6 +130,12 @@ export const languages = { extensions: ['.kt'], alias: [], }, + scala: { + name: 'Scala', + monaco: 'scala', + extensions: ['.scala'], + alias: [], + }, ocaml: { name: 'OCaml', monaco: 'ocaml', diff --git a/webpack.config.esm.js b/webpack.config.esm.js index bf1069fff..820e2dc0c 100644 --- a/webpack.config.esm.js +++ b/webpack.config.esm.js @@ -46,7 +46,7 @@ const staticPath = path.join(distPath, 'static'); const webjackJsHack = '.v4.'; const plugins = [ new MonacoEditorWebpackPlugin({ - languages: [ 'cpp', 'go', 'pascal', 'python', 'rust', 'swift', 'java', 'kotlin' ], + languages: [ 'cpp', 'go', 'pascal', 'python', 'rust', 'swift', 'java', 'kotlin', 'scala' ], filename: isDev ? '[name].worker.js' : `[name]${webjackJsHack}worker.[contenthash].js`, }), new CopyWebpackPlugin([