Merge pull request #21 from eanderton/master

Element Position Support
diff --git a/cmd/test_program.go b/cmd/test_program.go
index 06ec8b5..65dd8a3 100644
--- a/cmd/test_program.go
+++ b/cmd/test_program.go
@@ -20,7 +20,7 @@
 		os.Exit(1)
 	}
 
-	typedTree := translate((map[string]interface{})(*tree))
+	typedTree := translate(*tree)
 
 	if err := json.NewEncoder(os.Stdout).Encode(typedTree); err != nil {
 		log.Fatalf("Error encoding JSON: %s", err)
@@ -30,7 +30,6 @@
 }
 
 func translate(tomlData interface{}) interface{} {
-
 	switch orig := tomlData.(type) {
 	case map[string]interface{}:
 		typed := make(map[string]interface{}, len(orig))
@@ -39,7 +38,14 @@
 		}
 		return typed
 	case *toml.TomlTree:
-		return translate((map[string]interface{})(*orig))
+		return translate(*orig)
+	case toml.TomlTree:
+		keys := orig.Keys()
+		typed := make(map[string]interface{}, len(keys))
+		for _, k := range keys {
+			typed[k] = translate(orig.GetPath([]string{k}))
+		}
+		return typed
 	case []*toml.TomlTree:
 		typed := make([]map[string]interface{}, len(orig))
 		for i, v := range orig {
diff --git a/lexer.go b/lexer.go
index b13c87b..b6d28b4 100644
--- a/lexer.go
+++ b/lexer.go
@@ -45,11 +45,39 @@
 	tokenEOL
 )
 
+var tokenTypeNames []string = []string{
+	"EOF",
+	"Comment",
+	"Key",
+	"=",
+	"\"",
+	"Integer",
+	"True",
+	"False",
+	"Float",
+	"[",
+	"[",
+	"]]",
+	"[[",
+	"Date",
+	"KeyGroup",
+	"KeyGroupArray",
+	",",
+	"EOL",
+}
+
 type token struct {
-	typ  tokenType
-	val  string
-	line int
-	col  int
+	Position
+	typ tokenType
+	val string
+}
+
+func (tt tokenType) String() string {
+	idx := int(tt)
+	if idx < len(tokenTypeNames) {
+		return tokenTypeNames[idx]
+	}
+	return "Unknown"
 }
 
 func (i token) String() string {
@@ -66,10 +94,6 @@
 	return fmt.Sprintf("%q", i.val)
 }
 
-func (i token) Pos() string {
-	return fmt.Sprintf("(%d, %d)", i.line+1, i.col+1)
-}
-
 func isSpace(r rune) bool {
 	return r == ' ' || r == '\t'
 }
@@ -119,24 +143,31 @@
 		r, width := utf8.DecodeRuneInString(l.input[i:])
 		if r == '\n' {
 			l.line += 1
-			l.col = 0
+			l.col = 1
 		} else {
 			l.col += 1
 		}
 		i += width
-		//    fmt.Printf("'%c'\n", r)
 	}
 	// advance start position to next token
 	l.start = l.pos
 }
 
 func (l *lexer) emit(t tokenType) {
-	l.tokens <- token{t, l.input[l.start:l.pos], l.line, l.col}
+	l.tokens <- token{
+		Position: Position{l.line, l.col},
+		typ:      t,
+		val:      l.input[l.start:l.pos],
+	}
 	l.nextStart()
 }
 
 func (l *lexer) emitWithValue(t tokenType, value string) {
-	l.tokens <- token{t, value, l.line, l.col}
+	l.tokens <- token{
+		Position: Position{l.line, l.col},
+		typ:      t,
+		val:      value,
+	}
 	l.nextStart()
 }
 
@@ -161,10 +192,9 @@
 
 func (l *lexer) errorf(format string, args ...interface{}) stateFn {
 	l.tokens <- token{
-		tokenError,
-		fmt.Sprintf(format, args...),
-		l.line,
-		l.col,
+		Position: Position{l.line, l.col},
+		typ:      tokenError,
+		val:      fmt.Sprintf(format, args...),
 	}
 	return nil
 }
@@ -534,6 +564,8 @@
 	l := &lexer{
 		input:  input,
 		tokens: make(chan token),
+		line:   1,
+		col:    1,
 	}
 	go l.run()
 	return l, l.tokens
diff --git a/lexer_test.go b/lexer_test.go
index afe8d61..20483d7 100644
--- a/lexer_test.go
+++ b/lexer_test.go
@@ -11,8 +11,8 @@
 			t.Log("compared", token, "to", expected)
 			t.Log(token.val, "<->", expected.val)
 			t.Log(token.typ, "<->", expected.typ)
-			t.Log(token.line, "<->", expected.line)
-			t.Log(token.col, "<->", expected.col)
+			t.Log(token.Line, "<->", expected.Line)
+			t.Log(token.Col, "<->", expected.Col)
 			t.FailNow()
 		}
 	}
