Skip to content

Commit

Permalink
* Add some documentation for Info, InfoMap, InfoMapper, and `P…
Browse files Browse the repository at this point in the history
…arser`

 * Fix the `Parser` not filtering and expanding properly some preprocessor directives, as well as producing wrong code for `typedef struct *`
  • Loading branch information
saudet committed May 18, 2014
1 parent 11bdc99 commit 7f64d9e
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 47 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

* Add some documentation for `Info`, `InfoMap`, `InfoMapper`, and `Parser`
* Fix the `Parser` not filtering and expanding properly some preprocessor directives, as well as producing wrong code for `typedef struct *`
* Skip Java path search when building for Android to prevent including some random `jni.h` file ([issue #3](https://github.com/bytedeco/javacpp/issues/3))
* Fix the `Parser` losing some keywords like `static` on methods annotated with an `@Adapter` ([issue #2](https://github.com/bytedeco/javacpp/issues/2))
* Fix `Loader.load()` not properly force loading all inherited target classes ([issue #1](https://github.com/bytedeco/javacpp/issues/1))
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,8 @@ And instead of `Loader.load()`, the library should be loaded with `System.load("


----
Original author: Samuel Audet [samuel.audet `at` gmail.com](mailto:samuel.audet at gmail.com)
Project site: https://github.com/bytedeco/javacpp
Project lead: Samuel Audet [samuel.audet `at` gmail.com](mailto:samuel.audet at gmail.com)
Developer site: https://github.com/bytedeco/javacpp
Discussion group: http://groups.google.com/group/javacpp-project

Licensed under the GNU General Public License version 2 (GPLv2) **with Classpath exception**.
Expand Down
47 changes: 43 additions & 4 deletions src/main/java/org/bytedeco/javacpp/tools/Info.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,18 @@

package org.bytedeco.javacpp.tools;

import org.bytedeco.javacpp.Pointer;
import org.bytedeco.javacpp.annotation.ByVal;
import org.bytedeco.javacpp.annotation.Cast;

/**
* Holds information useful to the {@link Parser} and associated with C++ identifiers.
* Info objects are meant to be added by the user to an {@link InfoMap} passed as
* argument to {@link InfoMapper#map(InfoMap)}. A class inheriting from the latter
* becomes a kind of configuration file entirely written in Java.
* <p>
* For usage examples, one can refer to the source code of the default values defined
* in the initializer of {@link InfoMap#defaults}.
*
* @author Samuel Audet
*/
Expand All @@ -43,10 +54,38 @@ public Info(Info i) {
javaText = i.javaText;
}

String[] cppNames = null, javaNames = null, annotations = null,
cppTypes = null, valueTypes = null, pointerTypes = null;
boolean cast = false, define = false, translate = false, skip = false;
String base = null, cppText = null, javaText = null;
/** A list of C++ identifiers or expressions to which this info is to be bound.
* Usually set via the constructor parameter of {@link #Info(String...)}. */
String[] cppNames = null;
/** The Java identifiers to output corresponding to the C++ identifiers of {@link #cppNames}.
* By default, the names of C++ identifiers {@link #cppNames} are used. */
String[] javaNames = null;
/** Additional Java annotations that should prefix the identifiers on output. */
String[] annotations = null;
/** A list of C++ types that supply information missing from macros, templates, etc.
* By default, identifiers with missing type information are skipped, except for
* variable-like macros for which the type is guessed based on the expression. */
String[] cppTypes = null;
/** A list of (usually) primitive Java types to be used to map C++ value types.
* By default, {@link #pointerTypes} prefixed with @{@link ByVal} are used. */
String[] valueTypes = null;
/** A list of (usually) {@link Pointer} Java subclasses to be used to map C++ pointer types.
* By default, the names of the C++ types {@link #cppNames} are used. */
String[] pointerTypes = null;
/** Annotates Java identifiers with @{@link Cast} containing C++ identifier names {@link #cppNames}. */
boolean cast = false;
/** Indicates expressions of conditional macro groups to parse, or templates to specialize. */
boolean define = false;
/** Attempts to translate naively the statements of variable-like macros to Java. */
boolean translate = false;
/** Skips entirely all the code associated with the C++ identifiers. */
boolean skip = false;
/** Allows to override the base class of {@link #pointerTypes}. Defaults to {@link Pointer}. */
String base = null;
/** Replaces the code associated with the declaration of C++ identifiers, before parsing. */
String cppText = null;
/** Outputs the given code, instead of the result parsed from the declaration of C++ identifiers. */
String javaText = null;

public Info cppNames(String ... cppNames) { this.cppNames = cppNames; return this; }
public Info javaNames(String ... javaNames) { this.javaNames = javaNames; return this; }
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/bytedeco/javacpp/tools/InfoMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/**
* A {@link Map} containing {@link Info} objects consumed by the {@link Parser}.
* Also contains a few utility methods to facilitate its use for both the user
* and the {@link Parser}.
*
* @author Samuel Audet
*/
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/org/bytedeco/javacpp/tools/InfoMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,16 @@

package org.bytedeco.javacpp.tools;

import org.bytedeco.javacpp.annotation.Properties;

/**
* An interface to define a kind of configuration file entirely written in Java.
* A class implementing this interface can be passed to the {@link Parser}, which
* will create an instance of the class before calling the {@link #map(InfoMap)}
* method, to be filled in with {@link Info} objects defined by the user.
* <p>
* A class further annotated with {@link Properties#target()} gets detected by
* the {@link Builder}, which then delegates it to the {@link Parser}.
*
* @author Samuel Audet
*/
Expand Down
32 changes: 28 additions & 4 deletions src/main/java/org/bytedeco/javacpp/tools/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,28 @@
import org.bytedeco.javacpp.Loader;

/**
* The Parser, just like the Generator, is a mess that is not meant to support the
* entirety of C++, but an appropriate subset as used by typical C/C++ header files.
* To figure out what that subset is and what the output should be, the idea is to
* apply it on as many C/C++ libraries as possible, and patch the code as we go.
* At one point in time, when this prototype code appears to have stabilized, we can
* start to redesign it in a more meaningful way.
* <p>
* That said, to understand how it is supposed to function in its present state,
* one can step through the code at runtime: It is quite friendly to debuggers.
* <p>
* Moreover, it relies on {@link Info} objects created as part of the execution
* of {@link InfoMapper#map(InfoMap)}. We can understand better how the parsing
* is supposed to get accomplished by studying that documentation as well.
* <p>
* To do:
* - Inherit constructors from helper classes, if possible
* - etc.
*
* @see Info
* @see InfoMap
* @see InfoMapper
*
* @author Samuel Audet
*/
public class Parser {
Expand Down Expand Up @@ -1393,7 +1411,10 @@ boolean typedef(Context context, DeclarationList declList) throws ParserExceptio
if (info.cppTypes == null) {
info.cppTypes(typeName);
}
if (info.pointerTypes == null) {
if (info.valueTypes == null && dcl.indirections > 0) {
info.valueTypes(typeName);
info.pointerTypes("PointerPointer");
} else if (info.pointerTypes == null) {
info.pointerTypes(typeName);
}
if (info.annotations == null) {
Expand Down Expand Up @@ -1457,9 +1478,6 @@ boolean group(Context context, DeclarationList declList) throws ParserException
}

tokens.next().expect(Token.IDENTIFIER, '{');
if (typedef && tokens.get(1).match('*')) {
tokens.next();
}
if (!tokens.get().match('{') && tokens.get(1).match(Token.IDENTIFIER)
&& (typedef || !tokens.get(2).match(';'))) {
tokens.next();
Expand Down Expand Up @@ -1489,6 +1507,12 @@ boolean group(Context context, DeclarationList declList) throws ParserException
}
}
}
if (typedef && tokens.get().match('*')) {
// skip pointer typedef
while (!tokens.get().match(';', Token.EOF)) {
tokens.next();
}
}
if (!tokens.get().match('{', ';')) {
tokens.index = backIndex;
return false;
Expand Down
82 changes: 45 additions & 37 deletions src/main/java/org/bytedeco/javacpp/tools/TokenIndexer.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,15 @@ void filter(int index) {
while (index < array.length) {
Token keyword = null;
if (array[index].match('#')) {
if (count == 0 && array[index + 1].match(Token.IF, Token.IFDEF, Token.IFNDEF)) {
if (array[index + 1].match(Token.IF, Token.IFDEF, Token.IFNDEF)) {
count++;
keyword = array[index + 1];
} else if (count == 1 && array[index + 1].match(Token.ELIF, Token.ELSE, Token.ENDIF)) {
}
if (count == 1 && array[index + 1].match(Token.IF, Token.IFDEF, Token.IFNDEF, Token.ELIF, Token.ELSE, Token.ENDIF)) {
keyword = array[index + 1];
}
if (array[index + 1].match(Token.ENDIF)) {
count--;
}
}
if (keyword != null) {
tokens.add(array[index++]);
Expand All @@ -82,7 +85,6 @@ void filter(int index) {
} else if (keyword.match(Token.ELSE)) {
define = info == null || !define;
} else if (keyword.match(Token.ENDIF)) {
count--;
if (count == 0) {
break;
}
Expand Down Expand Up @@ -110,47 +112,52 @@ void expand(int index) {
Tokenizer tokenizer = new Tokenizer(info.cppText);
if (!tokenizer.nextToken().match('#')
|| !tokenizer.nextToken().match(Token.DEFINE)
|| !tokenizer.nextToken().match(info.cppNames[0])
|| !tokenizer.nextToken().match('(')) {
return;
}
ArrayList<String> params = new ArrayList<String>();
Token token;
while (!(token = tokenizer.nextToken()).isEmpty()) {
if (token.match(Token.IDENTIFIER)) {
params.add(token.value);
} else if (token.match(')')) {
break;
}
}
if (params.size() > 0 && (index + 1 >= array.length
|| !array[index + 1].match('('))) {
|| !tokenizer.nextToken().match(info.cppNames[0])) {
return;
}
ArrayList<Token> tokens = new ArrayList<Token>();
for (int i = 0; i < index; i++) {
tokens.add(array[i]);
}
ArrayList<Token>[] args = new ArrayList[params.size()];
int count = 0, count2 = 0;
for (index += 2; index < array.length; index++) {
token = array[index];
if (count2 == 0 && token.match(')')) {
break;
} else if (count2 == 0 && token.match(',')) {
count++;
continue;
} else if (token.match('(','[','{')) {
count2++;
} else if (token.match(')',']','}')) {
count2--;
ArrayList<String> params = new ArrayList<String>();
ArrayList<Token>[] args = null;
Token token = tokenizer.nextToken();
if (token.match('(')) {
token = tokenizer.nextToken();
while (!token.isEmpty()) {
if (token.match(Token.IDENTIFIER)) {
params.add(token.value);
} else if (token.match(')')) {
token = tokenizer.nextToken();
break;
}
token = tokenizer.nextToken();
}
if (args[count] == null) {
args[count] = new ArrayList<Token>();
index++;
if (params.size() > 0 && (index >= array.length || !array[index].match('('))) {
return;
}
args = new ArrayList[params.size()];
int count = 0, count2 = 0;
for (index++; index < array.length; index++) {
Token token2 = array[index];
if (count2 == 0 && token2.match(')')) {
break;
} else if (count2 == 0 && token2.match(',')) {
count++;
continue;
} else if (token2.match('(','[','{')) {
count2++;
} else if (token2.match(')',']','}')) {
count2--;
}
if (args[count] == null) {
args[count] = new ArrayList<Token>();
}
args[count].add(token2);
}
args[count].add(token);
}
while (!(token = tokenizer.nextToken()).isEmpty()) {
while (!token.isEmpty()) {
boolean foundArg = false;
for (int i = 0; i < params.size(); i++) {
if (params.get(i).equals(token.value)) {
Expand All @@ -168,8 +175,9 @@ void expand(int index) {
}
tokens.add(token);
}
token = tokenizer.nextToken();
}
for (index += 1; index < array.length; index++) {
for (index++; index < array.length; index++) {
tokens.add(array[index]);
}
array = tokens.toArray(new Token[tokens.size()]);
Expand Down

0 comments on commit 7f64d9e

Please sign in to comment.