+ public final class Line
+ {
+ private final String content;
+ private final int lineNumber;
+ private final int offset;
+
+ private final Deque<Token> tokens = new LinkedList<>();
(I'm mildly upset that Stack isn't an interface implemented by Deque, as it
would convey your usage better here.)
+
+ private final Line previousLine;
+ /** Not made final to avoid a possible StackOverflowError. Do not modify. */
+ private Line nextLine = null;
+
+ private Line( final LineNumberReader commandStream )
+ {
+ this( commandStream, null );
+ }
+
+ private Line( final LineNumberReader commandStream, final Line previousLine )
+ {
+ this.previousLine = previousLine;
+ if ( previousLine != null )
+ {
+ previousLine.nextLine = this;
+ }
+
+ int offset = 0;
+ String line;
+
+ try
+ {
+ line = commandStream.readLine();
+ }
+ catch ( IOException e )
+ {
+ // This should not happen. Therefore, print
+ // a stack trace for debug purposes.
+
+ StaticEntity.printStackTrace( e );
+ line = null;
Might I suggest initializing this.content / this.lineNumber / this.offset here
and then returning? That way you don't have to keep track of "maybe we caught an
error condition". Guards are generally useful for helping to reduce nesting and
the amount of mental state needed.
https://en.wikipedia.org/wiki/Guard_(computer_science)
+ }
+
+ if ( line != null )
+ {
+ // If the line starts with a Unicode BOM, remove it.
This is slightly incorrect behavior, as it can trigger in the middle of a file,
where Unicode says it should be treated as a zero-width non-breaking space. But,
I see that's consistent with what we're doing today.
(Nothing needed here, just worth noting.)
+ if ( line.length() > 0 &&
+ line.charAt( 0 ) == Parser.BOM )
+ {
+ line = line.substring( 1 );
A wild string copy appeared! (Again, apparently in existng code. This doesn't
seem like something Java cares about.)
+ offset += 1;
+ }
+
+ // Remove whitespace at front and end
+ final String trimmed = line.trim();
+ final int ltrim = line.indexOf( trimmed );
This is more expensive than likely needed, but until it's a proven performance
issue, it's likely better to leave it as the more obvious solution.
Java's String.indexOf( String ) is mostly optimized for this situation, anyways (although, we
still need to read through the end of the line to make sure these strings are
identical).
The "better" (at least, more efficient) implementation might look something like...
if ( !trimmed.isEmpty() )
{
// Here, line.indexOf( trimmed ) == line.indexOf( trimmed.charAt( 0 ) )
offset += line.indexOf( trimmed.charAt( 0 ) );
}
+
+ if ( ltrim > 0 )
+ {
+ offset += ltrim;
+ }
+
+ line = trimmed;
+ }
+
+ this.content = line;
+
+ if ( line != null )
+ {
+ this.lineNumber = commandStream.getLineNumber();
+ this.offset = offset;
+ }
+ else
+ {
+ // We are the "end of file"
+ // (or there was an IOException when reading)
Instead of needing to think about both these cases, can we add an early return
from the catch block as requested above? Regardless, I'd recommend moving this
up after the try/catch statement, as the following:
if ( line == null )
{
this.lineNumber = this.previousLine != null ? this.previousLine.lineNumber : 0;
this.offset = this.previousLine != null ? this.previousLine.offset : 0;
this.content = null;
return;
}
Then, you can go through the rest of the constructor without worrying if line
might be null.
+ this.lineNumber = this.previousLine != null ? this.previousLine.lineNumber : 0;
+ this.offset = this.previousLine != null ? this.previousLine.offset : 0;
+ }
+ }
+
+ private String substring( final int beginIndex )
+ {
+ // subtract "offset" from beginIndex, since
+ // we already removed it
+ return this.content.substring( beginIndex - this.offset );
Is it okay for this function to be unchecked?