vimlrs 0.2.1

Faithful Rust port of the Vimscript (VimL) interpreter, from the Neovim C eval engine
Documentation
" deferred_function.vim — a `:function` nested inside a control-flow block
" (`:if`/`:while`/`:for`/`:try`) or another function body is registered when its
" line EXECUTES, not at parse time (userfunc.c:2485-2511: those blocks only
" adjust `indent`, and an inner `:function …(` is defined when the enclosing code
" runs). This is the idempotent `if !exists('*F') | function F() … | endif`
" idiom that real `.vimrc`s and colour schemes (e.g. zpwrmarklar.vim) rely on.
" Verified against Vim 9.2. Self-test: asserts into v:errors, throws if any fail.

" --- 1. a function defined inside a TRUE :if block is callable afterward
if 1
  function! TrueGuard()
    return 42
  endfunction
endif
call assert_equal(1, exists('*TrueGuard'))
call assert_equal(42, TrueGuard())

" --- 2. a function inside a FALSE :if guard is never defined
if 0
  function! FalseGuard()
    return 7
  endfunction
endif
call assert_equal(0, exists('*FalseGuard'))

" --- 3. the `if !exists('*F')` idiom is idempotent: a second guard block at
"        script level (as a re-source would hit) sees the function already
"        defined and does NOT redefine it — the original body wins.
if !exists('*ScriptGuard')
  function! ScriptGuard()
    return 'first'
  endfunction
endif
if !exists('*ScriptGuard')
  function! ScriptGuard()
    return 'second'
  endfunction
endif
call assert_equal('first', ScriptGuard())

" --- 4. a function defined inside ANOTHER function's body (def-in-def) is
"        registered when the OUTER function runs — not at parse time, and NOT an
"        error (Vim's E120 is unrelated: "Using <SID> not in a script context").
function! Outer()
  function! Inner()
    return 'inner'
  endfunction
endfunction
call assert_equal(0, exists('*Inner'))
call Outer()
call assert_equal(1, exists('*Inner'))
call assert_equal('inner', Inner())

" --- 5. the guarded idiom inside an init function is also idempotent across
"        repeated calls (the common autoload/plugin-init shape).
function! s:init() abort
  if !exists('*InitFn')
    function! InitFn()
      return 'v1'
    endfunction
  endif
endfunction
call s:init()
call assert_equal('v1', InitFn())
call s:init()
call assert_equal('v1', InitFn())

" --- 6. deferred inside a :while loop: defined on the first reached iteration
let s:n = 0
while s:n < 3
  if !exists('*LoopFn')
    function! LoopFn()
      return 'looped'
    endfunction
  endif
  let s:n += 1
endwhile
call assert_equal('looped', LoopFn())

if len(v:errors) > 0
  for err in v:errors
    echo err
  endfor
  throw 'deferred_function.vim: ' . len(v:errors) . ' assertion(s) failed'
endif
echo 'deferred_function.vim: all assertions passed'