Skip to content

Latest commit

 

History

History
116 lines (92 loc) · 5.75 KB

README.md

File metadata and controls

116 lines (92 loc) · 5.75 KB

Vim Turing Machine

Ever wish you could run your code in your editor? Tired of installing huge dependencies like bash or python to run your scripts? Love Vim so much that you never want to leave it? Why not run your code... in your editor itself? Enter vim_turing_machine: a tool to allow you to run a Turing machine using only normal mode Vim commands.

And now you might ask, but what can we do on a Turing machine! To demonstrate its capabilities, we implemented a solution to the Merge Overlapping Intervals question and defined all the state transitions needed to solve this glorious problem. So next time you need to merge some intervals, don't hand-write a 10-line python program. Instead, take out your favorite editor and watch it solve the problem in less than a minute with 1400 state transitions!

But a simple naysayer may say, 'We already have vimscript! Why in God's name would I want to use a Turing machine instead?' To that, we retort: our Turing machine only uses normal mode. So you could theoretically just type in the program and then execute it without running a single script! No ex mode either! This project proves that normal mode in Vim is as powerful as any computer!

Merging your favorite intervals

Given a set of sorted potentially overlapping open/close intervals, merge the overlapping intervals together.

Example:

[[1, 5], [6, 7]] -> [[1, 5], [6, 7]]
[[1, 5], [2, 3], [5, 7], [12, 15]] -> [[1, 7], [12, 15]]

Running the Python Turing Machine: make run

Opening the Vim Turing Machine without running it: make open-vim-machine

Opening and then running the Vim Turing Machine: make run-vim-machine

So Vim did what? Wait. How does it even?

So you run this program, and it works. Great! So what happened? Well the most common thing you're going to see is y$@". What this does is yank from the current cursor to the end of the line and then executes the default register as a macro. This allows us to encode motions in lines and then execute them. We then chain lines together by ending lines with moving to a mark, or a search result, and then yanking and executing that line.

Using that nifty trick, we begin by yanking the first line and executing it. That then sets off our mark initialization. We then search for _<someletter> and then mark that position with the corresponding letter. Generally the first initial of whatever the thing we're marking is. Once everything is marked, we then begin the state transitions.

We begin a state transition by executing a long command (located at _n:) which jumps to the tape marker, yanks it, then jumps to the current state marker, yanks that too, and then searches for some transition that contains both the state and tape values. Once it gets to that line, it jumps to the command string and then executes our trusty y$@" to execute it. To make sure we keep transitioning, each state transition ends with `ny$@ which tells it to jump to our "next state" marker and then execute it again, which kicks off the search for the next state.

The execution halts when it can't find a new state to transition to. The state search includes an "or" operator where it will fall back to matching ---, which tells it to print the current state and halt.

Most transitions themselves involve changing a tape value or a state value and then moving in some direction on the tape. Changing values consists of jumping to the tape or state marks (`t or `k respectively) and then using cw or C to change the value. We then move the pointer by jumping to the tape position (`t) and then moving a word forward (W) or backward (B), and then marking the new tape position.

The last real piece of complication is extending the tape. We're living in a world with unlimited tapes! What a time to be alive! This is done through a series of nifty hacks. First, we have a modeline that sets whichwrap+b,s. This allows us to move across line breaks and keep the tape all in the screen. Next, the line directly under the tape contains a "fake" value that, when added to our state search, will prevent it from matching any real state transitions and instead match a "transition" for adding a line to the tape. This line tells us to jump to the end of the tape, and then insert a full line of empty values (we use X), and then go back to our original tape location and execute the next state transition!

And there you have it! A simple ggyy@" will kick off all of these sequences until execution completes. The cool thing is that this isn't special to the intervals problem. In fact, you can write your own state machine and use the provided Vim adapter to create a new Vim machine to solve any problem that can be solved by a Turing Machine!

To see some more details about various common commands, you can take a look at vim_turing_machine/vim_constants.py. That file contains some constants that are used repeatedly in the generated machine.vim file and their names are fairly descriptive. Also, if you'd like to step through manually, you can edit the Vim machine in vim_turing_machine/machines/vim_is_number_even.py and tell it not to auto step and then step through manually using y$@".

Happy hacking!

Dependencies

To run this code, you will need python3.6, tox, and vim installed on your machine. This code hasn't been tested on other versions of python3, but they'll probably work if you change the pinned version in tox.ini. This code is not python2 compatible.

Contributors

eliot and ifij wrote this project in July 2017 for Yelp's Hackathon 23. It was inspired by vimmmex: a Brainfuck interpretor written in Vim.