3 ms·
One could consider how the Ruby parser would have looked like if the parser would have been built around a more powerful parser engine though. Would the develop
by yxhuvud 10y ago
One could consider how the Ruby parser would have looked like if the parser would have been built around a more powerful parser engine though. Would the developers have abused the added power to add even more exceptions or would the added power have made a lot of the exceptions go away?
(by more powerful I mean more powerful in the way the chart parser from the article is more powerful than an LR based parser, ie that it can parse a bigger subset of CFG in linear time).
- vidarh 10y agoIt's hard to tell. The current Ruby grammar doesn't really need a very advanced engine per se. It certainly could have been written more cleanly even with Bison. It seems more like a case of painting yourself into a corner through in some cases. Maybe a better engine would have led to more discipline, but I doubt it. E.g. one of the things people tend to like about Ruby is the ability to leave out parentheses around arguments in method calls. People often disagree on where/when to use it, but it allows for DSL's that looks more "integrated" with the language, for example. But it causes all kinds of weirdness around the edges. E.g. for starters, you need to look at the symbol table for the current scope to know whether to treat a given identifier as a reference to a local variable or a method call. In itself that's a tiny little infraction, but the reason it is necessary is to prevent big surprises in common cases, and the result is to leave a variety of surprises in more unusual cases. If a valid local variable name has been assigned to, it's a local variable except in contexts where it would be a syntax error unless you treat it as a method call. If we assume "x=42" earlier in the scope, couple with the "fun" of the optional parentheses, you get stuff like this. * "x" is a local variable. * "x 1" is the method call self.x(1) * "x + 2" is the method call x.+(2) (so on the object held in the local variable x) * "[x 1]" is a syntax error. * "y[x 1]" is a nested method call: y.[](self.x(1)) * "z(x 1)" is a nested method call: self.z(self.x(1)) * "z(x 1, x 2)" is a syntax error. * "z(x 1, x(2))" is a nested method call, that tends to surprise people: self.z(self.x(1, self.x(2)) (most people tends to expect it will parse as self.z(self.x(1), self.x(2))) * "z(x 1, x)" is a nested method call where "x" refers to two different things: self.z(self.x(1),42) (with the caveat I've had too little sleep, so I might very well have messed up one or the other of these...) It's not hard to parse, and not all that hard to understand and reason about, but it is messy, and tack on a number of them and the parser gets ugly, and you create odd "dark corners" of the grammar that most people never run into but that surprise them whenever they do, and that parsers for alternative implementations needs to get right.