com.jogamp.gluegen.jcpp.Source Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gluegen-rt-android Show documentation
Show all versions of gluegen-rt-android Show documentation
JNI binding generator (Android runtime)
The newest version!
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.jogamp.gluegen.jcpp;
import java.io.Closeable;
import java.io.IOException;
import java.util.Iterator;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import static com.jogamp.gluegen.jcpp.Token.CCOMMENT;
import static com.jogamp.gluegen.jcpp.Token.CPPCOMMENT;
import static com.jogamp.gluegen.jcpp.Token.EOF;
import static com.jogamp.gluegen.jcpp.Token.NL;
import static com.jogamp.gluegen.jcpp.Token.WHITESPACE;
/**
* An input to the Preprocessor.
*
* Inputs may come from Files, Strings or other sources. The
* preprocessor maintains a stack of Sources. Operations such as
* file inclusion or token pasting will push a new source onto
* the Preprocessor stack. Sources pop from the stack when they
* are exhausted; this may be transparent or explicit.
*
* BUG: Error messages are not handled properly.
*/
public abstract class Source implements Iterable, Closeable {
private Source parent;
private boolean autopop;
private PreprocessorListener listener;
private boolean active;
private boolean werror;
/* LineNumberReader */
/*
// We can't do this, since we would lose the LexerException
private class Itr implements Iterator {
private Token next = null;
private void advance() {
try {
if (next != null)
next = token();
}
catch (IOException e) {
throw new UnsupportedOperationException(
"Failed to advance token iterator: " +
e.getMessage()
);
}
}
public boolean hasNext() {
return next.getType() != EOF;
}
public Token next() {
advance();
Token t = next;
next = null;
return t;
}
public void remove() {
throw new UnsupportedOperationException(
"Cannot remove tokens from a Source."
);
}
}
*/
public Source() {
this.parent = null;
this.autopop = false;
this.listener = null;
this.active = true;
this.werror = false;
}
/**
* Sets the parent source of this source.
*
* Sources form a singly linked list.
*/
/* pp */ void setParent(final Source parent, final boolean autopop) {
this.parent = parent;
this.autopop = autopop;
}
/**
* Returns the parent source of this source.
*
* Sources form a singly linked list.
*/
public final Source getParent() {
return parent;
}
// @OverrideMustInvoke
/* pp */ void init(final Preprocessor pp) {
setListener(pp.getListener());
this.werror = pp.getWarnings().contains(Warning.ERROR);
}
/**
* Sets the listener for this Source.
*
* Normally this is set by the Preprocessor when a Source is
* used, but if you are using a Source as a standalone object,
* you may wish to call this.
*/
public void setListener(final PreprocessorListener pl) {
this.listener = pl;
}
/**
* Returns the File currently being lexed.
*
* If this Source is not a {@link FileLexerSource}, then
* it will ask the parent Source, and so forth recursively.
* If no Source on the stack is a FileLexerSource, returns null.
*/
@CheckForNull
public String getPath() {
final Source parent = getParent();
if (parent != null)
return parent.getPath();
return null;
}
/**
* Returns the human-readable name of the current Source.
*/
@CheckForNull
public String getName() {
final Source parent = getParent();
if (parent != null)
return parent.getName();
return null;
}
/**
* Returns the current line number within this Source.
*/
@Nonnegative
public int getLine() {
final Source parent = getParent();
if (parent == null)
return 0;
return parent.getLine();
}
/**
* Returns the current column number within this Source.
*/
public int getColumn() {
final Source parent = getParent();
if (parent == null)
return 0;
return parent.getColumn();
}
/**
* Returns true if this Source is expanding the given macro.
*
* This is used to prevent macro recursion.
*/
/* pp */ boolean isExpanding(@Nonnull final Macro m) {
final Source parent = getParent();
if (parent != null)
return parent.isExpanding(m);
return false;
}
/**
* Returns true if this Source should be transparently popped
* from the input stack.
*
* Examples of such sources are macro expansions.
*/
/* pp */ boolean isAutopop() {
return autopop;
}
/**
* Returns true if this source has line numbers.
*/
/* pp */ boolean isNumbered() {
return false;
}
/* This is an incredibly lazy way of disabling warnings when
* the source is not active. */
/* pp */ void setActive(final boolean b) {
this.active = b;
}
/* pp */ boolean isActive() {
return active;
}
/**
* Returns the next Token parsed from this input stream.
*
* @see Token
*/
@Nonnull
public abstract Token token()
throws IOException,
LexerException;
/**
* Returns a token iterator for this Source.
*/
@Override
public Iterator iterator() {
return new SourceIterator(this);
}
/**
* Skips tokens until the end of line.
*
* @param white true if only whitespace is permitted on the
* remainder of the line.
* @return the NL token.
*/
@Nonnull
public Token skipline(final boolean white)
throws IOException,
LexerException {
for (;;) {
final Token tok = token();
switch (tok.getType()) {
case EOF:
/* There ought to be a newline before EOF.
* At least, in any skipline context. */
/* XXX Are we sure about this? */
warning(tok.getLine(), tok.getColumn(),
"No newline before end of file");
return new Token(NL,
tok.getLine(), tok.getColumn(),
"\n");
// return tok;
case NL:
/* This may contain one or more newlines. */
return tok;
case CCOMMENT:
case CPPCOMMENT:
case WHITESPACE:
break;
default:
/* XXX Check white, if required. */
if (white)
warning(tok.getLine(), tok.getColumn(),
"Unexpected nonwhite token");
break;
}
}
}
protected void error(final int line, final int column, final String msg)
throws LexerException {
if (listener != null)
listener.handleError(this, line, column, msg);
else
throw new LexerException("Error at " + line + ":" + column + ": " + msg);
}
protected void warning(final int line, final int column, final String msg)
throws LexerException {
if (werror)
error(line, column, msg);
else if (listener != null)
listener.handleWarning(this, line, column, msg);
else
throw new LexerException("Warning at " + line + ":" + column + ": " + msg);
}
public void close()
throws IOException {
}
}