Merge pull request #18 from colincross/ninjastring

Fix bug in parseNinjaString
diff --git a/ninja_strings.go b/ninja_strings.go
index 950518d..3c3b444 100644
--- a/ninja_strings.go
+++ b/ninja_strings.go
@@ -59,6 +59,21 @@
 	result      *ninjaString
 }
 
+func (ps *parseState) pushVariable(v Variable) {
+	if len(ps.result.variables) == len(ps.result.strings) {
+		// Last push was a variable, we need a blank string separator
+		ps.result.strings = append(ps.result.strings, "")
+	}
+	ps.result.variables = append(ps.result.variables, v)
+}
+
+func (ps *parseState) pushString(s string) {
+	if len(ps.result.strings) != len(ps.result.variables) {
+		panic("oops, pushed string after string")
+	}
+	ps.result.strings = append(ps.result.strings, s)
+}
+
 type stateFunc func(*parseState, int, rune) (stateFunc, error)
 
 // parseNinjaString parses an unescaped ninja string (i.e. all $<something>
@@ -98,7 +113,7 @@
 		return parseDollarStartState, nil
 
 	case r == eof:
-		state.result.strings = append(state.result.strings, state.str[state.stringStart:i])
+		state.pushString(state.str[state.stringStart:i])
 		return nil, nil
 
 	default:
@@ -112,7 +127,7 @@
 		r >= '0' && r <= '9', r == '_', r == '-':
 		// The beginning of a of the variable name.  Output the string and
 		// keep going.
-		state.result.strings = append(state.result.strings, state.str[state.stringStart:i-1])
+		state.pushString(state.str[state.stringStart:i-1])
 		return parseDollarState, nil
 
 	case r == '$':
@@ -123,7 +138,7 @@
 	case r == '{':
 		// This is a bracketted variable name (e.g. "${blah.blah}").  Output
 		// the string and keep going.
-		state.result.strings = append(state.result.strings, state.str[state.stringStart:i-1])
+		state.pushString(state.str[state.stringStart:i-1])
 		state.varStart = i + 1
 		return parseBracketsState, nil
 
@@ -153,14 +168,11 @@
 			return nil, err
 		}
 
-		state.result.variables = append(state.result.variables, v)
+		state.pushVariable(v)
 		state.varStart = i + 1
+		state.stringStart = i
 
-		// We always have a string in between variables, even if it's an
-		// empty one.
-		state.result.strings = append(state.result.strings, "")
-
-		return parseDollarState, nil
+		return parseDollarStartState, nil
 
 	case r == eof:
 		// This is the end of the variable name.
@@ -169,10 +181,10 @@
 			return nil, err
 		}
 
-		state.result.variables = append(state.result.variables, v)
+		state.pushVariable(v)
 
 		// We always end with a string, even if it's an empty one.
-		state.result.strings = append(state.result.strings, "")
+		state.pushString("")
 
 		return nil, nil
 
@@ -184,7 +196,7 @@
 			return nil, err
 		}
 
-		state.result.variables = append(state.result.variables, v)
+		state.pushVariable(v)
 		state.stringStart = i
 		return parseStringState, nil
 	}
@@ -210,7 +222,7 @@
 			return nil, err
 		}
 
-		state.result.variables = append(state.result.variables, v)
+		state.pushVariable(v)
 		state.stringStart = i + 1
 		return parseStringState, nil
 
diff --git a/ninja_strings_test.go b/ninja_strings_test.go
index 55651ff..b35c8b4 100644
--- a/ninja_strings_test.go
+++ b/ninja_strings_test.go
@@ -56,6 +56,16 @@
 		strs:  []string{"foo $$ bar"},
 	},
 	{
+		input: "$foo${bar}",
+		vars:  []string{"foo", "bar"},
+		strs:  []string{"","", ""},
+	},
+	{
+		input: "$foo$$",
+		vars:  []string{"foo"},
+		strs:  []string{"","$$"},
+	},
+	{
 		input: "foo $ bar",
 		err:   "invalid character after '$' at byte offset 5",
 	},