blob: a7fd8d8224063e4e76509a3a5141a9ae75d7aee1 [file] [log] [blame] [raw]
RabsRincon6ef87b52018-02-27 14:58:21 +01001// Copyright (c) 2017, Jared Wyles
jaredwy13cd0fd2017-07-03 17:42:27 +10002// 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
Austin Morton044dcfb2020-09-26 16:59:26 -040025import _ from 'underscore';
jaredwy13cd0fd2017-07-03 17:42:27 +100026
Austin Morton044dcfb2020-09-26 16:59:26 -040027import { logger } from '../logger';
28import * as utils from '../utils';
29
30export class BaseParser {
Partouf96e8d722018-11-10 01:05:11 +010031 static hasSupport(options, forOption) {
32 return _.keys(options).find(option => option.includes(forOption));
33 }
34
35 static parseLines(stdout, optionRegex) {
36 let previousOption = false;
37 let options = {};
38
39 utils.eachLine(stdout, line => {
40 const match = line.match(optionRegex);
41 if (!match) {
Matt Godbolta4659622021-05-27 23:17:13 -050042 if (previousOption && (line.trim().length > 0)) {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +020043 if (options[previousOption].description.endsWith('-'))
Partouf96e8d722018-11-10 01:05:11 +010044 options[previousOption].description += line.trim();
45 else {
Matt Godbolta4659622021-05-27 23:17:13 -050046 if (options[previousOption].description.length > 0)
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +020047 options[previousOption].description += ' ' + line.trim();
Partouf96e8d722018-11-10 01:05:11 +010048 else
49 options[previousOption].description = line.trim();
50 }
51 } else {
52 previousOption = false;
53 }
54 return;
55 }
56
57 if (match) previousOption = match[1];
58 if (previousOption) {
59 options[previousOption] = {
60 description: match[2].trim(),
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +020061 timesused: 0,
Partouf96e8d722018-11-10 01:05:11 +010062 };
63 }
64 });
65
66 return options;
67 }
68
Matt Godbolt03a3fb32020-01-14 22:37:58 -060069 static async getOptions(compiler, helpArg) {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +020070 const optionFinder = /^\s*(--?[\d+,<=>[\]a-z|-]*)\s*(.*)/i;
Matt Godbolt03a3fb32020-01-14 22:37:58 -060071 const result = await compiler.execCompilerCached(compiler.compiler.exe, [helpArg]);
72 const options = result.code === 0
73 ? BaseParser.parseLines(result.stdout + result.stderr, optionFinder) : {};
74 compiler.possibleArguments.populateOptions(options);
75 return options;
RabsRincona54faef2018-01-18 19:43:10 +010076 }
RabsRincond493dfb2018-01-18 19:46:02 +010077
RabsRincona54faef2018-01-18 19:43:10 +010078 static parse(compiler) {
79 return compiler;
80 }
81}
Matt Godbolt6e7e30b2017-12-19 10:15:17 -060082
Austin Morton044dcfb2020-09-26 16:59:26 -040083export class GCCParser extends BaseParser {
Matt Godbolt03a3fb32020-01-14 22:37:58 -060084 static async parse(compiler) {
85 const results = await Promise.all([
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +020086 GCCParser.getOptions(compiler, '-fsyntax-only --target-help'),
87 GCCParser.getOptions(compiler, '-fsyntax-only --help=common'),
88 GCCParser.getOptions(compiler, '-fsyntax-only --help=optimizers'),
Matt Godbolt03a3fb32020-01-14 22:37:58 -060089 ]);
90 const options = Object.assign({}, ...results);
91 const keys = _.keys(options);
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +020092 logger.debug(`gcc-like compiler options: ${keys.join(' ')}`);
93 if (BaseParser.hasSupport(options, '-masm=')) {
Iain Buclaw91297042020-06-08 12:47:44 +020094 // -masm= may be available but unsupported by the compiler.
Austin Mortona16013a2020-10-16 13:24:40 -040095 const res = await compiler.execCompilerCached(compiler.compiler.exe,
96 ['-fsyntax-only', '--target-help', '-masm=intel']);
Austin Morton044dcfb2020-09-26 16:59:26 -040097 if (res.code === 0) {
98 compiler.compiler.intelAsm = '-masm=intel';
99 compiler.compiler.supportsIntel = true;
100 }
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600101 }
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200102 if (BaseParser.hasSupport(options, '-fdiagnostics-color')) {
103 if (compiler.compiler.options) compiler.compiler.options += ' ';
104 compiler.compiler.options += '-fdiagnostics-color=always';
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600105 }
106 // This check is not infallible, but takes care of Rust and Swift being picked up :)
107 if (_.find(keys, key => key.startsWith('-fdump-'))) {
108 compiler.compiler.supportsGccDump = true;
109 }
110 return compiler;
RabsRincona54faef2018-01-18 19:43:10 +0100111 }
Iain Buclaw91297042020-06-08 12:47:44 +0200112
113 static async getOptions(compiler, helpArg) {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200114 const optionFinder = /^\s*(--?[\d+,<=>[\]a-z|-]*)\s*(.*)/i;
Iain Buclaw91297042020-06-08 12:47:44 +0200115 const result = await compiler.execCompilerCached(compiler.compiler.exe, helpArg.split(' '));
116 const options = result.code === 0
117 ? BaseParser.parseLines(result.stdout + result.stderr, optionFinder) : {};
118 compiler.possibleArguments.populateOptions(options);
119 return options;
120 }
RabsRincona54faef2018-01-18 19:43:10 +0100121}
jaredwy13cd0fd2017-07-03 17:42:27 +1000122
Austin Morton044dcfb2020-09-26 16:59:26 -0400123export class ClangParser extends BaseParser {
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600124 static async parse(compiler) {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200125 const options = await ClangParser.getOptions(compiler, '--help');
126 logger.debug(`clang-like compiler options: ${_.keys(options).join(' ')}`);
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600127 if (BaseParser.hasSupport(options, '-fsave-optimization-record')) {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200128 compiler.compiler.optArg = '-fsave-optimization-record';
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600129 compiler.compiler.supportsOptOutput = true;
130 }
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200131 if (BaseParser.hasSupport(options, '-fcolor-diagnostics')) {
132 if (compiler.compiler.options) compiler.compiler.options += ' ';
133 compiler.compiler.options += '-fcolor-diagnostics';
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600134 }
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200135 if (BaseParser.hasSupport(options, '-emit-llvm')) {
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600136 compiler.compiler.supportsIrView = true;
137 compiler.compiler.irArg = ['-Xclang', '-emit-llvm', '-fsyntax-only'];
138 }
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200139 if (BaseParser.hasSupport(options, '-fno-crash-diagnostics')) {
140 if (compiler.compiler.options) compiler.compiler.options += ' ';
141 compiler.compiler.options += '-fno-crash-diagnostics';
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600142 }
143 return compiler;
RabsRincona54faef2018-01-18 19:43:10 +0100144 }
145}
jaredwy13cd0fd2017-07-03 17:42:27 +1000146
Austin Morton044dcfb2020-09-26 16:59:26 -0400147export class PascalParser extends BaseParser {
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600148 static async parse(compiler) {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200149 await PascalParser.getOptions(compiler, '-help');
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600150 return compiler;
Partoufe892d352019-01-08 03:20:30 +0100151 }
152}
153
Austin Morton044dcfb2020-09-26 16:59:26 -0400154export class ISPCParser extends BaseParser {
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600155 static async parse(compiler) {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200156 const options = await ISPCParser.getOptions(compiler, '--help');
157 if (BaseParser.hasSupport(options, '--x86-asm-syntax')) {
158 compiler.compiler.intelAsm = '--x86-asm-syntax=intel';
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600159 compiler.compiler.supportsIntel = true;
160 }
161 return compiler;
Partoufe892d352019-01-08 03:20:30 +0100162 }
163
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600164 static async getOptions(compiler, helpArg) {
165 const result = await compiler.execCompilerCached(compiler.compiler.exe, [helpArg]);
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200166 const optionFinder = /^\s*\[(--?[\d\s()+,/<=>a-z{|}-]*)]\s*(.*)/i;
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600167 const options = result.code === 0
168 ? BaseParser.parseLines(result.stdout + result.stderr, optionFinder) : {};
169 compiler.possibleArguments.populateOptions(options);
170 return options;
Partoufe892d352019-01-08 03:20:30 +0100171 }
172}
173
Austin Morton044dcfb2020-09-26 16:59:26 -0400174export class JavaParser extends BaseParser {
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600175 static async parse(compiler) {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200176 await JavaParser.getOptions(compiler, '-help');
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600177 return compiler;
Christian Vonrüti92914a72019-05-26 19:16:14 +0200178 }
179}
180
Daniel Belowb4ebb472021-06-02 22:58:41 +0200181export class KotlinParser extends BaseParser {
182 static async parse(compiler) {
183 await KotlinParser.getOptions(compiler, '-help');
184 return compiler;
185 }
186}
187
Oleksandrd1da1482021-06-29 10:39:06 +0300188export class ScalaParser extends BaseParser {
189 static async parse(compiler) {
190 await ScalaParser.getOptions(compiler, '-help');
191 return compiler;
192 }
193}
194
Austin Morton044dcfb2020-09-26 16:59:26 -0400195export class VCParser extends BaseParser {
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600196 static async parse(compiler) {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200197 await VCParser.getOptions(compiler, '/help');
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600198 return compiler;
Partouf96e8d722018-11-10 01:05:11 +0100199 }
200
201 static parseLines(stdout, optionRegex) {
202 let previousOption = false;
203 let options = {};
204
205 const matchLine = (line) => {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200206 if (line.startsWith('/?')) return;
Partouf96e8d722018-11-10 01:05:11 +0100207
208 const match = line.match(optionRegex);
209 if (!match) {
Matt Godbolta4659622021-05-27 23:17:13 -0500210 if (previousOption && (line.trim().length > 0)) {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200211 if (options[previousOption].description.endsWith(':'))
212 options[previousOption].description += ' ' + line.trim();
Partouf96e8d722018-11-10 01:05:11 +0100213 else {
Matt Godbolta4659622021-05-27 23:17:13 -0500214 if (options[previousOption].description.length > 0)
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200215 options[previousOption].description += ', ' + line.trim();
Partouf96e8d722018-11-10 01:05:11 +0100216 else
217 options[previousOption].description = line.trim();
218 }
219 } else {
220 previousOption = false;
221 }
222 return;
223 }
224
225 if (match) previousOption = match[1];
226 if (previousOption) {
227 options[previousOption] = {
228 description: match[2].trim(),
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200229 timesused: 0,
Partouf96e8d722018-11-10 01:05:11 +0100230 };
231 }
232 };
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600233
Partouf96e8d722018-11-10 01:05:11 +0100234 utils.eachLine(stdout, line => {
235 if (line.length === 0) return;
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200236 if (line.includes('C/C++ COMPILER OPTIONS')) return;
Matt Godbolt4e36d202021-05-27 23:19:32 -0500237 if (/^\s+-.*-$/.test(line)) return;
Partouf96e8d722018-11-10 01:05:11 +0100238
239 let col1;
240 let col2;
241 if ((line.length > 39) && (line[40] === '/')) {
242 col1 = line.substr(0, 39);
243 col2 = line.substr(40);
244 } else {
245 col1 = line;
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200246 col2 = '';
Partouf96e8d722018-11-10 01:05:11 +0100247 }
248
249 if (col1) matchLine(col1);
250 if (col2) matchLine(col2);
251 });
252
253 return options;
254 }
255
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600256 static async getOptions(compiler, helpArg) {
257 const result = await compiler.execCompilerCached(compiler.compiler.exe, [helpArg]);
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200258 const optionFinder = /^\s*(\/[\w#+,.:<=>[\]{|}-]*)\s*(.*)/i;
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600259 const options = result.code === 0
260 ? this.parseLines(result.stdout, optionFinder) : {};
261 compiler.possibleArguments.populateOptions(options);
262 return options;
jaredwy13cd0fd2017-07-03 17:42:27 +1000263 }
264}
265
Austin Morton044dcfb2020-09-26 16:59:26 -0400266export class RustParser extends BaseParser {
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600267 static async parse(compiler) {
268 const results = await Promise.all([
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200269 RustParser.getOptions(compiler, '--help'),
270 RustParser.getOptions(compiler, '-C help'),
271 RustParser.getOptions(compiler, '--help -v'),
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600272 ]);
273 const options = Object.assign({}, ...results);
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200274 if (BaseParser.hasSupport(options, '--color')) {
275 if (compiler.compiler.options) compiler.compiler.options += ' ';
276 compiler.compiler.options += '--color=always';
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600277 }
278 return compiler;
Partouffb286bd2019-08-08 17:19:20 +0200279 }
280
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600281 static async getOptions(compiler, helpArg) {
282 const result = await compiler.execCompilerCached(compiler.compiler.exe, helpArg.split(' '));
283 let options = {};
284 if (result.code === 0) {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200285 if (helpArg === '-C help') {
286 const optionFinder = /^\s*(-c\s*[\d=a-z-]*)\s--\s(.*)/i;
Partouffb286bd2019-08-08 17:19:20 +0200287
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600288 options = BaseParser.parseLines(result.stdout + result.stderr, optionFinder);
289 } else {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200290 const optionFinder = /^\s*(--?[\d+,<=>[\]a-z|-]*)\s*(.*)/i;
Partouffb286bd2019-08-08 17:19:20 +0200291
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600292 options = BaseParser.parseLines(result.stdout + result.stderr, optionFinder);
Partouffb286bd2019-08-08 17:19:20 +0200293 }
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600294 }
295 compiler.possibleArguments.populateOptions(options);
296 return options;
Partouffb286bd2019-08-08 17:19:20 +0200297 }
298}
299
Marc Poulhièsb283b7e2021-05-27 21:51:33 +0200300export class MrustcParser extends BaseParser {
301 static async parse(compiler) {
302 await MrustcParser.getOptions(compiler, '--help');
303 return compiler;
304 }
305}
306
Austin Morton044dcfb2020-09-26 16:59:26 -0400307export class NimParser extends BaseParser {
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600308 static async parse(compiler) {
Rubén Rincón Blancoccff4b92020-08-04 22:39:02 +0200309 await NimParser.getOptions(compiler, '-help');
Matt Godbolt03a3fb32020-01-14 22:37:58 -0600310 return compiler;
bastien penavayre34922872019-12-24 13:33:11 +0100311 }
312}
Quinton Miller94ecb092021-07-08 06:23:48 +0800313
314export class CrystalParser extends BaseParser {
315 static async parse(compiler) {
316 await CrystalParser.getOptions(compiler, 'build');
317 return compiler;
318 }
319}