Skip to content

Commit

Permalink
Improve parsing of function templates
Browse files Browse the repository at this point in the history
  • Loading branch information
HGuillemet committed Dec 28, 2023
1 parent 9855bf6 commit 7c80a07
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 69 deletions.
50 changes: 13 additions & 37 deletions src/main/java/org/bytedeco/javacpp/tools/InfoMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,19 @@ String normalize(String name, boolean unconst, boolean untemplate) {
if (name == null || name.length() == 0 || name.startsWith("basic/")) {
return name;
}
if (untemplate) {
// Remove template arguments in the last NS component only, and not in parameters, if any
Templates.SplitResult comps = Templates.splitNamespace(name);
int last = comps.size()-1;
String lastComp = comps.get(last);
comps.set(last, Templates.strip(lastComp));
name = comps.get(0);
for (int i = 1; i <= last; i++)
name += "::" + comps.get(i);
if (comps.parameterList != null)
name += comps.parameterList;
if (name.isEmpty()) return name;
}
boolean foundConst = false, simpleType = true;
String prefix = null;
Token[] tokens = new Tokenizer(name, null, 0).tokenize();
Expand Down Expand Up @@ -216,43 +229,6 @@ String normalize(String name, boolean unconst, boolean untemplate) {
for (int i = 1; i < n; i++) {
name += " " + tokens[i].value;
}
} else if (untemplate) {
int count = 0, lastColon = -1, template = -1, parameters = n;
for (int i = 0; i < n; i++) {
if (tokens[i].match('<')) {
count++;
} else if (tokens[i].match('>')) {
count--;
}
if (count == 0 && tokens[i].match("::")) {
lastColon = i;
} else if (count == 0 && tokens[i].match('(')) {
parameters = i;
break;
}
}
for (int i = lastColon + 1; i < parameters; i++) {
if (tokens[i].match('<')) {
if (count == 0) {
template = i;
}
count++;
} else if (tokens[i].match('>')) {
count--;
if (count == 0 && i + 1 != parameters) {
template = -1;
}
}
}
if (template >= 0) {
name = foundConst ? "const " : "";
for (int i = 0; i < template; i++) {
name += tokens[i];
}
for (int i = parameters; i < n; i++) {
name += tokens[i].spacing + tokens[i];
}
}
}
if (unconst && foundConst) {
name = name.substring(name.indexOf("const") + 5);
Expand Down
83 changes: 56 additions & 27 deletions src/main/java/org/bytedeco/javacpp/tools/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,28 @@ Type[] templateArguments(Context context) throws ParserException {
return arguments.toArray(new Type[0]);
}

/**
* Read and return the operator following an operator keyword:
* any of new, delete, + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= <=>(since C++20) && || ++ -- , ->* -> ( ) [ ]
* taking care of template arguments, if any.
*/
private String operator(Context context) throws ParserException {
String res = tokens.get().toString(); // Can be '('
int lenFirstToken = res.length();
String s = "";
tokens.next();
int backIndex = tokens.index;
for (Token token = tokens.get(); !token.match('(', Token.EOF); token = tokens.next()) {
s += token;
}
s = Templates.strip(s);
tokens.index = backIndex;
for (Token token = tokens.get(); s.length() > res.length() - lenFirstToken; token = tokens.next()) {
res += token;
}
return res;
}

Type type(Context context) throws ParserException {
return type(context, false);
}
Expand Down Expand Up @@ -865,7 +887,8 @@ Type type(Context context, boolean definition) throws ParserException {
} else if (type.cppName.endsWith("::")) {
type.operator = true;
tokens.next();
break;
type.cppName += operator(context);
continue;
} else {
break;
}
Expand Down Expand Up @@ -1109,22 +1132,15 @@ Type type(Context context, boolean definition) throws ParserException {
}
}
if (context.cppName != null && type.javaName.length() > 0) {
String cppName = type.cppName;
String groupName = context.cppName;
String cppNameStripped = Templates.strip(cppName);
String groupNameStripped = Templates.strip(groupName);
if (cppNameStripped.length() == cppName.length() && groupNameStripped.length() != groupName.length()) {
groupName = groupNameStripped;
} else if (cppNameStripped.length() != cppName.length() && groupNameStripped.length() == groupName.length()) {
cppName = cppNameStripped;
}
String cppName = Templates.strip(type.cppName);
String groupName = Templates.strip(context.cppName);
List<String> cppNameSplit = Templates.splitNamespace(cppName);
List<String> groupNameSplit = Templates.splitNamespace(groupName);
if (cppNameSplit.size() == 1 && groupNameSplit.size() > 1)
groupName = groupNameSplit.get(groupNameSplit.size() - 1);
else if (cppNameSplit.size() > 1 && groupNameSplit.size() == 1)
cppName = cppNameSplit.get(cppNameSplit.size() - 1);
if (cppName.equals(groupName) || groupName.startsWith(cppName + "<")) {
if (cppName.equals(groupName)) {
type.constructor = !type.destructor && !type.operator
&& type.indirections == 0 && !type.reference && tokens.get().match('(', ':');
}
Expand Down Expand Up @@ -1347,11 +1363,8 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
} else if (token.match(Token.OPERATOR)) {
dcl.operator = true;
if (!tokens.get(1).match(Token.IDENTIFIER) || tokens.get(1).match(Token.NEW, Token.DELETE)) {
// assume we can have any symbols until the first open parenthesis
dcl.cppName += "operator " + tokens.next();
for (token = tokens.next(); !token.match(Token.EOF, '('); token = tokens.next()) {
dcl.cppName += token;
}
tokens.next();
dcl.cppName += "operator " + operator(context);
break;
}
} else if (token.match('<')) {
Expand Down Expand Up @@ -2347,10 +2360,11 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
dcl.cppName = context.namespace + "::" + dcl.cppName;
}
Info info = null, fullInfo = null;
String fullname = dcl.cppName, fullname2 = dcl.cppName;
String templateArgs = declList.templateMap != null ? declList.templateMap.toString() : "";
String fullname = dcl.cppName + templateArgs;
if (dcl.parameters != null) {
fullname += "(";
fullname2 += "(";
String param1 = "(";
String param2 = "(";
String separator = "";
for (Declarator d : dcl.parameters.declarators) {
if (d != null) {
Expand All @@ -2376,25 +2390,40 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
if (d.type.constPointer && !s.endsWith(" const")) {
s = s + " const";
}
fullname += separator + s;
fullname2 += separator + s2;
param1 += separator + s;
param2 += separator + s2;
separator = ", ";
}
}
info = fullInfo = infoMap.getFirst(fullname += ")", false);
param1 += ")";
param2 += ")";
fullname += templateArgs + param1;
fullname += param1;
info = fullInfo = infoMap.getFirst(fullname, false);
if (info == null) {
info = infoMap.getFirst(fullname2 += ")", false);
info = infoMap.getFirst(dcl.cppName + templateArgs + param2, false);
if (info == null && !templateArgs.isEmpty()) {
info = infoMap.getFirst(dcl.cppName + param1, false);
if (info == null) {
info = infoMap.getFirst(dcl.cppName + param2, false);
}
}
}
}
if (info == null) {
if (type.constructor) {
// get Info explicitly associated with all constructors
List<String> cppNameSplit = Templates.splitNamespace(dcl.cppName);
String name = Templates.strip(cppNameSplit.get(cppNameSplit.size() - 1));
info = fullInfo = infoMap.getFirst(dcl.cppName + "::" + name);
}
if (info == null) {
info = infoMap.getFirst(dcl.cppName);
info = fullInfo = infoMap.getFirst(dcl.cppName + "::" + name + templateArgs);
if (info == null && !templateArgs.isEmpty()) {
info = infoMap.getFirst(dcl.cppName + "::" + name);
}
} else {
info = infoMap.getFirst(dcl.cppName + templateArgs);
if (info == null && !templateArgs.isEmpty()) {
info = infoMap.getFirst(dcl.cppName);
}
}
if (!type.constructor && !type.destructor && !type.operator && (context.templateMap == null || context.templateMap.full())) {
infoMap.put(info != null ? new Info(info).cppNames(fullname).javaNames(null) : new Info(fullname));
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/org/bytedeco/javacpp/tools/TemplateMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
package org.bytedeco.javacpp.tools;

import java.util.LinkedHashMap;
import java.util.Map;

/**
*
Expand Down Expand Up @@ -67,4 +68,19 @@ Type get(String key) {
return value;
}
}

@Override
public String toString() {
String res = "<";
for (Map.Entry<String, Type> e: entrySet()) {
if (res.length() > 1) res += ",";
Type t = e.getValue();
if (t == null)
res += e.getKey();
else
res += t.cppName;
}
if (res.charAt(res.length()-1) == '>') res += " ";
return res + ">";
}
}
32 changes: 27 additions & 5 deletions src/main/java/org/bytedeco/javacpp/tools/Templates.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,12 @@ static boolean notExists(String s) {
return strip(s).length() == s.length();
}

/** Split s at ::, but taking care of qualified template arguments */
static List<String> splitNamespace(String s) {
static class SplitResult extends ArrayList<String> {
String parameterList;
}

/** Split s at ::, but taking care of qualified template arguments and qualified function parameters, if any. */
static SplitResult splitNamespace(String s) {
String sTemplatesMasked = s;
for (;;) {
Matcher m = templatePattern.matcher(sTemplatesMasked);
Expand All @@ -60,18 +64,36 @@ static List<String> splitNamespace(String s) {
break;
}
}
ArrayList<String> comps = new ArrayList<>();
SplitResult comps = new SplitResult();
int pIndex = sTemplatesMasked.lastIndexOf(')'); // last because of function pointer types like void(*)()
if (pIndex > 0) {
// Pointer list may contain function pointer types with parentheses
int count = 1;
for (pIndex--; pIndex >= 0; pIndex--) {
char c = sTemplatesMasked.charAt(pIndex);
if (c == ')') count++;
else if (c == '(') {
count--;
if (count == 0) break;
}
}
}
int start = 0;
for (;;) {
int i = sTemplatesMasked.indexOf("::", start);
if (i >= 0) {
if (i >= 0 && (i < pIndex || pIndex == -1)) {
comps.add(s.substring(start, i));
start = i + 2;
} else {
break;
}
}
comps.add(s.substring(start));
if (pIndex >= 0) {
comps.add(s.substring(start, pIndex));
comps.parameterList = s.substring(pIndex);
} else {
comps.add(s.substring(start));
}
return comps;
}
}

0 comments on commit 7c80a07

Please sign in to comment.