reimplement Path.newPath using the full parser

This commit is contained in:
Havoc Pennington 2011-11-10 15:04:45 -05:00
parent 859dc082bd
commit d46b068eaf
5 changed files with 45 additions and 16 deletions

View File

@ -214,7 +214,7 @@ final class Parser {
// now save substitution
List<Token> expression = Tokens
.getSubstitutionPathExpression(valueToken);
Path path = parsePathExpression(expression,
Path path = parsePathExpression(expression.iterator(),
Tokens.getSubstitutionOrigin(valueToken));
minimized.add(path);
} else {
@ -447,13 +447,14 @@ final class Parser {
}
}
private static Path parsePathExpression(List<Token> expression,
private static Path parsePathExpression(Iterator<Token> expression,
ConfigOrigin origin) {
// each builder in "buf" is an element in the path.
List<Element> buf = new ArrayList<Element>();
buf.add(new Element("", false));
for (Token t : expression) {
while (expression.hasNext()) {
Token t = expression.next();
if (Tokens.isValueWithType(t, ConfigValueType.STRING)) {
AbstractConfigValue v = Tokens.getValue(t);
// this is a quoted string; so any periods
@ -461,6 +462,11 @@ final class Parser {
String s = v.transformToString();
addPathText(buf, true, s);
} else if (t == Tokens.END) {
// ignore this; when parsing a file, it should not happen
// since we're parsing a token list rather than the main
// token iterator, and when parsing a path expression from the
// API, it's expected to have an END.
} else {
// any periods outside of a quoted string count as
// separators
@ -501,4 +507,14 @@ final class Parser {
return pb.result();
}
static ConfigOrigin apiOrigin = new SimpleConfigOrigin("path parameter");
static Path parsePath(String path) {
StringReader reader = new StringReader(path);
Iterator<Token> tokens = Tokenizer.tokenize(apiOrigin, reader);
tokens.next(); // drop START
return parsePathExpression(tokens, apiOrigin);
}
}

View File

@ -101,8 +101,6 @@ final class Path {
}
static Path newPath(String path) {
PathBuilder pb = new PathBuilder();
pb.appendPath(path);
return pb.result();
return Parser.parsePath(path);
}
}

View File

@ -51,8 +51,10 @@ class ConfParserTest extends TestUtils {
}
private def parsePath(s: String): Path = {
// parse first by wrapping into a whole document and using
// the regular parser.
val tree = parseWithoutResolving("[${" + s + "}]")
tree match {
val result = tree match {
case list: ConfigList =>
list.asJavaList().get(0) match {
case subst: ConfigSubstitution =>
@ -61,6 +63,12 @@ class ConfParserTest extends TestUtils {
}
}
}
// also parse with the standalone path parser and be sure the
// outcome is the same
val shouldBeSame = Parser.parsePath(s)
assertEquals(result, shouldBeSame)
result
}
@Test

View File

@ -9,10 +9,14 @@ class PathTest extends TestUtils {
def pathEquality() {
// note: foo.bar is a single key here
val a = Path.newKey("foo.bar")
// check that newKey worked
assertEquals(path("foo.bar"), a);
val sameAsA = Path.newKey("foo.bar")
val differentKey = Path.newKey("hello")
// here foo.bar is two elements
val twoElements = Path.newPath("foo.bar")
// check that newPath worked
assertEquals(path("foo", "bar"), twoElements);
val sameAsTwoElements = Path.newPath("foo.bar")
checkEqualObjects(a, a)
@ -24,18 +28,18 @@ class PathTest extends TestUtils {
@Test
def pathToString() {
assertEquals("Path(foo)", Path.newPath("foo").toString())
assertEquals("Path(foo.bar)", Path.newPath("foo.bar").toString())
assertEquals("Path(foo.\"bar*\")", Path.newPath("foo.bar*").toString())
assertEquals("Path(\"foo.bar\")", Path.newKey("foo.bar").toString())
assertEquals("Path(foo)", path("foo").toString())
assertEquals("Path(foo.bar)", path("foo", "bar").toString())
assertEquals("Path(foo.\"bar*\")", path("foo", "bar*").toString())
assertEquals("Path(\"foo.bar\")", path("foo.bar").toString())
}
@Test
def pathRender() {
assertEquals("foo", Path.newPath("foo").render())
assertEquals("foo.bar", Path.newPath("foo.bar").render())
assertEquals("foo.\"bar*\"", Path.newPath("foo.bar*").render())
assertEquals("\"foo.bar\"", Path.newKey("foo.bar").render())
assertEquals("foo bar", Path.newKey("foo bar").render())
assertEquals("foo", path("foo").render())
assertEquals("foo.bar", path("foo", "bar").render())
assertEquals("foo.\"bar*\"", path("foo", "bar*").render())
assertEquals("\"foo.bar\"", path("foo.bar").render())
assertEquals("foo bar", path("foo bar").render())
}
}

View File

@ -288,5 +288,8 @@ abstract trait TestUtils {
tokenize(s).asScala.toList
}
// this is importantly NOT using Path.newPath, which relies on
// the parser; in the test suite we are often testing the parser,
// so we don't want to use the parser to build the expected result.
def path(elements: String*) = new Path(elements: _*)
}