@@ -32,245 +32,245 @@
 
 func TestValidKeyGroup(t *testing.T) {
 	testFlow(t, "[hello world]", []token{
-		token{tokenLeftBracket, "[", 0, 0},
-		token{tokenKeyGroup, "hello world", 0, 1},
-		token{tokenRightBracket, "]", 0, 12},
-		token{tokenEOF, "", 0, 13},
+		token{Position{1, 1}, tokenLeftBracket, "["},
+		token{Position{1, 2}, tokenKeyGroup, "hello world"},
+		token{Position{1, 13}, tokenRightBracket, "]"},
+		token{Position{1, 14}, tokenEOF, ""},
 	})
 }
 
 func TestUnclosedKeyGroup(t *testing.T) {
 	testFlow(t, "[hello world", []token{
-		token{tokenLeftBracket, "[", 0, 0},
-		token{tokenError, "unclosed key group", 0, 1},
+		token{Position{1, 1}, tokenLeftBracket, "["},
+		token{Position{1, 2}, tokenError, "unclosed key group"},
 	})
 }
 
 func TestComment(t *testing.T) {
 	testFlow(t, "# blahblah", []token{
-		token{tokenEOF, "", 0, 10},
+		token{Position{1, 11}, tokenEOF, ""},
 	})
 }
 
 func TestKeyGroupComment(t *testing.T) {
 	testFlow(t, "[hello world] # blahblah", []token{
-		token{tokenLeftBracket, "[", 0, 0},
-		token{tokenKeyGroup, "hello world", 0, 1},
-		token{tokenRightBracket, "]", 0, 12},
-		token{tokenEOF, "", 0, 24},
+		token{Position{1, 1}, tokenLeftBracket, "["},
+		token{Position{1, 2}, tokenKeyGroup, "hello world"},
+		token{Position{1, 13}, tokenRightBracket, "]"},
+		token{Position{1, 25}, tokenEOF, ""},
 	})
 }
 
 func TestMultipleKeyGroupsComment(t *testing.T) {
 	testFlow(t, "[hello world] # blahblah\n[test]", []token{
-		token{tokenLeftBracket, "[", 0, 0},
-		token{tokenKeyGroup, "hello world", 0, 1},
-		token{tokenRightBracket, "]", 0, 12},
-		token{tokenLeftBracket, "[", 1, 0},
-		token{tokenKeyGroup, "test", 1, 1},
-		token{tokenRightBracket, "]", 1, 5},
-		token{tokenEOF, "", 1, 6},
+		token{Position{1, 1}, tokenLeftBracket, "["},
+		token{Position{1, 2}, tokenKeyGroup, "hello world"},
+		token{Position{1, 13}, tokenRightBracket, "]"},
+		token{Position{2, 1}, tokenLeftBracket, "["},
+		token{Position{2, 2}, tokenKeyGroup, "test"},
+		token{Position{2, 6}, tokenRightBracket, "]"},
+		token{Position{2, 7}, tokenEOF, ""},
 	})
 }
 
 func TestBasicKey(t *testing.T) {
 	testFlow(t, "hello", []token{
-		token{tokenKey, "hello", 0, 0},
-		token{tokenEOF, "", 0, 5},
+		token{Position{1, 1}, tokenKey, "hello"},
+		token{Position{1, 6}, tokenEOF, ""},
 	})
 }
 
 func TestBasicKeyWithUnderscore(t *testing.T) {
 	testFlow(t, "hello_hello", []token{
-		token{tokenKey, "hello_hello", 0, 0},
-		token{tokenEOF, "", 0, 11},
+		token{Position{1, 1}, tokenKey, "hello_hello"},
+		token{Position{1, 12}, tokenEOF, ""},
 	})
 }
 
 func TestBasicKeyWithDash(t *testing.T) {
 	testFlow(t, "hello-world", []token{
-		token{tokenKey, "hello-world", 0, 0},
-		token{tokenEOF, "", 0, 11},
+		token{Position{1, 1}, tokenKey, "hello-world"},
+		token{Position{1, 12}, tokenEOF, ""},
 	})
 }
 
 func TestBasicKeyWithUppercaseMix(t *testing.T) {
 	testFlow(t, "helloHELLOHello", []token{
-		token{tokenKey, "helloHELLOHello", 0, 0},
-		token{tokenEOF, "", 0, 15},
+		token{Position{1, 1}, tokenKey, "helloHELLOHello"},
+		token{Position{1, 16}, tokenEOF, ""},
 	})
 }
 
 func TestBasicKeyWithInternationalCharacters(t *testing.T) {
 	testFlow(t, "héllÖ", []token{
-		token{tokenKey, "héllÖ", 0, 0},
-		token{tokenEOF, "", 0, 5},
+		token{Position{1, 1}, tokenKey, "héllÖ"},
+		token{Position{1, 6}, tokenEOF, ""},
 	})
 }
 
 func TestBasicKeyAndEqual(t *testing.T) {
 	testFlow(t, "hello =", []token{
-		token{tokenKey, "hello", 0, 0},
-		token{tokenEqual, "=", 0, 6},
-		token{tokenEOF, "", 0, 7},
+		token{Position{1, 1}, tokenKey, "hello"},
+		token{Position{1, 7}, tokenEqual, "="},
+		token{Position{1, 8}, tokenEOF, ""},
 	})
 }
 
 func TestKeyWithSharpAndEqual(t *testing.T) {
 	testFlow(t, "key#name = 5", []token{
-		token{tokenKey, "key#name", 0, 0},
-		token{tokenEqual, "=", 0, 9},
-		token{tokenInteger, "5", 0, 11},
-		token{tokenEOF, "", 0, 12},
+		token{Position{1, 1}, tokenKey, "key#name"},
+		token{Position{1, 10}, tokenEqual, "="},
+		token{Position{1, 12}, tokenInteger, "5"},
+		token{Position{1, 13}, tokenEOF, ""},
 	})
 }
 
 func TestKeyWithSymbolsAndEqual(t *testing.T) {
 	testFlow(t, "~!@#$^&*()_+-`1234567890[]\\|/?><.,;:' = 5", []token{
-		token{tokenKey, "~!@#$^&*()_+-`1234567890[]\\|/?><.,;:'", 0, 0},
-		token{tokenEqual, "=", 0, 38},
-		token{tokenInteger, "5", 0, 40},
-		token{tokenEOF, "", 0, 41},
+		token{Position{1, 1}, tokenKey, "~!@#$^&*()_+-`1234567890[]\\|/?><.,;:'"},
+		token{Position{1, 39}, tokenEqual, "="},
+		token{Position{1, 41}, tokenInteger, "5"},
+		token{Position{1, 42}, tokenEOF, ""},
 	})
 }
 
 func TestKeyEqualStringEscape(t *testing.T) {
 	testFlow(t, `foo = "hello\""`, []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenString, "hello\"", 0, 7},
-		token{tokenEOF, "", 0, 15},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 8}, tokenString, "hello\""},
+		token{Position{1, 16}, tokenEOF, ""},
 	})
 }
 
 func TestKeyEqualStringUnfinished(t *testing.T) {
 	testFlow(t, `foo = "bar`, []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenError, "unclosed string", 0, 7},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 8}, tokenError, "unclosed string"},
 	})
 }
 
 func TestKeyEqualString(t *testing.T) {
 	testFlow(t, `foo = "bar"`, []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenString, "bar", 0, 7},
-		token{tokenEOF, "", 0, 11},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 8}, tokenString, "bar"},
+		token{Position{1, 12}, tokenEOF, ""},
 	})
 }
 
 func TestKeyEqualTrue(t *testing.T) {
 	testFlow(t, "foo = true", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenTrue, "true", 0, 6},
-		token{tokenEOF, "", 0, 10},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenTrue, "true"},
+		token{Position{1, 11}, tokenEOF, ""},
 	})
 }
 
 func TestKeyEqualFalse(t *testing.T) {
 	testFlow(t, "foo = false", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenFalse, "false", 0, 6},
-		token{tokenEOF, "", 0, 11},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenFalse, "false"},
+		token{Position{1, 12}, tokenEOF, ""},
 	})
 }
 
 func TestArrayNestedString(t *testing.T) {
 	testFlow(t, `a = [ ["hello", "world"] ]`, []token{
-		token{tokenKey, "a", 0, 0},
-		token{tokenEqual, "=", 0, 2},
-		token{tokenLeftBracket, "[", 0, 4},
-		token{tokenLeftBracket, "[", 0, 6},
-		token{tokenString, "hello", 0, 8},
-		token{tokenComma, ",", 0, 14},
-		token{tokenString, "world", 0, 17},
-		token{tokenRightBracket, "]", 0, 23},
-		token{tokenRightBracket, "]", 0, 25},
-		token{tokenEOF, "", 0, 26},
+		token{Position{1, 1}, tokenKey, "a"},
+		token{Position{1, 3}, tokenEqual, "="},
+		token{Position{1, 5}, tokenLeftBracket, "["},
+		token{Position{1, 7}, tokenLeftBracket, "["},
+		token{Position{1, 9}, tokenString, "hello"},
+		token{Position{1, 15}, tokenComma, ","},
+		token{Position{1, 18}, tokenString, "world"},
+		token{Position{1, 24}, tokenRightBracket, "]"},
+		token{Position{1, 26}, tokenRightBracket, "]"},
+		token{Position{1, 27}, tokenEOF, ""},
 	})
 }
 
 func TestArrayNestedInts(t *testing.T) {
 	testFlow(t, "a = [ [42, 21], [10] ]", []token{
-		token{tokenKey, "a", 0, 0},
-		token{tokenEqual, "=", 0, 2},
-		token{tokenLeftBracket, "[", 0, 4},
-		token{tokenLeftBracket, "[", 0, 6},
-		token{tokenInteger, "42", 0, 7},
-		token{tokenComma, ",", 0, 9},
-		token{tokenInteger, "21", 0, 11},
-		token{tokenRightBracket, "]", 0, 13},
-		token{tokenComma, ",", 0, 14},
-		token{tokenLeftBracket, "[", 0, 16},
-		token{tokenInteger, "10", 0, 17},
-		token{tokenRightBracket, "]", 0, 19},
-		token{tokenRightBracket, "]", 0, 21},
-		token{tokenEOF, "", 0, 22},
+		token{Position{1, 1}, tokenKey, "a"},
+		token{Position{1, 3}, tokenEqual, "="},
+		token{Position{1, 5}, tokenLeftBracket, "["},
+		token{Position{1, 7}, tokenLeftBracket, "["},
+		token{Position{1, 8}, tokenInteger, "42"},
+		token{Position{1, 10}, tokenComma, ","},
+		token{Position{1, 12}, tokenInteger, "21"},
+		token{Position{1, 14}, tokenRightBracket, "]"},
+		token{Position{1, 15}, tokenComma, ","},
+		token{Position{1, 17}, tokenLeftBracket, "["},
+		token{Position{1, 18}, tokenInteger, "10"},
+		token{Position{1, 20}, tokenRightBracket, "]"},
+		token{Position{1, 22}, tokenRightBracket, "]"},
+		token{Position{1, 23}, tokenEOF, ""},
 	})
 }
 
 func TestArrayInts(t *testing.T) {
 	testFlow(t, "a = [ 42, 21, 10, ]", []token{
-		token{tokenKey, "a", 0, 0},
-		token{tokenEqual, "=", 0, 2},
-		token{tokenLeftBracket, "[", 0, 4},
-		token{tokenInteger, "42", 0, 6},
-		token{tokenComma, ",", 0, 8},
-		token{tokenInteger, "21", 0, 10},
-		token{tokenComma, ",", 0, 12},
-		token{tokenInteger, "10", 0, 14},
-		token{tokenComma, ",", 0, 16},
-		token{tokenRightBracket, "]", 0, 18},
-		token{tokenEOF, "", 0, 19},
+		token{Position{1, 1}, tokenKey, "a"},
+		token{Position{1, 3}, tokenEqual, "="},
+		token{Position{1, 5}, tokenLeftBracket, "["},
+		token{Position{1, 7}, tokenInteger, "42"},
+		token{Position{1, 9}, tokenComma, ","},
+		token{Position{1, 11}, tokenInteger, "21"},
+		token{Position{1, 13}, tokenComma, ","},
+		token{Position{1, 15}, tokenInteger, "10"},
+		token{Position{1, 17}, tokenComma, ","},
+		token{Position{1, 19}, tokenRightBracket, "]"},
+		token{Position{1, 20}, tokenEOF, ""},
 	})
 }
 
 func TestMultilineArrayComments(t *testing.T) {
 	testFlow(t, "a = [1, # wow\n2, # such items\n3, # so array\n]", []token{
-		token{tokenKey, "a", 0, 0},
-		token{tokenEqual, "=", 0, 2},
-		token{tokenLeftBracket, "[", 0, 4},
-		token{tokenInteger, "1", 0, 5},
-		token{tokenComma, ",", 0, 6},
-		token{tokenInteger, "2", 1, 0},
-		token{tokenComma, ",", 1, 1},
-		token{tokenInteger, "3", 2, 0},
-		token{tokenComma, ",", 2, 1},
-		token{tokenRightBracket, "]", 3, 0},
-		token{tokenEOF, "", 3, 1},
+		token{Position{1, 1}, tokenKey, "a"},
+		token{Position{1, 3}, tokenEqual, "="},
+		token{Position{1, 5}, tokenLeftBracket, "["},
+		token{Position{1, 6}, tokenInteger, "1"},
+		token{Position{1, 7}, tokenComma, ","},
+		token{Position{2, 1}, tokenInteger, "2"},
+		token{Position{2, 2}, tokenComma, ","},
+		token{Position{3, 1}, tokenInteger, "3"},
+		token{Position{3, 2}, tokenComma, ","},
+		token{Position{4, 1}, tokenRightBracket, "]"},
+		token{Position{4, 2}, tokenEOF, ""},
 	})
 }
 
 func TestKeyEqualArrayBools(t *testing.T) {
 	testFlow(t, "foo = [true, false, true]", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenLeftBracket, "[", 0, 6},
-		token{tokenTrue, "true", 0, 7},
-		token{tokenComma, ",", 0, 11},
-		token{tokenFalse, "false", 0, 13},
-		token{tokenComma, ",", 0, 18},
-		token{tokenTrue, "true", 0, 20},
-		token{tokenRightBracket, "]", 0, 24},
-		token{tokenEOF, "", 0, 25},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenLeftBracket, "["},
+		token{Position{1, 8}, tokenTrue, "true"},
+		token{Position{1, 12}, tokenComma, ","},
+		token{Position{1, 14}, tokenFalse, "false"},
+		token{Position{1, 19}, tokenComma, ","},
+		token{Position{1, 21}, tokenTrue, "true"},
+		token{Position{1, 25}, tokenRightBracket, "]"},
+		token{Position{1, 26}, tokenEOF, ""},
 	})
 }
 
 func TestKeyEqualArrayBoolsWithComments(t *testing.T) {
 	testFlow(t, "foo = [true, false, true] # YEAH", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenLeftBracket, "[", 0, 6},
-		token{tokenTrue, "true", 0, 7},
-		token{tokenComma, ",", 0, 11},
-		token{tokenFalse, "false", 0, 13},
-		token{tokenComma, ",", 0, 18},
-		token{tokenTrue, "true", 0, 20},
-		token{tokenRightBracket, "]", 0, 24},
-		token{tokenEOF, "", 0, 32},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenLeftBracket, "["},
+		token{Position{1, 8}, tokenTrue, "true"},
+		token{Position{1, 12}, tokenComma, ","},
+		token{Position{1, 14}, tokenFalse, "false"},
+		token{Position{1, 19}, tokenComma, ","},
+		token{Position{1, 21}, tokenTrue, "true"},
+		token{Position{1, 25}, tokenRightBracket, "]"},
+		token{Position{1, 33}, tokenEOF, ""},
 	})
 }
 
