This is a duplicate of an old question I cannot found anymore but for which I've a trace (through a solution): https://github.com/LucHermitte/lh-misc/blob/master/plugin/rotate_substitute.vim
:command! -bang -nargs=1 -range CycleSubstitute <line1>,<line2>call s:CycleSubstitute("<bang>", <f-args>)
" no back ref supported; makes no sense
function! s:CycleSubstitute(bang, repl_arg) range
let do_loop = a:bang != "!"
let sep = a:repl_arg[0]
let fields = split(a:repl_arg, sep)
let cleansed_fields = map(copy(fields), 'substitute(v:val, "\\\\[<>]", "", "g")')
" build the action to execute
let action = '\=s:DoCycleSubst('.do_loop.',' . string(cleansed_fields) . ', "^".submatch(0)."$")'
" prepare the :substitute command
let args = [join(fields, '\|'), action ]
let cmd = a:firstline . ',' . a:lastline . 's'
\. sep . join(fields, '\|')
\. sep . action
\. sep . 'g'
" echom cmd
" and run it
exe cmd
endfunction
function! s:DoCycleSubst(do_loop, fields, what)
let idx = (match(a:fields, a:what) + 1) % len(a:fields)
return a:fields[idx]
endfunction
Which could be used with: %CycleSubstitute/foo/bar
in your example.