PaulR has the right suggestion. You have to run through the code by “hand” (using whatever tools you want – debuggers, paper, logging function calls and variables at certain points) until you understand it. For an explanation of the code I’ll refer you to quasiverse’s excellent answer.
Perhaps this visualization of the call graph with a slightly smaller string makes it more obvious how it works:
The graph was made with graphviz.
// x.dot // dot x.dot -Tpng -o x.png digraph x { rankdir=LR size="16,10" node [label="permute(\"ABC\", 0, 2)"] n0; node [label="permute(\"ABC\", 1, 2)"] n1; node [label="permute(\"ABC\", 2, 2)"] n2; node [label="permute(\"ACB\", 2, 2)"] n3; node [label="permute(\"BAC\", 1, 2)"] n4; node [label="permute(\"BAC\", 2, 2)"] n5; node [label="permute(\"BCA\", 2, 2)"] n6; node [label="permute(\"CBA\", 1, 2)"] n7; node [label="permute(\"CBA\", 2, 2)"] n8; node [label="permute(\"CAB\", 2, 2)"] n9; n0 -> n1 [label="swap(0, 0)"]; n0 -> n4 [label="swap(0, 1)"]; n0 -> n7 [label="swap(0, 2)"]; n1 -> n2 [label="swap(1, 1)"]; n1 -> n3 [label="swap(1, 2)"]; n4 -> n5 [label="swap(1, 1)"]; n4 -> n6 [label="swap(1, 2)"]; n7 -> n8 [label="swap(1, 1)"]; n7 -> n9 [label="swap(1, 2)"]; }