Add Language Support
A good place to start looking at is here: https://github.com/searleser97/cpbooster/blob/33f274c030015bb555824d5ba7a4c1b11776257a/app/src/Test/TesterFactory/TesterFactory.ts
where you will find that we have three main clases that represent compiled
, interpreted
and mixed
languages.
Interpreted
Usually, all interpreted languages have the same syntax to run a file:
interpreter filename.[extension]
e.g.
$ python filename.py
$ ruby filename.rb
$ node filname.js
...
therefore, cpbooster
should support absolutely all interpreted
languages.
The issue comes when we use either compiled
or interpreted
languages, specifically
when it comes to indicate the name for the executable (binary) file.
Compiled
Compilers like gcc
, clang
, rustc
, go
, ... use the -o
argument to indicate
the name for the executable file.
e.g.
gcc filename.cpp -o myexecutable.exe
go build filename.go -o myexecutable.exe
rustc filename.rs -o myexecutable.exe
...
However, there might exist some other compilers that do not follow this convention and they probably use a different argument, to solve this we have the following function
static getFileNameOptionForCompilerCommand(compilerCommand: string): string {
return CompiledTester.fileNameOptionForCommand.get(compilerCommand) ?? "-o";
}
which uses a Map
(hash table)
to retrieve the correct argument name depending on the compiler command (gcc
, g++
, csc
, go
, ...),
if the compiler does not exist in the hash table (Map
) it defaults to the -o
argument name.
private static fileNameOptionForCommand: Map<string, string> = new Map([
[NonStandardCompilers.mcs, "-out:"], // csharp compiler
[NonStandardCompilers.csc, "/out:"] // csharp compiler
]);
notice that in the hash table (Map
) we just have msc
and csc
which are C#
compilers, this is because
all the tested languages except for C#
use the -o
argument therefore there is no need to insert them into the hash table.
Now let's actually talk about C#
compilers and how they conflict with the standard format. It turns out that these compilers
not just use a different argument name to sepecify the executable name, but they also force us to write the name of the executable
together with the argument name (i.e. not separated by a space)
e.g.
mcs -out:myexecutable.exe filename.cs
csc /out:myexecutable.exe filename.cs
to solve this when we compile we have an special condition, which basically checks if the compiler is NOT standard (i.e. csc
and mcs
)
then join/concatenate the argument name with the executable name.
if (Object.keys(NonStandardCompilers).includes(compilerCommand)) {
args.push(
CompiledTester.getFileNameOptionForCompilerCommand(compilerCommand) +
this.getDefaultExecutableFileName(debug)
);
} else {
args.push(
CompiledTester.getFileNameOptionForCompilerCommand(compilerCommand),
this.getDefaultExecutableFileName(debug)
);
}
export enum NonStandardCompilers {
mcs = "mcs",
csc = "csc",
}
Mixed
mixed
languages are the ones that are compiled with one command but executed with another one (not counting ./executable.exe
format as command)
e.g. programs written in Java
are compiled using the javac
command and then executed using the java
command, something similar
happens with languages like Kotlin
and Scala
.
Usually, these languages generate a .class
file after compilation, this .class
file usually has the same name as the source file name or
the same name as the class
declared inside it. cpbooster
takes advantage of this behavior and therefore, no extra code is written to name
the executables (.class
files), except for kotlin
which adds Kt
to the executable name, we have that case covered with a simple if
condition here:
getExecutableFileName(): string {
return `${this.getExecutableFileNameNoExtension()}${
this.langExtension === LangExtensions.kotlin ? "Kt" : ""
}.class`;
}
Currently, to guarantee the correct behavior of cpbooster
, the class
name should match with the source file name, since
some languages use the class
name as the executable (.class
) name instead of the source file name.
Which leads to a possible contribution related with the "templates" for languages that require the declaration of a class.
We can add the concept of cpbooster-variables
which will be formatted strings that will get replaced with some information,
like filename or date, etc
e.g.
template.java
/**
* Date Time: $${DateTime}$$
*/
import java.util.*;
public class $${FileName}$$ <-- just a suggested syntax not sure if its the best
{
public static void main(String[] args)
{
}
}
then if we create a file ProblemC.java
with cpbooster
the file will look like this:
/**
* DateTime: 13-07-2022 13:30 <-- $${DateTime}$$ was replaced with the "current" date time
*/
import java.util.*;
public class ProblemC <-- $${FileName}$$ was replaced with ProblemC
{
public static void main(String[] args)
{
}
}
one thing to note here is that we will also need to force the file name to have the first letter capitalized (in uppercase),
since some mixed
languages do not allow to create classes that do not have the first letter in uppercase.