@@ -282,138 +282,138 @@
 
 func TestKeyEqualDate(t *testing.T) {
 	testFlow(t, "foo = 1979-05-27T07:32:00Z", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenDate, "1979-05-27T07:32:00Z", 0, 6},
-		token{tokenEOF, "", 0, 26},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenDate, "1979-05-27T07:32:00Z"},
+		token{Position{1, 27}, tokenEOF, ""},
 	})
 }
 
 func TestFloatEndingWithDot(t *testing.T) {
 	testFlow(t, "foo = 42.", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenError, "float cannot end with a dot", 0, 6},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenError, "float cannot end with a dot"},
 	})
 }
 
 func TestFloatWithTwoDots(t *testing.T) {
 	testFlow(t, "foo = 4.2.", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenError, "cannot have two dots in one float", 0, 6},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenError, "cannot have two dots in one float"},
 	})
 }
 
 func TestDoubleEqualKey(t *testing.T) {
 	testFlow(t, "foo= = 2", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 3},
-		token{tokenError, "cannot have multiple equals for the same key", 0, 4},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 4}, tokenEqual, "="},
+		token{Position{1, 5}, tokenError, "cannot have multiple equals for the same key"},
 	})
 }
 
 func TestInvalidEsquapeSequence(t *testing.T) {
 	testFlow(t, `foo = "\x"`, []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenError, "invalid escape sequence: \\x", 0, 7},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 8}, tokenError, "invalid escape sequence: \\x"},
 	})
 }
 
 func TestNestedArrays(t *testing.T) {
 	testFlow(t, "foo = [[[]]]", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenLeftBracket, "[", 0, 6},
-		token{tokenLeftBracket, "[", 0, 7},
-		token{tokenLeftBracket, "[", 0, 8},
-		token{tokenRightBracket, "]", 0, 9},
-		token{tokenRightBracket, "]", 0, 10},
-		token{tokenRightBracket, "]", 0, 11},
-		token{tokenEOF, "", 0, 12},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenLeftBracket, "["},
+		token{Position{1, 8}, tokenLeftBracket, "["},
+		token{Position{1, 9}, tokenLeftBracket, "["},
+		token{Position{1, 10}, tokenRightBracket, "]"},
+		token{Position{1, 11}, tokenRightBracket, "]"},
+		token{Position{1, 12}, tokenRightBracket, "]"},
+		token{Position{1, 13}, tokenEOF, ""},
 	})
 }
 
 func TestKeyEqualNumber(t *testing.T) {
 	testFlow(t, "foo = 42", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenInteger, "42", 0, 6},
-		token{tokenEOF, "", 0, 8},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenInteger, "42"},
+		token{Position{1, 9}, tokenEOF, ""},
 	})
 
 	testFlow(t, "foo = +42", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenInteger, "+42", 0, 6},
