The problem is that -
is in what some parser folks call the "leading set" for float
so the parser, having no idea that what follows isn't a float
, merrily goes along and tries to parse one. The Parsing Expression Grammar style of parser implemented by PEGjs doesn't do backtracking within a symbol.
The only way to avoid this is to give the parser more information about what you're trying to do to avoid the leading set ambiguity you introduced by allowing -
in the leading set of str
and in float
. You could fix this another way, by forcing the parser to require [0-9]+
after it sees -
. In fact, I suspect your grammar is not accurately representing what you want to accomplish since it permits strings like 0123-456
or 123.456-789.987.123
as float
as well. You need to force the -
as the optional first character of a float
and then require a string of digits to make it do floats right anyway.
I suggest you write your grammar like this:
start = val
ln = [\n\r]
float = digits:$('-'? [0-9]+ '.'? [0-9]*
/ '-'? '.' [0-9]+) { return parseFloat(digits, 10) }
str = str:$(!ln !"\"" .)+
val = float / str
The first part of float
captures the case where there are digits before the decimal point or the decimal point is missing. The second part captures the case where there are no digits before the decimal point, but it is present, and it enforces the requirement of digits after the decimal point in this case.
The fact that you have val = float / str
rather than val = str / float
is critical also. You have to try to match a float
before you try to match a str
for this to work. I'm not really sure about that definition for str
, but I don't know the language you're trying to parse.