aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShevek <[email protected]>2015-11-17 13:18:05 -0800
committerShevek <[email protected]>2015-11-17 13:18:05 -0800
commit523e439a8de3807fd1d4917a03ad958e5ef91786 (patch)
tree82f10668ff7ecb26a586946e8c02742bbca1d1ca
parenta031457d300215a11df39ea6da5344af20555ee7 (diff)
Fix #24: Omit trailing comma pasted onto an empty variadic argument.
-rw-r--r--src/main/java/org/anarres/cpp/MacroTokenSource.java35
-rw-r--r--src/main/java/org/anarres/cpp/SourceIterator.java6
-rw-r--r--src/test/java/org/anarres/cpp/VaArgsPastingTest.java2
3 files changed, 40 insertions, 3 deletions
diff --git a/src/main/java/org/anarres/cpp/MacroTokenSource.java b/src/main/java/org/anarres/cpp/MacroTokenSource.java
index 238ab40..6423743 100644
--- a/src/main/java/org/anarres/cpp/MacroTokenSource.java
+++ b/src/main/java/org/anarres/cpp/MacroTokenSource.java
@@ -19,13 +19,17 @@ package org.anarres.cpp;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
+import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import static org.anarres.cpp.Token.*;
/* This source should always be active, since we don't expand macros
* in any inactive context. */
/* pp */ class MacroTokenSource extends Source {
+ private static final Logger LOG = LoggerFactory.getLogger(MacroTokenSource.class);
private final Macro macro;
private final Iterator<Token> tokens; /* Pointer into the macro. */
@@ -96,18 +100,34 @@ import static org.anarres.cpp.Token.*;
str.toString(), buf.toString());
}
+ /**
+ * Returns true if the given argumentIndex is the last argument of a variadic macro.
+ *
+ * @param argumentIndex The index of the argument to inspect.
+ * @return true if the given argumentIndex is the last argument of a variadic macro.
+ */
+ private boolean isVariadicArgument(@Nonnegative int argumentIndex) {
+ if (!macro.isVariadic())
+ return false;
+ return argumentIndex == args.size() - 1;
+ }
/* At this point, we have consumed the first M_PASTE.
* @see Macro#addPaste(Token) */
private void paste(@Nonnull Token ptok)
throws IOException,
LexerException {
+ // List<Token> out = new ArrayList<Token>();
StringBuilder buf = new StringBuilder();
// Token err = null;
/* We know here that arg is null or expired,
* since we cannot paste an expanded arg. */
int count = 2;
+ // While I hate auxiliary booleans, this does actually seem to be the simplest solution,
+ // as it avoids duplicating all the logic around hasNext() in case COMMA.
+ boolean comma = false;
+ TOKEN:
for (int i = 0; i < count; i++) {
if (!tokens.hasNext()) {
/* XXX This one really should throw. */
@@ -127,16 +147,29 @@ import static org.anarres.cpp.Token.*;
break;
case M_ARG:
int idx = ((Integer) tok.getValue()).intValue();
- concat(buf, args.get(idx));
+ Argument arg = args.get(idx);
+ if (comma && isVariadicArgument(idx) && arg.isEmpty()) {
+ // Ugly way to strip the comma.
+ buf.setLength(buf.length() - 1);
+ } else {
+ concat(buf, arg);
+ }
break;
/* XXX Test this. */
case CCOMMENT:
case CPPCOMMENT:
+ // TODO: In cpp, -CC keeps these comments too,
+ // but turns all C++ comments into C comments.
break;
+ case ',':
+ comma = true;
+ buf.append(tok.getText());
+ continue TOKEN;
default:
buf.append(tok.getText());
break;
}
+ comma = false;
}
/* Push and re-lex. */
diff --git a/src/main/java/org/anarres/cpp/SourceIterator.java b/src/main/java/org/anarres/cpp/SourceIterator.java
index db16f01..c7fae18 100644
--- a/src/main/java/org/anarres/cpp/SourceIterator.java
+++ b/src/main/java/org/anarres/cpp/SourceIterator.java
@@ -19,6 +19,7 @@ package org.anarres.cpp;
import java.io.IOException;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import javax.annotation.Nonnull;
import static org.anarres.cpp.Token.EOF;
/**
@@ -30,7 +31,7 @@ public class SourceIterator implements Iterator<Token> {
private final Source source;
private Token tok;
- public SourceIterator(Source s) {
+ public SourceIterator(@Nonnull Source s) {
this.source = s;
this.tok = null;
}
@@ -56,6 +57,7 @@ public class SourceIterator implements Iterator<Token> {
* @throws IllegalStateException if the Source
* throws a LexerException or IOException
*/
+ @Override
public boolean hasNext() {
advance();
return tok.getType() != EOF;
@@ -68,6 +70,7 @@ public class SourceIterator implements Iterator<Token> {
* @throws IllegalStateException if the Source
* throws a LexerException or IOException
*/
+ @Override
public Token next() {
if (!hasNext())
throw new NoSuchElementException();
@@ -81,6 +84,7 @@ public class SourceIterator implements Iterator<Token> {
*
* @throws UnsupportedOperationException unconditionally.
*/
+ @Override
public void remove() {
throw new UnsupportedOperationException();
}
diff --git a/src/test/java/org/anarres/cpp/VaArgsPastingTest.java b/src/test/java/org/anarres/cpp/VaArgsPastingTest.java
index 7623ebf..f1bcbcd 100644
--- a/src/test/java/org/anarres/cpp/VaArgsPastingTest.java
+++ b/src/test/java/org/anarres/cpp/VaArgsPastingTest.java
@@ -58,6 +58,6 @@ public class VaArgsPastingTest {
+ "foo(a,b) // PASTE_ELLIPSIS 2\n"
+ "foo(a) // PASTE_ELLIPSIS 1\n"
+ "foo(a,b) // PASTE_VAARGS 2\n"
- + "foo(a) // PASTE_VAARGS 1\n", output);
+ + "foo(a) // PASTE_VAARGS 1", output);
}
}