-		token{tokenEOF, "", 0, 9},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenInteger, "+42"},
+		token{Position{1, 10}, tokenEOF, ""},
 	})
 
 	testFlow(t, "foo = -42", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenInteger, "-42", 0, 6},
-		token{tokenEOF, "", 0, 9},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenInteger, "-42"},
+		token{Position{1, 10}, tokenEOF, ""},
 	})
 
 	testFlow(t, "foo = 4.2", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenFloat, "4.2", 0, 6},
-		token{tokenEOF, "", 0, 9},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenFloat, "4.2"},
+		token{Position{1, 10}, tokenEOF, ""},
 	})
 
 	testFlow(t, "foo = +4.2", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenFloat, "+4.2", 0, 6},
-		token{tokenEOF, "", 0, 10},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenFloat, "+4.2"},
+		token{Position{1, 11}, tokenEOF, ""},
 	})
 
 	testFlow(t, "foo = -4.2", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenFloat, "-4.2", 0, 6},
-		token{tokenEOF, "", 0, 10},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenFloat, "-4.2"},
+		token{Position{1, 11}, tokenEOF, ""},
 	})
 }
 
 func TestMultiline(t *testing.T) {
 	testFlow(t, "foo = 42\nbar=21", []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenInteger, "42", 0, 6},
-		token{tokenKey, "bar", 1, 0},
-		token{tokenEqual, "=", 1, 3},
-		token{tokenInteger, "21", 1, 4},
-		token{tokenEOF, "", 1, 6},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 7}, tokenInteger, "42"},
+		token{Position{2, 1}, tokenKey, "bar"},
+		token{Position{2, 4}, tokenEqual, "="},
+		token{Position{2, 5}, tokenInteger, "21"},
+		token{Position{2, 7}, tokenEOF, ""},
 	})
 }
 
 func TestKeyEqualStringUnicodeEscape(t *testing.T) {
 	testFlow(t, `foo = "hello \u2665"`, []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenString, "hello ♥", 0, 7},
-		token{tokenEOF, "", 0, 20},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 8}, tokenString, "hello ♥"},
+		token{Position{1, 21}, tokenEOF, ""},
 	})
 }
 
 func TestUnicodeString(t *testing.T) {
 	testFlow(t, `foo = "hello ♥ world"`, []token{
-		token{tokenKey, "foo", 0, 0},
-		token{tokenEqual, "=", 0, 4},
-		token{tokenString, "hello ♥ world", 0, 7},
-		token{tokenEOF, "", 0, 21},
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 8}, tokenString, "hello ♥ world"},
+		token{Position{1, 22}, tokenEOF, ""},
 	})
 }
 
 func TestKeyGroupArray(t *testing.T) {
 	testFlow(t, "[[foo]]", []token{
-		token{tokenDoubleLeftBracket, "[[", 0, 0},
-		token{tokenKeyGroupArray, "foo", 0, 2},
-		token{tokenDoubleRightBracket, "]]", 0, 5},
-		token{tokenEOF, "", 0, 7},
+		token{Position{1, 1}, tokenDoubleLeftBracket, "[["},
+		token{Position{1, 3}, tokenKeyGroupArray, "foo"},
+		token{Position{1, 6}, tokenDoubleRightBracket, "]]"},
+		token{Position{1, 8}, tokenEOF, ""},
 	})
 }
