dictation-toolbox / aenea-grammars

Grammars pulled out of aenea as preparation for merging all grammars.
16 stars 11 forks source link

Rewrite multiedit and verbal_emacs to use Function #1

Open calmofthestorm opened 10 years ago

calmofthestorm commented 10 years ago

Now that I understand how Dragonfly functions work, I realize the process_recognition and value hacks are unnecessary. I suspect this will correct several bugs in verbal_emacs.

mzizzi commented 10 years ago

I'm in the process of building a few large grammars of my own. Mind sharing how/why Function() should be used instead of process_recognition() and value()?

calmofthestorm commented 10 years ago

it has been a while, and I never understood this stuff super well, but I will do my best to explain my understanding. The advantage over process_recognition is that in a recursive grammar the functions will be executed in the correct order, can be combined sensibly with each other, interact sensibly with extras, etc. In a flat grammar (say-this-do-that), it really doesn't much matter which you use. The intuition is that since the grammar itself is recursive, it is easier to process the actions when they too model a tree, as opposed to a depth-first traversal of a tree (which is what process_recognitions will look like).

Essentially it makes it much easier to nest them. process_recognition can be used to actually process what was said, but once you start relying on side effects you end up with the nastiness that is verbal_emacs.

The advantage over value is much more clear -- functions can access extras, meaning you can process arguments without hacking into node with specified paths. I have done a great deal of this, and while it does work it is both slow going and fragile.

Sorry I can't give a better answer, it is amazing how much slips out of your head in a month or two. I'll try to get to your PRs ASAP, but I'm on the interview loop at the moment, traveling a lot, and generally don't have a lot of time for OSS. Hopefully things will quiet down in a few weeks and I can catch up!

mzizzi commented 10 years ago

No rush and good luck with your interviews.

Using the debugger to look through the parse tree is certainly a pain. It is even more of a pain when using aenea remotely. This is been the biggest stumbling block when writing new grammars.

If I understand correctly, you believe that depth first traversal of the parse tree will cause problems with recursive grammars. Would you mind explaining that? It seems to me that being able to override value() is more flexible than relying on function. Using value should allow the top-level rule to decide how to evaluate the rest of the parse tree. I haven't used the function action yet but from my understanding they do not have access to the rest of the parse tree.

I will see if I can't get remote debugging setup for my installation and then mess with both function and value for recursive grammars.

On a related note, I think that might be helpful to have a modal VIM grammar. When performing complex selections it is very useful to use of VIM in visual mode. I think this is one of the biggest downfalls of the current implementation.

calmofthestorm commented 10 years ago

The issue with value is it doesn't have access to the extras. So for example if I have a command "up 5", the Up rule's value() would know it was called but not how far it should go. My understanding is that you're supposed to return a dynamic action that takes a %i, and then Dragonfly will take care of subbing in the 5 itself.

The problem is I never managed to get that working with more complex rules -- it would accept the wrong argument or put it in the wrong place -- so if I said "up five left 20" it might go up five left five, or throw a type error if I said something like "score hello_world up five". It's quite possible I was using it wrong, and that if I did a more careful revisit I could see how to use value, so I don't want to dissuade you too strongly from using it, just make sure it can handle nested rules with lots of arguments and that the arguments go in the right place before investing too much time in it.

I know function will work because it will bind the arguments in the correct order, but it is as you mention less convenient to use and if value can be made to work it should be preferred.

Modal VIM grammar has been an idea for some time; I agree; the current verbal_emacs doesn't mix nicely with the keyboard and it really should. So this basically requires the following:

The first three are straightforward, but mode-aware grammars bears some consideration -- for example, do we want to only make commands available for the mode they're in, or allow the grammar to switch in and out of modes seamlessly as necessary? I favor the latter -- the whole point of modes is making better use of the limited number of keys on a keyboard; a limitation voice lacks. So actually I feel when using VIM by voice the current mode should be more of an implementation detail that the speaker doesn't need to pay attention to except when using the keyboard.

Another option would be to require explicit mode switching -- this is most faithful to the keyboard interface, but I suspect would be cumbersome to actually use.

And finally, a hybrid approach -- what if we added a few "meta-modes", which guided the grammar? These meta modes could include things like "stay in insert mode", "switch as needed", "command mode", etc -- basically it would be nice to be able to force the behavior when entering a ton of text or whatnot (I cringe whenever I need to dictate the word 'delete' and FORGET about starting a dictation with it!), but in general I want automatic mode switching.

Regardless, removing the constraint that every command chain must start and end in command mode could really simplify the grammar a great deal -- a lot of the nesting issues I struggled with were due to the need to implicitly track mode in the structure of the parse tree. If each rule can painlessly check what mode we're currently in that would make life a lot easier (although I wonder if there'd be a lag between the grammar changing mode and the context picking it up from the VIM window...that could be a serious issue).

I don't know how much I'd contribute to a VIM grammar along these lines, but I would favor a total re-write over attempting to update verbal_emacs. It's well designed within limited parameters, but I now realize those limits are artificial, and I question how much of its design really carries over to a better implementation.

A better place to start might be multiedit -- it's complex enough to have a lot of the same issues yet in far simpler form.

mzizzi commented 10 years ago

I'm curious as to how you are debugging your grammars. Up until this point I have been developing the grammars locally on a Windows machine using WSR where I can attach a debugger to locally and trace through the grammars. I'd like to set up remote debugging and attach to my guest vm's python interpreter from the host linux machine. Has anyone had success with this approach?

calmofthestorm commented 10 years ago

Print statements:/ I think @nirvdrum has some remote debugger set up with Eclipse, but I've generally found for systems like this where you don't control the invocation and aren't writing anything too complicated print statements is the way to go. Pragmatism > purity.

mzizzi commented 10 years ago

Just a followup to my previous comment. I was able to install eclipse+pydev on the windows guest and interactively debug a few grammars. It is leaps and bounds quicker to trace issues and well worth the up-front time investment to get working. (sorry to derail this issue)

calmofthestorm commented 10 years ago

I'd love to add a tutorial on this. Even better would be if you could debug remotely on the host, but that probably adds complexity and security concerns.