blob: b12bf0329b986fe8a8bcd9adc2dae72eb0c12ab1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015-2020 Martin Weber.
*
* Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 "EPL".
* A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.jsoncdb.core.participant;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.cdt.jsoncdb.core.participant.IArglet.IArgumentCollector;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
/**
* Various Arglet implementation for parsing tool arguments.
*
* @author Martin Weber
*/
public final class Arglets {
private static final String EMPTY_STR = ""; //$NON-NLS-1$
/** matches a macro name, with optional macro parameter list */
@SuppressWarnings("nls")
private static final String REGEX_MACRO_NAME = "([\\w$]+)(?:\\([\\w$, ]*?\\))?";
/**
* matches a macro name, skipping leading whitespace. Name in matcher group 1
*/
@SuppressWarnings("nls")
private static final String REGEX_MACRO_NAME_SKIP_LEADING_WS = "\\s*" + REGEX_MACRO_NAME;
/**
* matches a macro argument in quotes, skipping leading whitespace. Quote
* character in matcher group 1, Name in matcher group 2
*/
@SuppressWarnings("nls")
private static final String REGEX_MACRO_ARG_QUOTED__SKIP_LEADING_WS = "\\s*([\"'])" + REGEX_MACRO_NAME;
/** matches an include path with quoted directory. Name in matcher group 2 */
@SuppressWarnings("nls")
private static final String REGEX_INCLUDEPATH_QUOTED_DIR = "\\s*([\"'])(.+?)\\1";
/**
* matches an include path with unquoted directory. Name in matcher group 1
*/
@SuppressWarnings("nls")
private static final String REGEX_INCLUDEPATH_UNQUOTED_DIR = "\\s*([^\\s]+)";
/**
* nothing to instantiate
*/
private Arglets() {
}
////////////////////////////////////////////////////////////////////
// Matchers for options
////////////////////////////////////////////////////////////////////
/**
* A matcher for option names. Includes information of the matcher groups that
* hold the option name.
*
* @author Martin Weber
*/
public static class NameOptionMatcher {
final Matcher matcher;
final int nameGroup;
/**
* Constructor.
*
* @param pattern - regular expression pattern being parsed by the parser.
* @param nameGroup - capturing group number defining name of an entry.
*/
public NameOptionMatcher(String pattern, int nameGroup) {
this.matcher = Pattern.compile(pattern).matcher(EMPTY_STR);
this.nameGroup = nameGroup;
}
@SuppressWarnings("nls")
@Override
public String toString() {
return "NameOptionMatcher [matcher=" + this.matcher + ", nameGroup=" + this.nameGroup + "]";
}
}
/**
* A matcher for preprocessor define options. Includes information of the
* matcher groups that hold the macro name and value.
*
* @author Martin Weber
*/
public static class NameValueOptionMatcher extends NameOptionMatcher {
/**
* the number of the value group, or {@code -1} for a pattern that does not
* recognize a macro value
*/
private final int valueGroup;
/**
* Constructor.
*
* @param pattern - regular expression pattern being parsed by the parser.
* @param nameGroup - capturing group number defining name of an entry.
* @param valueGroup - capturing group number defining value of an entry.
*/
/**
* @param pattern
* @param nameGroup
* @param valueGroup the number of the value group, or {@code -1} for a pattern
* that does not recognize a macro value
*/
public NameValueOptionMatcher(String pattern, int nameGroup, int valueGroup) {
super(pattern, nameGroup);
this.valueGroup = valueGroup;
}
@SuppressWarnings("nls")
@Override
public String toString() {
return "NameValueOptionMatcher [matcher=" + this.matcher + ", nameGroup=" + this.nameGroup + ", valueGroup="
+ this.valueGroup + "]";
}
}
////////////////////////////////////////////////////////////////////
// generic option parsers
////////////////////////////////////////////////////////////////////
/**
* A tool argument parser capable to parse a C-compiler macro definition
* argument.
*/
public static abstract class MacroDefineGeneric {
protected final int processArgument(IArgumentCollector resultCollector, String args,
NameValueOptionMatcher[] optionMatchers) {
for (NameValueOptionMatcher oMatcher : optionMatchers) {
final Matcher matcher = oMatcher.matcher;
matcher.reset(args);
if (matcher.lookingAt()) {
final String name = matcher.group(oMatcher.nameGroup);
final String value = oMatcher.valueGroup == -1 ? null : matcher.group(oMatcher.valueGroup);
resultCollector.addDefine(name, value);
final int end = matcher.end();
return end;
}
}
return 0;// no input consumed
}
}
/**
* A tool argument parser capable to parse a C-compiler macro cancel argument.
*/
public static class MacroUndefineGeneric {
/*-
* @see org.eclipse.cdt.jsoncdb.IArglet#processArgument(java.util.List, java.lang.String)
*/
protected final int processArgument(IArgumentCollector resultCollector, String argsLine,
NameOptionMatcher optionMatcher) {
final Matcher oMatcher = optionMatcher.matcher;
oMatcher.reset(argsLine);
if (oMatcher.lookingAt()) {
final String name = oMatcher.group(1);
resultCollector.addUndefine(name);
final int end = oMatcher.end();
return end;
}
return 0;// no input consumed
}
}
/**
* A tool argument parser capable to parse a C-compiler include path argument.
*/
public static abstract class IncludePathGeneric {
/**
* @param isSystemIncludePath <code>true</code> if the include path is a system include path otherwise <code>false</code>
* @param cwd the current working directory of the compiler at its invocation
* @see org.eclipse.cdt.jsoncdb.core.participant.IArglet#processArgument(IArgumentCollector,
* IPath, String)
*/
protected final int processArgument(boolean isSystemIncludePath, IArgumentCollector resultCollector, IPath cwd,
String argsLine, NameOptionMatcher[] optionMatchers) {
for (NameOptionMatcher oMatcher : optionMatchers) {
final Matcher matcher = oMatcher.matcher;
matcher.reset(argsLine);
if (matcher.lookingAt()) {
String name = matcher.group(oMatcher.nameGroup);
// workaround for relative path by cmake bug
// https://gitlab.kitware.com/cmake/cmake/issues/13894 : prepend cwd
IPath path = Path.fromOSString(name);
if (!path.isAbsolute()) {
// prepend CWD
name = cwd.append(path).toOSString();
}
if (isSystemIncludePath) {
resultCollector.addSystemIncludePath(name);
} else {
resultCollector.addIncludePath(name);
}
final int end = matcher.end();
return end;
}
}
return 0;// no input consumed
}
}
/**
* A tool argument parser capable to parse a C-compiler include file argument.
*/
public static abstract class IncludeFileGeneric {
/**
* @param cwd
* the current working directory of the compiler at its invocation
*/
protected final int processArgument(IArgumentCollector resultCollector, IPath cwd, String argsLine,
NameOptionMatcher[] optionMatchers) {
for (NameOptionMatcher oMatcher : optionMatchers) {
final Matcher matcher = oMatcher.matcher;
matcher.reset(argsLine);
if (matcher.lookingAt()) {
String name = matcher.group(oMatcher.nameGroup);
resultCollector.addIncludeFile(name);
final int end = matcher.end();
return end;
}
}
return 0;// no input consumed
}
}
/**
* A tool argument parser capable to parse a C-compiler macros file argument.
*/
public static abstract class MacrosFileGeneric {
/**
* @param cwd
* the current working directory of the compiler at its invocation
*/
protected final int processArgument(IArgumentCollector resultCollector, IPath cwd, String argsLine,
NameOptionMatcher[] optionMatchers) {
for (NameOptionMatcher oMatcher : optionMatchers) {
final Matcher matcher = oMatcher.matcher;
matcher.reset(argsLine);
if (matcher.lookingAt()) {
String name = matcher.group(oMatcher.nameGroup);
resultCollector.addMacroFile(name);
final int end = matcher.end();
return end;
}
}
return 0;// no input consumed
}
}
////////////////////////////////////////////////////////////////////
// POSIX compatible option parsers
////////////////////////////////////////////////////////////////////
/**
* A tool argument parser capable to parse a POSIX compatible C-compiler macro
* definition argument: {@code -DNAME=value}.
*/
public static class MacroDefine_C_POSIX extends MacroDefineGeneric implements IArglet {
@SuppressWarnings("nls")
private static final NameValueOptionMatcher[] optionMatchers = {
/* string or char literal value, with whitespace in value and escaped quotes */
new NameValueOptionMatcher("-D" + REGEX_MACRO_NAME_SKIP_LEADING_WS + "=(" + "([\"'])" // the quote char
// in group 3
+ "(?:" // non-capturing
+ "\\\\\\\\" // the escaped escape char
+ "|" // OR
+ "\\\\\\3" // the escaped quote char
+ "|" // OR
+ "(?!\\3)." // any character except the quote char
+ ")*" // zero or more times
+ "\\3" // the quote char
+ ")", 1, 2),
/* macro name only, w/ optional macro arglist */
new NameValueOptionMatcher("-D" + REGEX_MACRO_NAME_SKIP_LEADING_WS + "=((\\S+))", 1, 3),
/* separated, quoted name-value arg, whitespace in value */
new NameValueOptionMatcher("-D" + REGEX_MACRO_ARG_QUOTED__SKIP_LEADING_WS + "=((.+?))\\1", 2, 4),
/* macro name only */
new NameValueOptionMatcher("-D" + REGEX_MACRO_NAME_SKIP_LEADING_WS, 1, -1), };
/*-
* @see org.eclipse.cdt.jsoncdb.IArglet#processArgs(java.lang.String)
*/
@Override
public int processArgument(IArgumentCollector resultCollector, IPath cwd, String argsLine) {
return processArgument(resultCollector, argsLine, optionMatchers);
}
}
////////////////////////////////////////////////////////////////////
/**
* A tool argument parser capable to parse a POSIX compatible C-compiler macro
* cancel argument: {@code -UNAME}.
*/
public static class MacroUndefine_C_POSIX extends MacroUndefineGeneric implements IArglet {
@SuppressWarnings("nls")
private static final NameOptionMatcher optionMatcher = new NameOptionMatcher(
"-U" + REGEX_MACRO_NAME_SKIP_LEADING_WS, 1);
/*-
* @see org.eclipse.cdt.jsoncdb.IArglet#processArgument(java.util.List, java.lang.String)
*/
@Override
public int processArgument(IArgumentCollector resultCollector, IPath cwd, String argsLine) {
return processArgument(resultCollector, argsLine, optionMatcher);
}
}
////////////////////////////////////////////////////////////////////
/**
* A tool argument parser capable to parse a POSIX compatible C-compiler include
* path argument: {@code -Ipath}.
*/
public static class IncludePath_C_POSIX extends IncludePathGeneric implements IArglet {
@SuppressWarnings("nls")
private static final NameOptionMatcher[] optionMatchers = {
/* quoted directory */
new NameOptionMatcher("-I" + REGEX_INCLUDEPATH_QUOTED_DIR, 2),
/* unquoted directory */
new NameOptionMatcher("-I" + REGEX_INCLUDEPATH_UNQUOTED_DIR, 1) };
/*-
* @see org.eclipse.cdt.jsoncdb.IArglet#processArgs(java.lang.String)
*/
@Override
public int processArgument(IArgumentCollector resultCollector, IPath cwd, String argsLine) {
return processArgument(false, resultCollector, cwd, argsLine, optionMatchers);
}
}
////////////////////////////////////////////////////////////////////
/**
* A tool argument parser capable to parse a C-compiler system include path
* argument: {@code -system path}.
*/
public static class SystemIncludePath_C extends IncludePathGeneric implements IArglet {
@SuppressWarnings("nls")
static final NameOptionMatcher[] optionMatchers = {
/* quoted directory */
new NameOptionMatcher("-isystem" + REGEX_INCLUDEPATH_QUOTED_DIR, 2),
/* unquoted directory */
new NameOptionMatcher("-isystem" + REGEX_INCLUDEPATH_UNQUOTED_DIR, 1), };
/*-
* @see org.eclipse.cdt.jsoncdb.IArglet#processArgs(java.lang.String)
*/
@Override
public int processArgument(IArgumentCollector resultCollector, IPath cwd, String argsLine) {
return processArgument(true, resultCollector, cwd, argsLine, optionMatchers);
}
}
////////////////////////////////////////////////////////////////////
/**
* A tool argument parser capable to parse a armcc-compiler system include path
* argument: {@code -Jdir}.
*/
// TODO move this to the arm plugin
public static class SystemIncludePath_armcc extends IncludePathGeneric implements IArglet {
@SuppressWarnings("nls")
static final NameOptionMatcher[] optionMatchers = {
/* quoted directory */
new NameOptionMatcher("-J" + "([\"'])(.+?)\\1", 2),
/* unquoted directory */
new NameOptionMatcher("-J" + "([^\\s]+)", 1), };
/*-
* @see org.eclipse.cdt.jsoncdb.IArglet#processArgs(java.lang.String)
*/
@Override
public int processArgument(IArgumentCollector resultCollector, IPath cwd, String argsLine) {
return processArgument(true, resultCollector, cwd, argsLine, optionMatchers);
}
}
////////////////////////////////////////////////////////////////////
// POSIX compatible option parsers
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// compiler built-ins detection
////////////////////////////////////////////////////////////////////
/**
* A tool argument parser capable to parse arguments from the command-line that
* affect built-in detection.
*/
public static abstract class BuiltinDetctionArgsGeneric {
/**
* @see org.eclipse.cdt.jsoncdb.core.participant.IArglet#processArgument(IArgumentCollector,
* IPath, String)
*/
protected final int processArgument(IArgumentCollector resultCollector, String argsLine,
Matcher[] optionMatchers) {
for (Matcher matcher : optionMatchers) {
matcher.reset(argsLine);
if (matcher.lookingAt()) {
resultCollector.addBuiltinDetectionArgument(matcher.group());
return matcher.end();
}
}
return 0;// no input consumed
}
}
////////////////////////////////////////////////////////////////////
/**
* A tool argument parser capable to parse a GCC include file argument {@code -include <file>}.
*/
public static class IncludeFile_GCC extends IncludeFileGeneric implements IArglet {
@SuppressWarnings("nls")
private static final NameOptionMatcher[] optionMatchers = {
/* "-include=" quoted directory */
new NameOptionMatcher("-include" + REGEX_INCLUDEPATH_QUOTED_DIR, 2),
/* "-include=" unquoted directory */
new NameOptionMatcher("-include" + REGEX_INCLUDEPATH_UNQUOTED_DIR, 1), };
@Override
public int processArgument(IArgumentCollector resultCollector, IPath cwd, String argsLine) {
return processArgument(resultCollector, cwd, argsLine, optionMatchers);
}
}
/**
* A tool argument parser capable to parse a GCC macros file argument {@code -imacros <file>}.
*/
public static class MacrosFile_GCC extends MacrosFileGeneric implements IArglet {
@SuppressWarnings("nls")
private static final NameOptionMatcher[] optionMatchers = {
/* "-include=" quoted directory */
new NameOptionMatcher("-imacros" + REGEX_INCLUDEPATH_QUOTED_DIR, 2),
/* "-include=" unquoted directory */
new NameOptionMatcher("-imacros" + REGEX_INCLUDEPATH_UNQUOTED_DIR, 1), };
/*-
* @see de.marw.cmake.cdt.lsp.IArglet#processArgs(java.lang.String)
*/
@Override
public int processArgument(IArgumentCollector resultCollector, IPath cwd, String argsLine) {
return processArgument(resultCollector, cwd, argsLine, optionMatchers);
}
}
////////////////////////////////////////////////////////////////////
/**
* A tool argument parser capable to parse a GCC option to specify paths
* {@code --sysrooot}.
*/
public static class Sysroot_GCC extends BuiltinDetctionArgsGeneric implements IArglet {
@SuppressWarnings("nls")
private static final Matcher[] optionMatchers = {
/* "--sysroot=" quoted directory */
Pattern.compile("--sysroot=" + REGEX_INCLUDEPATH_QUOTED_DIR).matcher(EMPTY_STR),
/* "--sysroot=" unquoted directory */
Pattern.compile("--sysroot=" + REGEX_INCLUDEPATH_UNQUOTED_DIR).matcher(EMPTY_STR),
/* "-isysroot=" quoted directory */
Pattern.compile("-isysroot=" + REGEX_INCLUDEPATH_QUOTED_DIR).matcher(EMPTY_STR),
/* "-isysroot=" unquoted directory */
Pattern.compile("-isysroot=" + REGEX_INCLUDEPATH_UNQUOTED_DIR).matcher(EMPTY_STR),
/* "--no-sysroot-prefix" */
Pattern.compile("--no-sysroot-prefix").matcher(EMPTY_STR) };
/*-
* @see org.eclipse.cdt.jsoncdb.IArglet#processArgs(java.lang.String)
*/
@Override
public int processArgument(IArgumentCollector resultCollector, IPath cwd, String argsLine) {
return processArgument(resultCollector, argsLine, optionMatchers);
}
}
////////////////////////////////////////////////////////////////////
/**
* A tool argument parser capable to parse a GCC option to specify the language
* standard {@code -std=xxx}.
*/
public static class LangStd_GCC extends BuiltinDetctionArgsGeneric implements IArglet {
@SuppressWarnings("nls")
private static final Matcher[] optionMatchers = { Pattern.compile("-std=\\S+").matcher(EMPTY_STR),
Pattern.compile("-ansi").matcher(EMPTY_STR), };
/*-
* @see org.eclipse.cdt.jsoncdb.IArglet#processArgs(java.lang.String)
*/
@Override
public int processArgument(IArgumentCollector resultCollector, IPath cwd, String argsLine) {
return processArgument(resultCollector, argsLine, optionMatchers);
}
}
////////////////////////////////////////////////////////////////////
}