diff --git a/parser.go b/parser.go
index 17cd308..9945d39 100644
--- a/parser.go
+++ b/parser.go
@@ -22,7 +22,7 @@
 
 // Formats and panics an error message based on a token
 func (p *parser) raiseError(tok *token, msg string, args ...interface{}) {
-	panic(tok.Pos() + ": " + fmt.Sprintf(msg, args...))
+	panic(tok.Position.String() + ": " + fmt.Sprintf(msg, args...))
 }
 
 func (p *parser) run() {
@@ -47,10 +47,10 @@
 func (p *parser) assume(typ tokenType) {
 	tok := p.getToken()
 	if tok == nil {
-		p.raiseError(tok, "was expecting token %s, but token stream is empty", tok.typ)
+		p.raiseError(tok, "was expecting token %s, but token stream is empty", tok)
 	}
 	if tok.typ != typ {
-		p.raiseError(tok, "was expecting token %s, but got %s", typ, tok.typ)
+		p.raiseError(tok, "was expecting token %s, but got %s instead", typ, tok)
 	}
 }
 
@@ -70,6 +70,9 @@
 func parseStart(p *parser) parserStateFn {
 	tok := p.peek()
 
+	// prime position data with root tree instance
+	p.tree.position = tok.Position
+
 	// end of stream, parsing is finished
 	if tok == nil {
 		return nil
@@ -91,15 +94,16 @@
 }
 
 func parseGroupArray(p *parser) parserStateFn {
-	p.getToken() // discard the [[
+	start_token := p.getToken() // discard the [[
 	key := p.getToken()
 	if key.typ != tokenKeyGroupArray {
 		p.raiseError(key, "unexpected token %s, was expecting a key group array", key)
 	}
 
 	// get or create group array element at the indicated part in the path
-	p.currentGroup = strings.Split(key.val, ".")
-	dest_tree := p.tree.GetPath(p.currentGroup)
+	keys := strings.Split(key.val, ".")
+	p.tree.createSubTree(keys[:len(keys)-1]) // create parent entries
+	dest_tree := p.tree.GetPath(keys)
 	var array []*TomlTree
 	if dest_tree == nil {
 		array = make([]*TomlTree, 0)
@@ -108,14 +112,31 @@
 	} else {
 		p.raiseError(key, "key %s is already assigned and not of type group array", key)
 	}
+	p.currentGroup = keys
 
 	// add a new tree to the end of the group array
-	new_tree := make(TomlTree)
-	array = append(array, &new_tree)
+	new_tree := newTomlTree()
+	new_tree.position = start_token.Position
+	array = append(array, new_tree)
 	p.tree.SetPath(p.currentGroup, array)
 
+	// remove all keys that were children of this group array
+	prefix := key.val + "."
+	found := false
+	for ii := 0; ii < len(p.seenGroupKeys); {
+		groupKey := p.seenGroupKeys[ii]
+		if strings.HasPrefix(groupKey, prefix) {
+			p.seenGroupKeys = append(p.seenGroupKeys[:ii], p.seenGroupKeys[ii+1:]...)
+		} else {
+			found = (groupKey == key.val)
+			ii++
+		}
+	}
+
 	// keep this key name from use by other kinds of assignments
-	p.seenGroupKeys = append(p.seenGroupKeys, key.val)
+	if !found {
+		p.seenGroupKeys = append(p.seenGroupKeys, key.val)
+	}
 
 	// move to next parser state
 	p.assume(tokenDoubleRightBracket)
@@ -123,7 +144,7 @@
 }
 
 func parseGroup(p *parser) parserStateFn {
-	p.getToken() // discard the [
+	start_token := p.getToken() // discard the [
 	key := p.getToken()
 	if key.typ != tokenKeyGroup {
 		p.raiseError(key, "unexpected token %s, was expecting a key group", key)
@@ -133,12 +154,16 @@
 			p.raiseError(key, "duplicated tables")
 		}
 	}
+
 	p.seenGroupKeys = append(p.seenGroupKeys, key.val)
-	if err := p.tree.createSubTree(key.val); err != nil {
+	keys := strings.Split(key.val, ".")
+	if err := p.tree.createSubTree(keys); err != nil {
 		p.raiseError(key, "%s", err)
 	}
 	p.assume(tokenRightBracket)
-	p.currentGroup = strings.Split(key.val, ".")
+	p.currentGroup = keys
+	target_tree := p.tree.GetPath(p.currentGroup).(*TomlTree)
+	target_tree.position = start_token.Position
 	return parseStart(p)
 }
 
@@ -150,7 +175,7 @@
 	if len(p.currentGroup) > 0 {
 		group_key = p.currentGroup
 	} else {
-		group_key = make([]string, 0)
+		group_key = []string{}
 	}
 
 	// find the group to assign, looking out for arrays of groups
@@ -161,16 +186,18 @@
 	case *TomlTree:
 		target_node = node
 	default:
-		p.raiseError(key, "Unknown group type for path %s", group_key)
+		p.raiseError(key, "Unknown group type for path: %s",
+			strings.Join(group_key, "."))
 	}
 
 	// assign value to the found group
 	local_key := []string{key.val}
 	final_key := append(group_key, key.val)
 	if target_node.GetPath(local_key) != nil {
-		p.raiseError(key, "the following key was defined twice: %s", strings.Join(final_key, "."))
+		p.raiseError(key, "The following key was defined twice: %s",
+			strings.Join(final_key, "."))
 	}
-	target_node.SetPath(local_key, value)
+	target_node.values[key.val] = &tomlValue{value, key.Position}
 	return parseStart(p)
 }
 
