Exemple #1
0
class LLVMAsm(Lang):
    source_ext = '.ll'
    compiler = Program(
        'clang-8',
        opts=[  # Statically compile the program.
            '-x',
            'ir',  # Force the target language to be LLVM AS.
            '-Wno-override-module'  # Because the source file might lack the target module,
            # we don't want clang to complain about it.
        ])
    interpreter = Program('lli-8')  # JIT compiler.
    reference_source = r"""
Exemple #2
0
class BrainfuckToC(Lang, register=False):
    source_ext = '.bf'
    extra_binaries = {'esotope': Program('esotope-bfc', version_opt=None)}
    compiler = Program('python2',
                       env={'PYTHONPATH': '/usr/lib/python2.7/site-packages'},
                       opts=['-S', extra_binaries['esotope'].cmd, '-v', '-fc'])

    def compile_opt_out(self, output):
        # there is no way to specify an output file, use stderr
        return []

    def read_compiled(self, path, isolator):
        return isolator.stdout.encode()
Exemple #3
0
class VisualBasic(Lang):
    source_ext = '.vb'
    compiler = Program('vbnc', opts=['/optimize+'], version_opt='/help')
    interpreter = Program('mono')
    reference_source = r'''
Imports System
Public Module modmain
Sub Main()
    Console.WriteLine ("42")
End Sub
End Module
'''

    def compile_opt_out(self, output):
        return ['/out:' + output]
Exemple #4
0
class CSharp(Lang, name="C#"):
    source_ext = '.cs'
    compiler = Program('mcs', opts=['-optimize+'])
    interpreter = Program('mono')
    reference_source = r'''
using System;
class Program
{
    public static void Main()
    {
        Console.WriteLine(42);
    }
}
'''

    def compile_opt_out(self, output):
        return ['-out:' + output]
class Copy(Lang, register=False):
    source_ext = '.a'
    compiler = Program('cp')

    def compile_command(self, source, output):
        return [
            self.compiler.cmd,
            self.filter_box_prefix(source),
            self.filter_box_prefix(output)
        ]
Exemple #6
0
class Pascal(Lang):
    source_ext = '.pas'
    compiler = Program('fpc',
                       opts=['-XD', '-Fainitc'],
                       version_opt='-h',
                       version_lines=1)
    reference_source = r'''
program main;
begin
    Writeln(42);
end.
'''

    def compile_opt_out(self, output):
        return ['-o' + output]
Exemple #7
0
class D(Lang):
    source_ext = '.d'
    compiler = Program('dmd')
    allowed_dirs = ['/etc']
    reference_source = r'''
void main()
{
    import std.stdio: writeln;
    writeln("42");
}
'''

    def compile_opt_out(self, output):
        # '-of' and its value as two distinct arguments is illegal (go figure)
        return ['-of' + output]
Exemple #8
0
def test_version():
    v = Program('cp').version()
    assert '.' in v
Exemple #9
0
def test_no_version():
    echo = Program('echo', version_opt=None)
    assert echo._version() is None
    assert echo.long_version() is None
    assert echo.long_version() is None
Exemple #10
0
class Prolog(Lang):
    source_ext = '.pl'
    interpreter = Program('swipl',
                          opts=['--quiet', '-t', 'halt'],
                          version_opt='--version')
    reference_source = r":- write('42\n')."
Exemple #11
0
class Haskell(Lang):
    source_ext = '.hs'
    compiler = Program('ghc', opts=['-dynamic', '-O2'])
    reference_source = r'module Main where main = putStrLn "42"'
Exemple #12
0
class Lua(Lang):
    source_ext = '.lua'
    interpreter = Program('luajit', version_opt='-v')
    reference_source = r'print("42")'
Exemple #13
0
class Perl(Lang):
    source_ext = '.pl'
    interpreter = Program('perl')
    reference_source = r'print "42\n";'
class BadCompiler(Lang, register=False):
    source_ext = '.a'
    compiler = Program('sh', opts=['-c', 'echo BadCompiler is bad >&2'])

    def compile_command(self, source, output):
        return [self.compiler.cmd, *self.compiler.opts]
Exemple #15
0
class Ada(Lang):
    source_ext = '.adb'
    compiler = Program('gnatmake', opts=['-f'])
    reference_source = r'''
Exemple #16
0
class Ruby(Lang):
    source_ext = '.rb'
    interpreter = Program('ruby')
    reference_source = r'puts "42"'
Exemple #17
0
class OCaml(Lang):
    source_ext = '.ml'
    compiler = Program('ocamlopt', opts=['-w', 'A'], version_opt='-v')
    reference_source = r'print_int 42; print_string "\n";'
Exemple #18
0
class Go(Lang):
    source_ext = '.go'
    compiler = Program('go',
                       opts=['build', '-buildmode=exe'],
                       version_opt='version')
    reference_source = r'''
Exemple #19
0
class InterpretedLang(Lang):
    interpreter = Program('echo')
Exemple #20
0
class CompiledLang(Lang):
    compiler = Program('echo')
Exemple #21
0
def test_long_version():
    v = Program('cp').long_version()
    assert v.startswith('cp')
Exemple #22
0
class C(Lang):
    source_ext = '.c'
    compiler = Program('gcc',
                       opts=['-std=c11', '-Wall', '-Wextra', '-O2', '-lm'])
    reference_source = r'''
Exemple #23
0
class Rust(Lang):
    source_ext = '.rs'
    compiler = Program('rustc', opts=['-W', 'warnings', '-O'])
    reference_source = r'fn main() { println!("42"); }'
Exemple #24
0
class Go(Lang):
    source_ext = '.go'
    compiler = Program('go', opts=['build', '-buildmode=exe'],
                       version_opt='version',
                       env={'GOCACHE':'/box/.gocache'})
    reference_source = r'''
Exemple #25
0
class Rust(Lang):
    source_ext = '.rs'
    compiler = Program('rustc', opts=['-W', 'warnings', '-O'])
    reference_source = r'''\
Exemple #26
0
class CXX(Lang, name="C++"):
    source_ext = '.cc'
    compiler = Program('g++', opts=['-std=c++17', '-Wall', '-Wextra', '-O2'])
    reference_source = r'''
Exemple #27
0
class Java(Lang):
    source_ext = '.java'
    compiled_ext = '.class'
    compiler = Program('javac', opts=['-encoding', 'UTF-8'],
                       env={'LANG': 'en_US.UTF-8'}, version_opt='-version')
    interpreter = Program('java', version_opt='-version')
    # /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/jvm.cfg links to
    # /etc/java-8-openjdk/amd64/jvm.cfg
    allowed_dirs = ['/etc/java-8-openjdk']
    # ensure we can parse the javac(1) stderr
    extra_binaries = {'disassembler': Program('javap', version_opt='-version')}
    reference_source = '''
class MyπClass {
    static int fortytwo() {
        return 42;
    }
    static class Subclassé {
        public static void main(String notMe) {}
        final static public void main(String args[]) {
           System.out.println(MyπClass.fortytwo());
        }
    }
}
'''

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # use an illegal class name so that javac(1) will spit out the actual
        # class named used in the source
        self.class_name = '1337'
        # we give priority to the public class, if any, so keep a flag if we
        # found such a public class
        self.found_public = False

        # Don't even try to cgroup the java process:
        # http://stackoverflow.com/questions/19910468
        # https://bugs.launchpad.net/ubuntu/+source/openjdk-7/+bug/1241926
        # https://bugs.openjdk.java.net/browse/JDK-8071445
        # http://bugs.java.com/view_bug.do?bug_id=8043516
        # Instead, pass the memory limit as the maximum heap size of the
        # runtime.
        try:
            self.heapsize = self.opts['execute'].pop('mem')
        except KeyError:
            self.heapsize = None

    def compile_opt_out(self, output):
        # javac has no output directive, file name is class name
        return []

    async def compile(self):
        # try to compile with default class name (Main)
        retcode, info, binary = await super().compile()
        if retcode != 0:
            # error: public class name is not '1337' as it's an illegal name,
            # so find what it actually is
            try:
                javac_stderr = info['stderr'].decode()
            except UnicodeDecodeError:  # noqa
                raise RuntimeError(
                    "could not decode javac stderr to find class name")
            match = RE_WRONG_FILENAME_ERROR.search(javac_stderr)
            if match:
                self.found_public = True
                self.class_name = match.group(1)
                # retry with new name
                retcode, info, binary = await super().compile()
        return (retcode, info, binary)

    def source_filename(self):
        return self.class_name + self.source_ext

    def execute_filename(self):
        # return eg. Main.class
        return self.class_name + self.compiled_ext

    def execute_command(self, output):
        cmd = [self.interpreter.cmd] + self.interpreter.opts

        # Use the memory limit as a maximum heap size
        if self.heapsize is not None:
            cmd.append(f'-Xmx{self.heapsize}k')

        # foo/Bar.class is run with $ java -cp foo Bar
        cmd += ['-cp', str(Path(self.filter_box_prefix(output)).parent),
                self.class_name]
        return cmd

    def find_class_having_main(self, classes):
        for file in classes:
            # run javap(1) with type signatures
            try:
                stdout = subprocess.check_output(
                    [self.extra_binaries['disassembler'].cmd, '-s', str(file)],
                    stderr=subprocess.DEVNULL, env=self.compiler.env)
            except subprocess.SubprocessError:  # noqa
                continue
            # iterate on lines to find p s v main() signature and then
            # its descriptor on the line below; we don't rely on the type
            # from the signature, because it could be String[], String... or
            # some other syntax I'm not even aware of
            lines = iter(stdout.decode().split('\n'))
            for line in lines:
                line = line.lstrip()
                if line.startswith('public static') and 'void main(' in line:
                    if next(lines).lstrip() == PSVMAIN_DESCRIPTOR:
                        return file.stem

    def read_compiled(self, path, isolator):
        # in case of multiple or nested classes, multiple .class files are
        # generated by javac
        classes = list(isolator.path.glob('*.class'))
        files = [(file.name, file.open('rb').read()) for file in classes]
        if not self.found_public:
            # the main() may be anywhere, so run javap(1) on all .class
            new_class_name = self.find_class_having_main(classes)
            if new_class_name:
                self.class_name = new_class_name
        return files

    def write_binary(self, path, binary):
        # see read_compiled(), we need to write back all .class files
        # but give only the main class name (execute_filename()) to java(1)
        for file, data in binary:
            with (path / file).open('wb') as c:
                c.write(data)
        return path / self.execute_filename()
Exemple #28
0
class PHP(Lang):
    source_ext = '.php'
    interpreter = Program('php')
    reference_source = r'<?php echo "42\n";'
Exemple #29
0
class Python(Lang):
    source_ext = '.py'
    interpreter = Program('python3', opts=['-S'])
    reference_source = r'print("42")'
Exemple #30
0
class Javascript(Lang):
    source_ext = '.js'
    interpreter = Program('node')
    reference_source = r"process.stdout.write('42\n');"