Handle nil, map[string]string, and map[interface{}]interface{} input (#103)

* Handle map[string]string and map[interface{}]interface{} input
* Handle nil values

Fixes #99
diff --git a/parser_test.go b/parser_test.go
index 5b78bc3..605750e 100644
--- a/parser_test.go
+++ b/parser_test.go
@@ -647,6 +647,7 @@
 			"1979-05-27T07:32:00Z"},
 		{[]interface{}{"gamma", "delta"},
 			"[\n  \"gamma\",\n  \"delta\",\n]"},
+		{nil, ""},
 	} {
 		result := toTomlValue(item.Value, 0)
 		if result != item.Expect {
@@ -668,6 +669,28 @@
 	}
 }
 
+func TestToStringMapStringString(t *testing.T) {
+	in := map[string]interface{}{"m": map[string]string{"v": "abc"}}
+	want := "\n[m]\n  v = \"abc\"\n"
+	tree := TreeFromMap(in)
+	got := tree.String()
+
+	if got != want {
+		t.Errorf("want:\n%q\ngot:\n%q", want, got)
+	}
+}
+
+func TestToStringMapInterfaceInterface(t *testing.T) {
+	in := map[string]interface{}{"m": map[interface{}]interface{}{"v": "abc"}}
+	want := "\n[m]\n  v = \"abc\"\n"
+	tree := TreeFromMap(in)
+	got := tree.String()
+
+	if got != want {
+		t.Errorf("want:\n%q\ngot:\n%q", want, got)
+	}
+}
+
 func assertPosition(t *testing.T, text string, ref map[string]Position) {
 	tree, err := Load(text)
 	if err != nil {
diff --git a/tomltree_conversions.go b/tomltree_conversions.go
index ae03189..bf9321b 100644
--- a/tomltree_conversions.go
+++ b/tomltree_conversions.go
@@ -84,6 +84,8 @@
 			result += toTomlValue(item, indent+2) + ",\n"
 		}
 		return result + tab + "]"
+	case nil:
+		return ""
 	default:
 		panic(fmt.Sprintf("unsupported value type %T: %v", value, value))
 	}
@@ -120,6 +122,20 @@
 				result += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
 			}
 			result += sub.toToml(indent+"  ", combinedKey)
+		case map[string]string:
+			sub := TreeFromMap(convertMapStringString(node))
+
+			if len(sub.Keys()) > 0 {
+				result += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
+			}
+			result += sub.toToml(indent+"  ", combinedKey)
+		case map[interface{}]interface{}:
+			sub := TreeFromMap(convertMapInterfaceInterface(node))
+
+			if len(sub.Keys()) > 0 {
+				result += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
+			}
+			result += sub.toToml(indent+"  ", combinedKey)
 		case *tomlValue:
 			result += fmt.Sprintf("%s%s = %s\n", indent, k, toTomlValue(node.value, 0))
 		default:
@@ -129,6 +145,22 @@
 	return result
 }
 
+func convertMapStringString(in map[string]string) map[string]interface{} {
+	result := make(map[string]interface{}, len(in))
+	for k, v := range in {
+		result[k] = v
+	}
+	return result
+}
+
+func convertMapInterfaceInterface(in map[interface{}]interface{}) map[string]interface{} {
+	result := make(map[string]interface{}, len(in))
+	for k, v := range in {
+		result[k.(string)] = v
+	}
+	return result
+}
+
 // ToString is an alias for String
 func (t *TomlTree) ToString() string {
 	return t.String()