@@ -251,14 +278,14 @@
 }
 
 func parse(flow chan token) *TomlTree {
-	result := make(TomlTree)
+	result := newTomlTree()
 	parser := &parser{
 		flow:          flow,
-		tree:          &result,
+		tree:          result,
 		tokensBuffer:  make([]token, 0),
 		currentGroup:  make([]string, 0),
 		seenGroupKeys: make([]string, 0),
 	}
 	parser.run()
-	return parser.tree
+	return result
 }
diff --git a/parser_test.go b/parser_test.go
index 20b9dd8..761a181 100644
--- a/parser_test.go
+++ b/parser_test.go
@@ -12,14 +12,15 @@
 		return
 	}
 	for k, v := range ref {
-		node := tree.Get(k)
-		switch cast_node := node.(type) {
+		// NOTE: directly access key instead of resolve by path
+		// NOTE: see TestSpecialKV
+		switch node := tree.GetPath([]string{k}).(type) {
 		case []*TomlTree:
-			for idx, item := range cast_node {
+			for idx, item := range node {
 				assertTree(t, item, err, v.([]map[string]interface{})[idx])
 			}
 		case *TomlTree:
-			assertTree(t, cast_node, err, v.(map[string]interface{}))
+			assertTree(t, node, err, v.(map[string]interface{}))
 		default:
 			if fmt.Sprintf("%v", node) != fmt.Sprintf("%v", v) {
 				t.Errorf("was expecting %v at %v but got %v", v, k, node)
@@ -29,8 +30,8 @@
 }
 
 func TestCreateSubTree(t *testing.T) {
-	tree := make(TomlTree)
-	tree.createSubTree("a.b.c")
+	tree := newTomlTree()
+	tree.createSubTree([]string{"a", "b", "c"})
 	tree.Set("a.b.c", 42)
 	if tree.Get("a.b.c") != 42 {
 		t.Fail()
@@ -50,6 +51,15 @@
 	})
 }
 
+// NOTE: from the BurntSushi test suite
+// NOTE: this test is pure evil due to the embedded '.'
+func TestSpecialKV(t *testing.T) {
+	tree, err := Load("~!@#$^&*()_+-`1234567890[]\\|/?><.,;: = 1")
+	assertTree(t, tree, err, map[string]interface{}{
+		"~!@#$^&*()_+-`1234567890[]\\|/?><.,;:": int64(1),
+	})
+}
+
 func TestSimpleNumbers(t *testing.T) {
 	tree, err := Load("a = +42\nb = -21\nc = +4.2\nd = -2.1")
 	assertTree(t, tree, err, map[string]interface{}{
@@ -107,7 +117,13 @@
 func TestNestedKeys(t *testing.T) {
 	tree, err := Load("[a.b.c]\nd = 42")
 	assertTree(t, tree, err, map[string]interface{}{
-		"a.b.c.d": int64(42),
+		"a": map[string]interface{}{
+			"b": map[string]interface{}{
+				"c": map[string]interface{}{
+					"d": int64(42),
+				},
+			},
+		},
 	})
 }
 
@@ -221,7 +237,7 @@
 
 func TestDuplicateKeys(t *testing.T) {
 	_, err := Load("foo = 2\nfoo = 3")
-	if err.Error() != "(2, 1): the following key was defined twice: foo" {
+	if err.Error() != "(2, 1): The following key was defined twice: foo" {
 		t.Error("Bad error message:", err.Error())
 	}
 }
@@ -270,20 +286,35 @@
 	tree, err := LoadFile("example.toml")
 
 	assertTree(t, tree, err, map[string]interface{}{
-		"title":                   "TOML Example",
-		"owner.name":              "Tom Preston-Werner",
-		"owner.organization":      "GitHub",
-		"owner.bio":               "GitHub Cofounder & CEO\nLikes tater tots and beer.",
-		"owner.dob":               time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC),
-		"database.server":         "192.168.1.1",
-		"database.ports":          []int64{8001, 8001, 8002},
-		"database.connection_max": 5000,
-		"database.enabled":        true,
-		"servers.alpha.ip":        "10.0.0.1",
-		"servers.alpha.dc":        "eqdc10",
-		"servers.beta.ip":         "10.0.0.2",
-		"servers.beta.dc":         "eqdc10",
-		"clients.data":            []interface{}{[]string{"gamma", "delta"}, []int64{1, 2}},
+		"title": "TOML Example",
+		"owner": map[string]interface{}{
+			"name":         "Tom Preston-Werner",
+			"organization": "GitHub",
+			"bio":          "GitHub Cofounder & CEO\nLikes tater tots and beer.",
+			"dob":          time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC),
+		},
+		"database": map[string]interface{}{
+			"server":         "192.168.1.1",
+			"ports":          []int64{8001, 8001, 8002},
+			"connection_max": 5000,
+			"enabled":        true,
+		},
+		"servers": map[string]interface{}{
+			"alpha": map[string]interface{}{
+				"ip": "10.0.0.1",
+				"dc": "eqdc10",
+			},
+			"beta": map[string]interface{}{
+				"ip": "10.0.0.2",
+				"dc": "eqdc10",
+			},
+		},
+		"clients": map[string]interface{}{
+			"data": []interface{}{
+				[]string{"gamma", "delta"},
+				[]int64{1, 2},
+			},
+		},
 	})
 }
 
@@ -333,17 +364,72 @@
 }
 
 func TestToString(t *testing.T) {
-	tree := &TomlTree{
-		"foo": &TomlTree{
-			"bar": []*TomlTree{
-				{"a": int64(42)},
-				{"a": int64(69)},
-			},
-		},
+	tree, err := Load("[foo]\n\n[[foo.bar]]\na = 42\n\n[[foo.bar]]\na = 69\n")
+	if err != nil {
+		t.Errorf("Test failed to parse: %v", err)
+		return
 	}
 	result := tree.ToString()
-	expected := "\n[foo]\n\n[[foo.bar]]\na = 42\n\n[[foo.bar]]\na = 69\n"
+	expected := "\n[foo]\n\n  [[foo.bar]]\n    a = 42\n\n  [[foo.bar]]\n    a = 69\n"
 	if result != expected {
 		t.Errorf("Expected got '%s', expected '%s'", result, expected)
 	}
 }
+
+func assertPosition(t *testing.T, text string, ref map[string]Position) {
+	tree, err := Load(text)
+	if err != nil {
+		t.Errorf("Error loading document text: `%v`", text)
+		t.Errorf("Error: %v", err)
+	}
+	for path, pos := range ref {
+		testPos := tree.GetPosition(path)
+		if testPos.Invalid() {
+			t.Errorf("Failed to query tree path: %s", path)
+		} else if pos != testPos {
+			t.Errorf("Expected position %v, got %v instead", pos, testPos)
+		}
+	}
+}
+
+func TestDocumentPositions(t *testing.T) {
+	assertPosition(t,
+		"[foo]\nbar=42\nbaz=69",
+		map[string]Position{
+			"foo":     Position{1, 1},
+			"foo.bar": Position{2, 1},
+			"foo.baz": Position{3, 1},
+		})
+}
+
+func TestDocumentPositionsWithSpaces(t *testing.T) {
+	assertPosition(t,
+		"  [foo]\n  bar=42\n  baz=69",
+		map[string]Position{
+			"foo":     Position{1, 3},
+			"foo.bar": Position{2, 3},
+			"foo.baz": Position{3, 3},
+		})
+}
+
+func TestDocumentPositionsWithGroupArray(t *testing.T) {
+	assertPosition(t,
+		"[[foo]]\nbar=42\nbaz=69",
+		map[string]Position{
+			"foo":     Position{1, 1},
+			"foo.bar": Position{2, 1},
+			"foo.baz": Position{3, 1},
+		})
+}
+
+func TestDocumentPositionsEmptyPath(t *testing.T) {
+	text := "[foo]\nbar=42\nbaz=69"
+	tree, err := Load(text)
+	if err != nil {
+		t.Errorf("Error loading document text: `%v`", text)
+		t.Errorf("Error: %v", err)
+	}
+	if pos := tree.GetPosition(""); !pos.Invalid() {
+		t.Errorf("Valid position was returned for empty path")
+	}
+}
diff --git a/position.go b/position.go
new file mode 100644
index 0000000..266bfcb
--- /dev/null
+++ b/position.go
@@ -0,0 +1,23 @@
+// Position support for go-toml
+
+package toml
+
+import (
+	"fmt"
+)
+
+// position within a TOML document
+type Position struct {
+	Line int // line within the document
+	Col  int // column within the line
+}
+
+// String representation of the position.
+// Displays 1-indexed line and column numbers.
+func (p *Position) String() string {
+	return fmt.Sprintf("(%d, %d)", p.Line, p.Col)
+}
+
+func (p *Position) Invalid() bool {
+	return p.Line <= 0 || p.Col <= 0
+}
diff --git a/position_test.go b/position_test.go
new file mode 100644
index 0000000..4cf0ebd
--- /dev/null
+++ b/position_test.go
@@ -0,0 +1,29 @@
+// Testing support for go-toml
+
+package toml
+
+import (
+	"testing"
+)
+
+func TestPositionString(t *testing.T) {
+	p := Position{123, 456}
+	expected := "(123, 456)"
+	value := p.String()
+
+	if value != expected {
+		t.Errorf("Expected %v, got %v instead", expected, value)
+	}
+}
+
+func TestInvalid(t *testing.T) {
+	for i, v := range []Position{
+		Position{0, 1234},
+		Position{1234, 0},
+		Position{0, 0},
+	} {
+		if !v.Invalid() {
+			t.Errorf("Position at %v is valid: %v", i, v)
+		}
+	}
+}
diff --git a/toml.go b/toml.go
index 8beb392..aa2ab6b 100644
--- a/toml.go
+++ b/toml.go
@@ -14,9 +14,24 @@
 	"time"
 )
 
+type tomlValue struct {
+	value    interface{}
+	position Position
+}
+
 // Definition of a TomlTree.
 // This is the result of the parsing of a TOML file.
-type TomlTree map[string]interface{}
+type TomlTree struct {
+	values   map[string]interface{}
+	position Position
+}
+
+func newTomlTree() *TomlTree {
+	return &TomlTree{
+		values:   make(map[string]interface{}),
+		position: Position{0, 0},
+	}
+}
 
 // Has returns a boolean indicating if the given key exists.
 func (t *TomlTree) Has(key string) bool {
@@ -28,35 +43,14 @@
 
 // Returns true if the given path of keys exists, false otherwise.
 func (t *TomlTree) HasPath(keys []string) bool {
-	if len(keys) == 0 {
-		return false
-	}
-	subtree := t
-	for _, intermediate_key := range keys[:len(keys)-1] {
-		_, exists := (*subtree)[intermediate_key]
-		if !exists {
-			return false
-		}
-		switch node := (*subtree)[intermediate_key].(type) {
-		case *TomlTree:
-			subtree = node
-		case []*TomlTree:
-			// go to most recent element
-			if len(node) == 0 {
-				return false
-			}
-			subtree = node[len(node)-1]
-		}
-	}
-	return true
+	return t.GetPath(keys) != nil
 }
 
 // Keys returns the keys of the toplevel tree.
 // Warning: this is a costly operation.
 func (t *TomlTree) Keys() []string {
 	keys := make([]string, 0)
-	mp := (map[string]interface{})(*t)
-	for k, _ := range mp {
+	for k, _ := range t.values {
 		keys = append(keys, k)
 	}
 	return keys
@@ -81,22 +75,79 @@
 	}
 	subtree := t
 	for _, intermediate_key := range keys[:len(keys)-1] {
-		_, exists := (*subtree)[intermediate_key]
+		value, exists := subtree.values[intermediate_key]
 		if !exists {
 			return nil
 		}
-		switch node := (*subtree)[intermediate_key].(type) {
+		switch node := value.(type) {
 		case *TomlTree:
 			subtree = node
 		case []*TomlTree:
 			// go to most recent element
 			if len(node) == 0 {
-				return nil //(*subtree)[intermediate_key] = append(node, &TomlTree{})
+				return nil
 			}
 			subtree = node[len(node)-1]
+		default:
+			return nil // cannot naigate through other node types
 		}
 	}
-	return (*subtree)[keys[len(keys)-1]]
+	// branch based on final node type
+	switch node := subtree.values[keys[len(keys)-1]].(type) {
+	case *tomlValue:
+		return node.value
+	default:
+		return node
+	}
+}
+
+func (t *TomlTree) GetPosition(key string) Position {
+	if key == "" {
+		return Position{0, 0}
+	}
+	return t.GetPositionPath(strings.Split(key, "."))
+}
+
+// Returns the element in the tree indicated by 'keys'.
+// If keys is of length zero, the current tree is returned.
+func (t *TomlTree) GetPositionPath(keys []string) Position {
+	if len(keys) == 0 {
+		return t.position
+	}
+	subtree := t
+	for _, intermediate_key := range keys[:len(keys)-1] {
+		value, exists := subtree.values[intermediate_key]
+		if !exists {
+			return Position{0, 0}
+		}
+		switch node := value.(type) {
+		case *TomlTree:
+			subtree = node
+		case []*TomlTree:
+			// go to most recent element
+			if len(node) == 0 {
+				return Position{0, 0}
+			}
+			subtree = node[len(node)-1]
+		default:
+			return Position{0, 0}
+		}
+	}
+	// branch based on final node type
+	switch node := subtree.values[keys[len(keys)-1]].(type) {
+	case *tomlValue:
+		return node.position
+	case *TomlTree:
+		return node.position
+	case []*TomlTree:
+		// go to most recent element
+		if len(node) == 0 {
+			return Position{0, 0}
+		}
+		return node[len(node)-1].position
+	default:
+		return Position{0, 0}
+	}
 }
 
 // Same as Get but with a default value
@@ -115,26 +166,30 @@
 	t.SetPath(strings.Split(key, "."), value)
 }
 
+// Set an element in the tree.
+// Keys is an array of path elements (e.g. {"a","b","c"}).
+// Creates all necessary intermediates trees, if needed.
 func (t *TomlTree) SetPath(keys []string, value interface{}) {
 	subtree := t
 	for _, intermediate_key := range keys[:len(keys)-1] {
-		_, exists := (*subtree)[intermediate_key]
+		nextTree, exists := subtree.values[intermediate_key]
 		if !exists {
-			var new_tree TomlTree = make(TomlTree)
-			(*subtree)[intermediate_key] = &new_tree
+			nextTree = newTomlTree()
+			subtree.values[intermediate_key] = &nextTree // add new element here
 		}
-		switch node := (*subtree)[intermediate_key].(type) {
+		switch node := nextTree.(type) {
 		case *TomlTree:
 			subtree = node
 		case []*TomlTree:
 			// go to most recent element
 			if len(node) == 0 {
-				(*subtree)[intermediate_key] = append(node, &TomlTree{})
+				// create element if it does not exist
+				subtree.values[intermediate_key] = append(node, newTomlTree())
 			}
 			subtree = node[len(node)-1]
 		}
 	}
-	(*subtree)[keys[len(keys)-1]] = value
+	subtree.values[keys[len(keys)-1]] = value
 }
 
 // createSubTree takes a tree and a key and create the necessary intermediate
@@ -144,25 +199,26 @@
 // and tree[a][b][c]
 //
 // Returns nil on success, error object on failure
-func (t *TomlTree) createSubTree(key string) error {
+func (t *TomlTree) createSubTree(keys []string) error {
 	subtree := t
-	for _, intermediate_key := range strings.Split(key, ".") {
+	for _, intermediate_key := range keys {
 		if intermediate_key == "" {
 			return fmt.Errorf("empty intermediate table")
 		}
-		_, exists := (*subtree)[intermediate_key]
+		nextTree, exists := subtree.values[intermediate_key]
 		if !exists {
-			var new_tree TomlTree = make(TomlTree)
-			(*subtree)[intermediate_key] = &new_tree
+			nextTree = newTomlTree()
+			subtree.values[intermediate_key] = nextTree
 		}
 
-		switch node := (*subtree)[intermediate_key].(type) {
+		switch node := nextTree.(type) {
 		case []*TomlTree:
 			subtree = node[len(node)-1]
 		case *TomlTree:
 			subtree = node
 		default:
-			return fmt.Errorf("unknown type for path %s", key)
+			return fmt.Errorf("unknown type for path %s (%s)",
+				strings.Join(keys, "."), intermediate_key)
 		}
 	}
 	return nil
@@ -231,9 +287,9 @@
 
 // Recursive support function for ToString()
 // Outputs a tree, using the provided keyspace to prefix group names
-func (t *TomlTree) toToml(keyspace string) string {
+func (t *TomlTree) toToml(indent, keyspace string) string {
 	result := ""
-	for k, v := range (map[string]interface{})(*t) {
+	for k, v := range t.values {
 		// figure out the keyspace
 		combined_key := k
 		if keyspace != "" {
@@ -244,17 +300,19 @@
 		case []*TomlTree:
 			for _, item := range node {
 				if len(item.Keys()) > 0 {
-					result += fmt.Sprintf("\n[[%s]]\n", combined_key)
+					result += fmt.Sprintf("\n%s[[%s]]\n", indent, combined_key)
 				}
-				result += item.toToml(combined_key)
+				result += item.toToml(indent+"  ", combined_key)
 			}
 		case *TomlTree:
 			if len(node.Keys()) > 0 {
-				result += fmt.Sprintf("\n[%s]\n", combined_key)
+				result += fmt.Sprintf("\n%s[%s]\n", indent, combined_key)
 			}
-			result += node.toToml(combined_key)
+			result += node.toToml(indent+"  ", combined_key)
+		case *tomlValue:
+			result += fmt.Sprintf("%s%s = %s\n", indent, k, toTomlValue(node.value, 0))
 		default:
-			result += fmt.Sprintf("%s = %s\n", k, toTomlValue(node, 0))
+			panic(fmt.Sprintf("unsupported node type: %v", node))
 		}
 	}
 	return result
@@ -263,7 +321,7 @@
 // Generates a human-readable representation of the current tree.
 // Output spans multiple lines, and is suitable for ingest by a TOML parser
 func (t *TomlTree) ToString() string {
-	return t.toToml("")
+	return t.toToml("", "")
 }
 
 // Create a TomlTree from a string.
diff --git a/toml_test.go b/toml_test.go
index 05a217e..09950b9 100644
--- a/toml_test.go
+++ b/toml_test.go
@@ -1,3 +1,5 @@
+// Testing support for go-toml
+
 package toml
 
 import (
@@ -27,16 +29,16 @@
 }
 
 func TestTomlGetPath(t *testing.T) {
-	node := make(TomlTree)
+	node := newTomlTree()
 	//TODO: set other node data
 
 	for idx, item := range []struct {
 		Path     []string
-		Expected interface{}
+		Expected *TomlTree
 	}{
 		{ // empty path test
 			[]string{},
-			&node,
+			node,
 		},
 	} {
 		result := node.GetPath(item.Path)