-
Notifications
You must be signed in to change notification settings - Fork 128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSON decoder example #23
base: master
Are you sure you want to change the base?
Conversation
Nice job. It's impressive how short it is. I may have to borrow this as a canonical benchmark! |
The grammar ended up very similar to the spec (unlike parsley). But at the same time it was a bit tricky to make the decoder since it required to switch to the grammar a lot. I actually ended up developing it with rules inside each of the methods' docstrings, and moving it out when it was finished :-) Also recently I presented parsimonious at a local Python meetup, showing how to write a simple interpreter. You might be interested to see it: https://gist.github.com/halst/4531a03bcddab550992a Too bad the camera's battery died while we were recording my talk, but I plan to make a screencast out of it. |
A couple ideas:
|
Say…it occurs to me that we can perfectly well extract a grammar from visitor docstrings without having to actually use that visitor to visit. :-) So there's no real disadvantage to doing that, except that you can't see the whole grammar at once without a little work. Hmm! |
If you get around to making a screencast, I'd love to see it or even help publicize it. |
As I can see around, this problem is usually handled by assigning names to children like parsley does:
With grabbing syntax this would look like
In these cases I like grabbing better, because you don't need to come up with silly short names. But I can imagine a problem that "naming" could handle that "grabbing" couldn't (probably?):
Although I'm not sure how parsley gets |
Well, in ideal parallel universe where Python has real lambdas, I wold love to change this code: class Mini(object):
...
def ifelse(self, node):
""" ifelse = ~"if\s*" expr ~"\s*then\s*" expr ~"\s*else\s*" expr """
_, cond, _, cons, _, alt = node
return self.eval(cons) if self.eval(cond) else self.eval(alt)
def infix(self, node, children):
""" infix = ~"\(\s*" expr ~"\s*" operator ~"\s*" expr ~"\s*\)\s*" """
_, left, _, operator, _, right, _ = children
operators = {'+': op.add, '-': op.sub, '*': op.mul, '/': op.div}
return operators[operator](left, right) into something like this (in CoffeeScript syntax): mini = Gramar({
...
'ifelse': rule '~"if\s*" expr ~"\s*then\s*" expr ~"\s*else\s*" expr', ->
mini.eval(@expr3) if mini.eval(@expr1) else mini.eval(@expr2)
'infix': rule '~"\(\s*" expr ~"\s*" operator ~"\s*" expr ~"\s*\)\s*"', ->
operators = {'+': op.add, '-': op.sub, '*': op.mul, '/': op.div}
operators[@operator](@expr1, @expr2)
})
|
I.e. somehow avoid method signatures and tuple unpacking |
This is, I suspect, where the third type of tree transformation comes in: http://doc.pypy.org/en/latest/rlib.html#nonterminal-1-nonterminal-2-nonterminal-n. (Yes, I changed the syntax in my example; don't let it confuse you.) |
I would nudge it in this direction: class Mini(object):
...
def ifelse(self, (_, cond, _, cons, _, alt)):
""" ~"if\s*" expr ~"\s*then\s*" expr ~"\s*else\s*" expr """
return self.eval(cons) if self.eval(cond) else self.eval(alt)
def infix(self, node, (_, left, _, operator, _, right, _)):
""" ~"\(\s*" expr ~"\s*" operator ~"\s*" expr ~"\s*\)\s*" """
operators = {'+': op.add, '-': op.sub, '*': op.mul, '/': op.div}
return operators[operator](left, right) That is, removing the duplicated rule names and doing tuple unpacking in the formal parameter list (though that's going away in Python 3 and will therefore require rethought). This takes us pretty close to a PEG version of PLY, which is not entirely a bad thing, since (1) it's optional and (2) it doesn't strictly hurt our decoupling. |
Yeah, I will be missing tuples in signatures. Completely opposite direction of what I want from Python :-). (E.g. CoffeeScript even allows unpacking of objects in signatures like I guess what I did with Mini is the way to go in this case 😟 |
I just finished multi-line support (#19) and am now turning my attention to benchmarking and optimizing, using your JSON decoder as a starting point. I got a real kick out of you naming the entrypoint |
😀 |
I just published the screencast I was talking about: http://www.youtube.com/watch?v=1h1mM7VwNGo The code is here: https://github.com/halst/mini On reddit: http://www.reddit.com/r/programming/comments/1dfn16/how_to_write_an_interpreter/ |
This is implementation of JSON decoder using parsimonious.
It's based on json spec with one exception that escape-sequences are not supported. I will most likely add them later.