diff options
Diffstat (limited to 'src/main/java/com/jogamp/gluegen/jcpp/Source.java')
-rw-r--r-- | src/main/java/com/jogamp/gluegen/jcpp/Source.java | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/src/main/java/com/jogamp/gluegen/jcpp/Source.java b/src/main/java/com/jogamp/gluegen/jcpp/Source.java new file mode 100644 index 0000000..d56b5d7 --- /dev/null +++ b/src/main/java/com/jogamp/gluegen/jcpp/Source.java @@ -0,0 +1,298 @@ +/* + * 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<Token>, 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<Token> 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 { + } + +} |