start fixing Token hierarchy by factoring origin() up to base class

This commit is contained in:
Havoc Pennington 2011-12-06 15:04:13 -05:00
parent 7d13a00f7d
commit 81a4fe63f9
7 changed files with 72 additions and 103 deletions

View File

@ -69,7 +69,7 @@ final class Parser {
}
if (Tokens.isProblem(t)) {
ConfigOrigin origin = Tokens.getProblemOrigin(t);
ConfigOrigin origin = t.origin();
String message = Tokens.getProblemMessage(t);
Throwable cause = Tokens.getProblemCause(t);
boolean suggestQuotes = Tokens.getProblemSuggestQuotes(t);
@ -102,7 +102,7 @@ final class Parser {
while (Tokens.isNewline(t)) {
// line number tokens have the line that was _ended_ by the
// newline, so we have to add one.
lineNumber = Tokens.getLineNumber(t) + 1;
lineNumber = t.lineNumber() + 1;
t = nextToken();
}
return t;
@ -129,7 +129,7 @@ final class Parser {
while (true) {
if (Tokens.isNewline(t)) {
// newline number is the line just ended, so add one
lineNumber = Tokens.getLineNumber(t) + 1;
lineNumber = t.lineNumber() + 1;
sawSeparatorOrNewline = true;
// we want to continue to also eat
// a comma if there is one.
@ -190,11 +190,11 @@ final class Parser {
} else if (Tokens.isUnquotedText(valueToken)) {
String text = Tokens.getUnquotedText(valueToken);
if (firstOrigin == null)
firstOrigin = Tokens.getUnquotedTextOrigin(valueToken);
firstOrigin = valueToken.origin();
sb.append(text);
} else if (Tokens.isSubstitution(valueToken)) {
if (firstOrigin == null)
firstOrigin = Tokens.getSubstitutionOrigin(valueToken);
firstOrigin = valueToken.origin();
if (sb.length() > 0) {
// save string so far
@ -204,8 +204,7 @@ final class Parser {
// now save substitution
List<Token> expression = Tokens
.getSubstitutionPathExpression(valueToken);
Path path = parsePathExpression(expression.iterator(),
Tokens.getSubstitutionOrigin(valueToken));
Path path = parsePathExpression(expression.iterator(), valueToken.origin());
boolean optional = Tokens.getSubstitutionOptional(valueToken);
minimized.add(new SubstitutionExpression(path, optional));

View File

@ -3,24 +3,51 @@
*/
package com.typesafe.config.impl;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigOrigin;
class Token {
final private TokenType tokenType;
final private String debugString;
final private ConfigOrigin origin;
Token(TokenType tokenType) {
this(tokenType, null);
Token(TokenType tokenType, ConfigOrigin origin) {
this(tokenType, origin, null);
}
Token(TokenType tokenType, String debugString) {
Token(TokenType tokenType, ConfigOrigin origin, String debugString) {
this.tokenType = tokenType;
this.origin = origin;
this.debugString = debugString;
}
// this is used for singleton tokens like COMMA or OPEN_CURLY
static Token newWithoutOrigin(TokenType tokenType, String debugString) {
return new Token(tokenType, null, debugString);
}
public TokenType tokenType() {
final TokenType tokenType() {
return tokenType;
}
// this is final because we don't always use the origin() accessor,
// and we don't because it throws if origin is null
final ConfigOrigin origin() {
// code is only supposed to call origin() on token types that are
// expected to have an origin.
if (origin == null)
throw new ConfigException.BugOrBroken(
"tried to get origin from token that doesn't have one: " + this);
return origin;
}
final int lineNumber() {
if (origin != null)
return origin.lineNumber();
else
return -1;
}
@Override
public String toString() {
if (debugString != null)
@ -36,6 +63,7 @@ class Token {
@Override
public boolean equals(Object other) {
if (other instanceof Token) {
// origin is deliberately left out
return canEqual(other)
&& this.tokenType == ((Token) other).tokenType;
} else {
@ -45,6 +73,7 @@ class Token {
@Override
public int hashCode() {
// origin is deliberately left out
return tokenType.hashCode();
}
}

View File

@ -479,8 +479,9 @@ final class Tokenizer {
return Tokens.END;
} else if (c == '\n') {
// newline tokens have the just-ended line number
Token line = Tokens.newLine(lineOrigin()); // uses lineNumber
lineNumber += 1;
return Tokens.newLine(lineNumber - 1);
return line;
} else {
Token t = null;
switch (c) {

View File

@ -16,7 +16,7 @@ final class Tokens {
final private AbstractConfigValue value;
Value(AbstractConfigValue value) {
super(TokenType.VALUE);
super(TokenType.VALUE, value.origin());
this.value = value;
}
@ -46,20 +46,13 @@ final class Tokens {
}
static private class Line extends Token {
final private int lineNumber;
Line(int lineNumber) {
super(TokenType.NEWLINE);
this.lineNumber = lineNumber;
}
int lineNumber() {
return lineNumber;
Line(ConfigOrigin origin) {
super(TokenType.NEWLINE, origin);
}
@Override
public String toString() {
return "'\n'@" + lineNumber;
return "'\n'@" + lineNumber();
}
@Override
@ -69,31 +62,24 @@ final class Tokens {
@Override
public boolean equals(Object other) {
return super.equals(other)
&& ((Line) other).lineNumber == lineNumber;
return super.equals(other) && ((Line) other).lineNumber() == lineNumber();
}
@Override
public int hashCode() {
return 41 * (41 + super.hashCode()) + lineNumber;
return 41 * (41 + super.hashCode()) + lineNumber();
}
}
// This is not a Value, because it requires special processing
static private class UnquotedText extends Token {
final private ConfigOrigin origin;
final private String value;
UnquotedText(ConfigOrigin origin, String s) {
super(TokenType.UNQUOTED_TEXT);
this.origin = origin;
super(TokenType.UNQUOTED_TEXT, origin);
this.value = s;
}
ConfigOrigin origin() {
return origin;
}
String value() {
return value;
}
@ -121,7 +107,6 @@ final class Tokens {
}
static private class Problem extends Token {
final private ConfigOrigin origin;
final private String what;
final private String message;
final private boolean suggestQuotes;
@ -129,18 +114,13 @@ final class Tokens {
Problem(ConfigOrigin origin, String what, String message, boolean suggestQuotes,
Throwable cause) {
super(TokenType.PROBLEM);
this.origin = origin;
super(TokenType.PROBLEM, origin);
this.what = what;
this.message = message;
this.suggestQuotes = suggestQuotes;
this.cause = cause;
}
ConfigOrigin origin() {
return origin;
}
String message() {
return message;
}
@ -189,21 +169,15 @@ final class Tokens {
// This is not a Value, because it requires special processing
static private class Substitution extends Token {
final private ConfigOrigin origin;
final private boolean optional;
final private List<Token> value;
Substitution(ConfigOrigin origin, boolean optional, List<Token> expression) {
super(TokenType.SUBSTITUTION);
this.origin = origin;
super(TokenType.SUBSTITUTION, origin);
this.optional = optional;
this.value = expression;
}
ConfigOrigin origin() {
return origin;
}
boolean optional() {
return optional;
}
@ -259,27 +233,10 @@ final class Tokens {
return token instanceof Line;
}
static int getLineNumber(Token token) {
if (token instanceof Line) {
return ((Line) token).lineNumber();
} else {
throw new ConfigException.BugOrBroken(
"tried to get line number from non-newline " + token);
}
}
static boolean isProblem(Token token) {
return token instanceof Problem;
}
static ConfigOrigin getProblemOrigin(Token token) {
if (token instanceof Problem) {
return ((Problem) token).origin();
} else {
throw new ConfigException.BugOrBroken("tried to get problem origin from " + token);
}
}
static String getProblemMessage(Token token) {
if (token instanceof Problem) {
return ((Problem) token).message();
@ -318,15 +275,6 @@ final class Tokens {
}
}
static ConfigOrigin getUnquotedTextOrigin(Token token) {
if (token instanceof UnquotedText) {
return ((UnquotedText) token).origin();
} else {
throw new ConfigException.BugOrBroken(
"tried to get unquoted text from " + token);
}
}
static boolean isSubstitution(Token token) {
return token instanceof Substitution;
}
@ -340,15 +288,6 @@ final class Tokens {
}
}
static ConfigOrigin getSubstitutionOrigin(Token token) {
if (token instanceof Substitution) {
return ((Substitution) token).origin();
} else {
throw new ConfigException.BugOrBroken(
"tried to get substitution origin from " + token);
}
}
static boolean getSubstitutionOptional(Token token) {
if (token instanceof Substitution) {
return ((Substitution) token).optional();
@ -358,18 +297,18 @@ final class Tokens {
}
}
final static Token START = new Token(TokenType.START, "start of file");
final static Token END = new Token(TokenType.END, "end of file");
final static Token COMMA = new Token(TokenType.COMMA, "','");
final static Token EQUALS = new Token(TokenType.EQUALS, "'='");
final static Token COLON = new Token(TokenType.COLON, "':'");
final static Token OPEN_CURLY = new Token(TokenType.OPEN_CURLY, "'{'");
final static Token CLOSE_CURLY = new Token(TokenType.CLOSE_CURLY, "'}'");
final static Token OPEN_SQUARE = new Token(TokenType.OPEN_SQUARE, "'['");
final static Token CLOSE_SQUARE = new Token(TokenType.CLOSE_SQUARE, "']'");
final static Token START = Token.newWithoutOrigin(TokenType.START, "start of file");
final static Token END = Token.newWithoutOrigin(TokenType.END, "end of file");
final static Token COMMA = Token.newWithoutOrigin(TokenType.COMMA, "','");
final static Token EQUALS = Token.newWithoutOrigin(TokenType.EQUALS, "'='");
final static Token COLON = Token.newWithoutOrigin(TokenType.COLON, "':'");
final static Token OPEN_CURLY = Token.newWithoutOrigin(TokenType.OPEN_CURLY, "'{'");
final static Token CLOSE_CURLY = Token.newWithoutOrigin(TokenType.CLOSE_CURLY, "'}'");
final static Token OPEN_SQUARE = Token.newWithoutOrigin(TokenType.OPEN_SQUARE, "'['");
final static Token CLOSE_SQUARE = Token.newWithoutOrigin(TokenType.CLOSE_SQUARE, "']'");
static Token newLine(int lineNumberJustEnded) {
return new Line(lineNumberJustEnded);
static Token newLine(ConfigOrigin origin) {
return new Line(origin);
}
static Token newProblem(ConfigOrigin origin, String what, String message,

View File

@ -388,6 +388,7 @@ abstract trait TestUtils {
def tokenDouble(d: Double) = Tokens.newDouble(fakeOrigin(), d, null)
def tokenInt(i: Int) = Tokens.newInt(fakeOrigin(), i, null)
def tokenLong(l: Long) = Tokens.newLong(fakeOrigin(), l, null)
def tokenLine(line: Int) = Tokens.newLine(fakeOrigin.setLineNumber(line))
private def tokenMaybeOptionalSubstitution(optional: Boolean, expression: Token*) = {
val l = new java.util.ArrayList[Token]

View File

@ -50,8 +50,8 @@ class TokenTest extends TestUtils {
checkEqualObjects(tokenNull, tokenNull)
// newline
checkEqualObjects(Tokens.newLine(10), Tokens.newLine(10))
checkNotEqualObjects(Tokens.newLine(10), Tokens.newLine(11))
checkEqualObjects(tokenLine(10), tokenLine(10))
checkNotEqualObjects(tokenLine(10), tokenLine(11))
// different types are not equal
checkNotEqualObjects(tokenTrue, tokenInt(1))
@ -71,7 +71,7 @@ class TokenTest extends TestUtils {
tokenUnquoted("foo").toString()
tokenString("bar").toString()
tokenKeySubstitution("a").toString()
Tokens.newLine(10).toString()
tokenLine(10).toString()
Tokens.START.toString()
Tokens.END.toString()
Tokens.COLON.toString()

View File

@ -23,7 +23,7 @@ class TokenizerTest extends TestUtils {
@Test
def tokenizeNewlines() {
assertEquals(List(Tokens.START, Tokens.newLine(1), Tokens.newLine(2), Tokens.END),
assertEquals(List(Tokens.START, tokenLine(1), tokenLine(2), Tokens.END),
tokenizeAsList("\n\n"))
}
@ -37,7 +37,7 @@ class TokenizerTest extends TestUtils {
tokenTrue, tokenDouble(3.14), tokenFalse,
tokenLong(42), tokenNull, tokenSubstitution(tokenUnquoted("a.b")),
tokenOptionalSubstitution(tokenUnquoted("x.y")),
tokenKeySubstitution("c.d"), Tokens.newLine(1), Tokens.END)
tokenKeySubstitution("c.d"), tokenLine(1), Tokens.END)
assertEquals(expected, tokenizeAsList(""",:=}{]["foo"true3.14false42null${a.b}${?x.y}${"c.d"}""" + "\n"))
}
@ -50,7 +50,7 @@ class TokenizerTest extends TestUtils {
tokenUnquoted(" "), tokenSubstitution(tokenUnquoted("a.b")), tokenUnquoted(" "),
tokenOptionalSubstitution(tokenUnquoted("x.y")), tokenUnquoted(" "),
tokenKeySubstitution("c.d"),
Tokens.newLine(1), Tokens.END)
tokenLine(1), Tokens.END)
assertEquals(expected, tokenizeAsList(""" , : = } { ] [ "foo" 42 true 3.14 false null ${a.b} ${?x.y} ${"c.d"} """ + "\n "))
}
@ -63,7 +63,7 @@ class TokenizerTest extends TestUtils {
tokenUnquoted(" "), tokenSubstitution(tokenUnquoted("a.b")), tokenUnquoted(" "),
tokenOptionalSubstitution(tokenUnquoted("x.y")), tokenUnquoted(" "),
tokenKeySubstitution("c.d"),
Tokens.newLine(1), Tokens.END)
tokenLine(1), Tokens.END)
assertEquals(expected, tokenizeAsList(""" , : = } { ] [ "foo" 42 true 3.14 false null ${a.b} ${?x.y} ${"c.d"} """ + "\n "))
}
@ -113,14 +113,14 @@ class TokenizerTest extends TestUtils {
@Test
def tokenizeUnquotedTextTrimsSpaces() {
val expected = List(Tokens.START, tokenUnquoted("foo"), Tokens.newLine(1), Tokens.END)
val expected = List(Tokens.START, tokenUnquoted("foo"), tokenLine(1), Tokens.END)
assertEquals(expected, tokenizeAsList(" foo \n"))
}
@Test
def tokenizeUnquotedTextKeepsInternalSpaces() {
val expected = List(Tokens.START, tokenUnquoted("foo"), tokenUnquoted(" "), tokenUnquoted("bar"),
tokenUnquoted(" "), tokenUnquoted("baz"), Tokens.newLine(1), Tokens.END)
tokenUnquoted(" "), tokenUnquoted("baz"), tokenLine(1), Tokens.END)
assertEquals(expected, tokenizeAsList(" foo bar baz \n"))
}
@ -128,7 +128,7 @@ class TokenizerTest extends TestUtils {
def tokenizeMixedUnquotedQuoted() {
val expected = List(Tokens.START, tokenUnquoted("foo"),
tokenString("bar"), tokenUnquoted("baz"),
Tokens.newLine(1), Tokens.END)
tokenLine(1), Tokens.END)
assertEquals(expected, tokenizeAsList(" foo\"bar\"baz \n"))
}