blob: f77ba783a7c482c4e96fc68b7c111ff7a574a1e4 [file] [log] [blame] [raw]
J. Ryan Stinnett80dd7632022-10-05 08:32:45 +01001// Copyright (c) 2022, Compiler Explorer Authors
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6//
7// * Redistributions of source code must retain the above copyright notice,
8// this list of conditions and the following disclaimer.
9// * Redistributions in binary form must reproduce the above copyright
10// notice, this list of conditions and the following disclaimer in the
11// documentation and/or other materials provided with the distribution.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
17// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23// POSSIBILITY OF SUCH DAMAGE.
24
25import path from 'path';
26
27import {CompilationResult, ExecutionOptions} from '../../types/compilation/compilation.interfaces';
Marc Poulhiès2fa2bbb2022-11-28 21:37:15 +010028import {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces';
J. Ryan Stinnett80dd7632022-10-05 08:32:45 +010029import {BaseCompiler} from '../base-compiler';
30import {logger} from '../logger';
31
32export class RacketCompiler extends BaseCompiler {
33 private raco: string;
34
35 static get key() {
36 return 'racket';
37 }
38
39 constructor(info, env) {
40 // Disable output filters, as they currently don't do anything
41 if (!info.disabledFilters) {
42 info.disabledFilters = ['labels', 'directives', 'commentOnly', 'trim'];
43 }
44 super(info, env);
Jeremy Rifkine13fe4a2022-11-26 13:56:04 -050045 this.raco = this.compilerProps<string>(`compiler.${this.compiler.id}.raco`);
J. Ryan Stinnett80dd7632022-10-05 08:32:45 +010046 }
47
Marc Poulhiès2fa2bbb2022-11-28 21:37:15 +010048 override optionsForFilter(
49 filters: ParseFiltersAndOutputOptions,
50 outputFilename: string,
51 userOptions?: string[],
52 ): string[] {
J. Ryan Stinnett80dd7632022-10-05 08:32:45 +010053 // We currently always compile to bytecode first and then decompile.
54 // Forcing `binary` on like this ensures `objdump` will be called for
55 // the decompilation phase.
56 filters.binary = true;
57
58 return [];
59 }
60
61 override supportsObjdump(): boolean {
62 return true;
63 }
64
65 override getSharedLibraryPathsAsArguments(libraries: object[], libDownloadPath?: string): string[] {
66 return [];
67 }
68
69 override async runCompiler(
70 compiler: string,
71 options: string[],
72 inputFilename: string,
73 execOptions: ExecutionOptions,
74 ): Promise<CompilationResult> {
75 if (!execOptions) {
76 execOptions = this.getDefaultExecOptions();
77 }
78
79 if (!execOptions.customCwd) {
80 execOptions.customCwd = path.dirname(inputFilename);
81 }
82
83 // Compile to bytecode via `raco make`
84 options.unshift('make');
85 const makeResult = await this.exec(this.raco, options, execOptions);
86
87 return this.transformToCompilationResult(makeResult, inputFilename);
88 }
89
90 override getOutputFilename(dirPath: string, outputFilebase: string, key?: any): string {
91 return path.join(dirPath, 'compiled', `${this.compileFilename.replace('.', '_')}.zo`);
92 }
93
94 override async objdump(
95 outputFilename: any,
96 result: any,
97 maxSize: number,
98 intelAsm: any,
99 demangle: any,
Marc Poulhiès2fa2bbb2022-11-28 21:37:15 +0100100 filters: ParseFiltersAndOutputOptions,
J. Ryan Stinnett80dd7632022-10-05 08:32:45 +0100101 ): Promise<any> {
102 // Decompile to assembly via `raco decompile` with `disassemble` package
103 const execOptions: ExecutionOptions = {
104 maxOutput: maxSize,
105 customCwd: (result.dirPath as string) || path.dirname(outputFilename),
106 };
107 const decompileResult = await this.exec(this.raco, ['decompile', outputFilename], execOptions);
108
109 if (decompileResult.code) {
110 logger.error('Error decompiling via `raco decompile`', decompileResult);
111 result.asm = `<No output: \`raco decompile\` returned ${decompileResult.code}>`;
112 }
113
114 result.objdumpTime = decompileResult.execTime;
115 result.asm = this.postProcessObjdumpOutput(decompileResult.stdout);
116
117 return result;
118 }
119
120 override processAsm(result: any, filters: any, options: any) {
121 // TODO: Process and highlight decompiled output
122 return {
123 asm: [{text: result.asm}],
124 };
125 }
126}