Merge branch 'master' into pelletier/inline-tables
diff --git a/lexer_test.go b/lexer_test.go
index 3509367..df2cac9 100644
--- a/lexer_test.go
+++ b/lexer_test.go
@@ -457,6 +457,13 @@
 		token{Position{1, 7}, tokenInteger, "1_2_3_4_5"},
 		token{Position{1, 16}, tokenEOF, ""},
 	})
+
+	testFlow(t, "flt8 = 9_224_617.445_991_228_313", []token{
+		token{Position{1, 1}, tokenKey, "flt8"},
+		token{Position{1, 6}, tokenEqual, "="},
+		token{Position{1, 8}, tokenFloat, "9_224_617.445_991_228_313"},
+		token{Position{1, 33}, tokenEOF, ""},
+	})
 }
 
 func TestMultiline(t *testing.T) {
diff --git a/parser.go b/parser.go
index 0fe0457..c3afa04 100644
--- a/parser.go
+++ b/parser.go
@@ -232,7 +232,8 @@
 		}
 		return val
 	case tokenFloat:
-		val, err := strconv.ParseFloat(tok.val, 64)
+		cleanedVal := strings.Replace(tok.val, "_", "", -1)
+		val, err := strconv.ParseFloat(cleanedVal, 64)
 		if err != nil {
 			p.raiseError(tok, "%s", err)
 		}
@@ -312,18 +313,7 @@
 		}
 		if follow.typ == tokenRightBracket {
 			p.getToken()
-			// An array of TomlTrees is actually an array of inline
-			// tables, which is a shorthand for a table array. If the
-			// array was not converted from []interface{} to []*TomlTree,
-			// the two notations would not be equivalent.
-			if arrayType == reflect.TypeOf(newTomlTree()) {
-				tomlArray := make([]*TomlTree, len(array))
-				for i, v := range array {
-					tomlArray[i] = v.(*TomlTree)
-				}
-				return tomlArray
-			}
-			return array
+			break
 		}
 		val := p.parseRvalue()
 		if arrayType == nil {
@@ -334,7 +324,7 @@
 		}
 		array = append(array, val)
 		follow = p.peek()
-		if follow == nil {
+		if follow == nil || follow.typ == tokenEOF {
 			p.raiseError(follow, "unterminated array")
 		}
 		if follow.typ != tokenRightBracket && follow.typ != tokenComma {
@@ -344,6 +334,17 @@
 			p.getToken()
 		}
 	}
+	// An array of TomlTrees is actually an array of inline
+	// tables, which is a shorthand for a table array. If the
+	// array was not converted from []interface{} to []*TomlTree,
+	// the two notations would not be equivalent.
+	if arrayType == reflect.TypeOf(newTomlTree()) {
+		tomlArray := make([]*TomlTree, len(array))
+		for i, v := range array {
+			tomlArray[i] = v.(*TomlTree)
+		}
+		return tomlArray
+	}
 	return array
 }
 
diff --git a/parser_test.go b/parser_test.go
index 93d0e78..365c247 100644
--- a/parser_test.go
+++ b/parser_test.go
@@ -68,7 +68,7 @@
 	})
 }
 
-func TestIntegersWithUnderscores(t *testing.T) {
+func TestNumbersWithUnderscores(t *testing.T) {
 	tree, err := Load("a = 1_000")
 	assertTree(t, tree, err, map[string]interface{}{
 		"a": int64(1000),
@@ -83,6 +83,16 @@
 	assertTree(t, tree, err, map[string]interface{}{
 		"a": int64(12345),
 	})
+
+	tree, err = Load("flt8 = 9_224_617.445_991_228_313")
+	assertTree(t, tree, err, map[string]interface{}{
+		"flt8": float64(9224617.445991228313),
+	})
+
+	tree, err = Load("flt9 = 1e1_00")
+	assertTree(t, tree, err, map[string]interface{}{
+		"flt9": float64(1e100),
+	})
 }
 
 func TestFloatsWithExponents(t *testing.T) {
@@ -287,6 +297,16 @@
 	if err.Error() != "(1, 8): unterminated array" {
 		t.Error("Bad error message:", err.Error())
 	}
+
+	_, err = Load("a = [1")
+	if err.Error() != "(1, 7): unterminated array" {
+		t.Error("Bad error message:", err.Error())
+	}
+
+	_, err = Load("a = [1 2")
+	if err.Error() != "(1, 8): missing comma" {
+		t.Error("Bad error message:", err.Error())
+	}
 }
 
 func TestNewlinesInArrays(t *testing.T) {