Escape leading space in ninja strings

Spaces normally don't need to be escaped, but leading spaces are
trimmed.  Escape leading space to allow setting a variable to a
value with leading spaces.

Test: ninja_string_test.go
Change-Id: Ic0ffb076dbd603b7c0203720b9c1ea635c5ded75
This commit is contained in:
Colin Cross 2017-05-09 10:03:00 -07:00
parent 7aa318f83d
commit 8de48af6de
2 changed files with 19 additions and 2 deletions

View file

@ -54,6 +54,7 @@ func simpleNinjaString(str string) *ninjaString {
type parseState struct { type parseState struct {
scope scope scope scope
str string str string
pendingStr string
stringStart int stringStart int
varStart int varStart int
result *ninjaString result *ninjaString
@ -64,6 +65,9 @@ func (ps *parseState) pushVariable(v Variable) {
// Last push was a variable, we need a blank string separator // Last push was a variable, we need a blank string separator
ps.result.strings = append(ps.result.strings, "") ps.result.strings = append(ps.result.strings, "")
} }
if ps.pendingStr != "" {
panic("oops, pushed variable with pending string")
}
ps.result.variables = append(ps.result.variables, v) ps.result.variables = append(ps.result.variables, v)
} }
@ -71,7 +75,8 @@ func (ps *parseState) pushString(s string) {
if len(ps.result.strings) != len(ps.result.variables) { if len(ps.result.strings) != len(ps.result.variables) {
panic("oops, pushed string after string") panic("oops, pushed string after string")
} }
ps.result.strings = append(ps.result.strings, s) ps.result.strings = append(ps.result.strings, ps.pendingStr+s)
ps.pendingStr = ""
} }
type stateFunc func(*parseState, int, rune) (stateFunc, error) type stateFunc func(*parseState, int, rune) (stateFunc, error)
@ -93,7 +98,7 @@ func parseNinjaString(scope scope, str string) (*ninjaString, error) {
result: result, result: result,
} }
state := parseStringState state := parseFirstRuneState
var err error var err error
for i := 0; i < len(str); i++ { for i := 0; i < len(str); i++ {
r := rune(str[i]) r := rune(str[i])
@ -111,6 +116,13 @@ func parseNinjaString(scope scope, str string) (*ninjaString, error) {
return result, nil return result, nil
} }
func parseFirstRuneState(state *parseState, i int, r rune) (stateFunc, error) {
if r == ' ' {
state.pendingStr += "$"
}
return parseStringState(state, i, r)
}
func parseStringState(state *parseState, i int, r rune) (stateFunc, error) { func parseStringState(state *parseState, i int, r rune) (stateFunc, error) {
switch { switch {
case r == '$': case r == '$':

View file

@ -70,6 +70,11 @@ var ninjaParseTestCases = []struct {
vars: nil, vars: nil,
strs: []string{"foo bar"}, strs: []string{"foo bar"},
}, },
{
input: " foo ",
vars: nil,
strs: []string{"$ foo "},
},
{ {
input: "foo $ bar", input: "foo $ bar",
err: "invalid character after '$' at byte offset 5", err: "invalid character after '$' at byte offset 5",