Refactoring: tidy-ups and performance improvements
- Simplify the dag implementation and move it to its own module
- Avoid recompiling regexes inside loops, whcih is a very expensive operation; instead, load them statically
- Improve the runtime by precomputing the edges where needed