Fix misparsed $ after variable name
If a $ sign occurs after a variable name, the ninja string parser fails to check if it is a $$ or a ${. Go to the parseDollarStartState instead of the parseDollarState. Since it is not yet known if the $ is the beginning of a new variable (${ or $<alphanumeric>) or a string ($$), an empty string separator cannot be added to the ninjaString strings list. Instead, add functions to push strings or variables onto the ninjaString, and automatically add the blank separator if two variables are pushed in a row. Change-Id: Ia1cae6259b1d7e4f633f61b9eadb2a2028bbd5f0
This commit is contained in:
parent
11bcca9098
commit
b247893deb
2 changed files with 35 additions and 13 deletions
|
@ -59,6 +59,21 @@ type parseState struct {
|
|||
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 @@ func parseStringState(state *parseState, i int, r rune) (stateFunc, error) {
|
|||
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 @@ func parseDollarStartState(state *parseState, i int, r rune) (stateFunc, error)
|
|||
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 @@ func parseDollarStartState(state *parseState, i int, r rune) (stateFunc, error)
|
|||
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 @@ func parseDollarState(state *parseState, i int, r rune) (stateFunc, error) {
|
|||
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 @@ func parseDollarState(state *parseState, i int, r rune) (stateFunc, error) {
|
|||
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 @@ func parseDollarState(state *parseState, i int, r rune) (stateFunc, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
state.result.variables = append(state.result.variables, v)
|
||||
state.pushVariable(v)
|
||||
state.stringStart = i
|
||||
return parseStringState, nil
|
||||
}
|
||||
|
@ -210,7 +222,7 @@ func parseBracketsState(state *parseState, i int, r rune) (stateFunc, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
state.result.variables = append(state.result.variables, v)
|
||||
state.pushVariable(v)
|
||||
state.stringStart = i + 1
|
||||
return parseStringState, nil
|
||||
|
||||
|
|
|
@ -55,6 +55,16 @@ var ninjaParseTestCases = []struct {
|
|||
vars: nil,
|
||||
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",
|
||||
|
|
Loading…
Reference in a new issue