Full Code of tpope/timl for AI

master 01deb947b222 cached
65 files
204.7 KB
70.8k tokens
1 requests
Download .txt
Showing preview only (221K chars total). Download the full file or copy to clipboard to get everything.
Repository: tpope/timl
Branch: master
Commit: 01deb947b222
Files: 65
Total size: 204.7 KB

Directory structure:
gitextract_hyaf864a/

├── .gitignore
├── README.markdown
├── autoload/
│   ├── timl/
│   │   ├── array.vim
│   │   ├── array_seq.vim
│   │   ├── atom.vim
│   │   ├── bootstrap.vim
│   │   ├── buffer.tim
│   │   ├── chunked_cons.vim
│   │   ├── coll.vim
│   │   ├── compiler.vim
│   │   ├── cons.vim
│   │   ├── core.tim
│   │   ├── core_basics.tim
│   │   ├── core_coll.tim
│   │   ├── core_macros.tim
│   │   ├── core_ref.tim
│   │   ├── core_seq.tim
│   │   ├── core_vim.tim
│   │   ├── delay.vim
│   │   ├── dictionary.vim
│   │   ├── equality.vim
│   │   ├── exception.vim
│   │   ├── false.vim
│   │   ├── file.tim
│   │   ├── ftplugin.tim
│   │   ├── funcref.vim
│   │   ├── function.vim
│   │   ├── future.vim
│   │   ├── hash.vim
│   │   ├── indent.tim
│   │   ├── inst.vim
│   │   ├── interactive.vim
│   │   ├── io.vim
│   │   ├── keyword.vim
│   │   ├── lazy_seq.vim
│   │   ├── list.vim
│   │   ├── loader.vim
│   │   ├── map.vim
│   │   ├── meta.vim
│   │   ├── namespace.vim
│   │   ├── nil.vim
│   │   ├── number.vim
│   │   ├── plugin_helper.tim
│   │   ├── printer.vim
│   │   ├── reader.vim
│   │   ├── repl.tim
│   │   ├── set.vim
│   │   ├── string.vim
│   │   ├── symbol.vim
│   │   ├── test.tim
│   │   ├── true.vim
│   │   ├── type.vim
│   │   ├── var.vim
│   │   └── vector.vim
│   └── timl.vim
├── doc/
│   ├── timl.txt
│   └── timl_core.txt
├── epl-v10.html
├── ftplugin/
│   └── timl.tim
├── indent/
│   └── timl.tim
├── plugin/
│   └── timl.vim
├── syntax/
│   └── timl.vim
└── test/
    └── timl/
        ├── core_coll_test.tim
        ├── core_test.tim
        └── number_test.tim

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/doc/tags


================================================
FILE: README.markdown
================================================
# Welcome to the future (of the past)

TimL is a Lisp dialect implemented in and compiling down to VimL, the
scripting language provided by the Vim text editor.  Think Clojure meets VimL.

## Is this a joke?

If you mean the 6,000 lines of working code, then no, I poured hundreds upon
hundreds of very serious hours into that.  But if you're referring to the fact
it's woefully underdocumented, adds considerable overhead to an already slow
host platform, and ultimately unlikely to gain any traction, then yeah,
probably.

## Language features

* Clojure like syntax and API, including everything from rich syntax literals
  to destructuring.
* Namespaces, including `refer` and `alias`.
* `timl.core`, a tiny but growing API resembling `clojure.core`.
* The same persistent collection types and interfaces, including vectors, hash
  maps, hash sets, lists, and lazy sequences.
* Macros, including syntax quoting and the implicit `&form` and `&env`.
* Metadata.  (Some collection types don't support it yet.)
* Reference types, including vars, atoms, futures.
* Extensible type system, including `defmethod` for duck typing.  (This is the
  most significant departure from Clojure.)
* Caching compiler generates real VimL.

## VimL interop

* TimL functions are actually VimL dictionaries (objects) containing a
  dictionary function (method) and a reference to the enclosing scope.
* Defining a symbol `baz` in namespace `foo.bar` actually defines
  `g:foo#bar.baz`.  If that symbol refers to something callable (like a
  function), calling `foo#bar#baz()` on the VimL side will invoke it.
* Arbitrary Vim variables and options can be referred to using VimL notation:
  `b:did_ftplugin`, `v:version`, `&expandtab`. You can also change them with
  `set!`: `(set! &filetype "timl")`.
* `#*function` returns a reference to a built-in or user defined function.
  You can call it like any other function: `(#*toupper "TimL is pretty neat")`.
* Interact with VimL exceptions with `throw`/`try`/`catch`/`finally`.
* Call a Vim command with `execute`: `(execute "wq")`.
* Lisp macros are a wonderful way to encapsulate and hide a lot of the pain
  points of VimL.  The current standard library barely scratches the surface
  here.

## Getting started

If you don't have a preferred installation method, I recommend
installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and
then simply copy and paste:

    cd ~/.vim/bundle
    git clone git://github.com/tpope/timl.git

Once help tags have been generated, you can view the manual with `:help timl`.
There's not a whole lot there, yet.  If you know Clojure, you can probably
guess a bunch of the function names.

Start a repl with `:TLrepl`.  Tab complete is your friend.  The first time may
take several seconds (if your computer is a piece of shit), but compilation is
cached, so subsequent invocations will be super quick, even if Vim is
restarted.

The familiar `ns` macro from Clojure is mostly identical in TimL. 
`:refer-clojure` is now `:refer-timl`, which is identical to 
`(refer 'timl.core opts)`. `:use` only supports symbol arguments.

    (ns my.ns
      (:refer-timl :exclude [+])
      (:use timl.repl)
      (:require [timl.file :as file]
                [timl.test]))

You can use Clojure's `in-ns`, `require`, `refer`, `alias`, and `use`,
however `use` and `require` are limited to a single argument.

    (in-ns 'my.ns)
    (use 'timl.repl)
    (require 'timl.file)
    (alias 'file 'timl.file)

Put files in `autoload/*.tim` in the runtime path and they will be requirable.

## License

Copyright © Tim Pope.

The use and distribution terms for this software are covered by the [Eclipse
Public License 1.0](http://opensource.org/licenses/eclipse-1.0.php), which can
be found in the file epl-v10.html at the root of this distribution.

By using this software in any fashion, you are agreeing to be bound by the
terms of this license.  You must not remove this notice, or any other, from
this software.


================================================
FILE: autoload/timl/array.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_array')
  finish
endif
let g:autoloaded_timl_array = 1

function! timl#array#lock(array) abort
  lockvar 1 a:array
  return a:array
endfunction

let s:type = type([])
function! timl#array#coerce(seq) abort
  if type(a:seq) ==# s:type
    return a:seq is# g:timl#nil ? [] : a:seq
  elseif timl#type#string(a:seq) ==# 'timl.lang/Vector'
    return copy(a:seq.array)
  endif
  let array = []
  let _ = {'seq': timl#coll#seq(a:seq)}
  while _.seq isnot# g:timl#nil
    call add(array, timl#coll#first(_.seq))
    let _.seq = timl#coll#next(_.seq)
  endwhile
  return array
endfunction

function! timl#array#seq(this, ...) abort
  return len(a:this) <= (a:0 ? a:1 : 0) ? g:timl#nil : timl#array_seq#create(a:this, a:0 ? a:1 : 0)
endfunction

function! timl#array#car(this) abort
  return get(a:this, 0, g:timl#nil)
endfunction

function! timl#array#cdr(this) abort
  return len(a:this) <= 1 ? g:timl#empty_list : timl#array_seq#create(a:this, 1)
endfunction

function! timl#array#lookup(this, idx, ...) abort
  if type(a:idx) == type(0)
    return get(a:this, a:idx, a:0 ? a:1 g:timl#nil)
  endif
  return a:0 ? a:1 : g:timl#nil
endfunction

function! timl#array#nth(this, idx, ...) abort
  let idx = timl#number#int(a:idx)
  if a:0
    return get(a:this, idx, a:1)
  else
    return a:this[idx]
  endif
endfunction

function! timl#array#conj(this, ...) abort
  return a:this + a:000
endfunction

function! timl#array#conjb(this, ...) abort
  return extend(a:this, a:000)
endfunction

function! timl#array#assocb(this, ...) abort
  let this = a:this
  for i in range(0, len(a:000)-2, 2)
    if (timl#number#integerp(a:000[i]) && a:000[i] ==# len(a:this)) || islocked('this')
      call add(this, a:000[i+1])
    else
      let this[a:000[i]] = a:000[i+1]
    endif
  endfor
  return this
endfunction

function! timl#array#dissocb(this, ...) abort
  let _ = {}
  for _.key in a:000
    if timl#number#integerp(_.key) && _.key < len(a:this) && (-_.key-1) < len(a:this)
      call remove(a:this, _.key)
    endif
  endfor
  return a:this
endfunction

function! timl#array#empty(this) abort
  return []
endfunction

function! timl#array#persistentb(this) abort
  return timl#vector#claim(a:this)
endfunction


================================================
FILE: autoload/timl/array_seq.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_array_seq")
  finish
endif
let g:autoloaded_timl_array_seq = 1

function! timl#array_seq#create(array, ...) abort
  let cc = timl#type#bless(s:type, {
        \ 'array': a:array,
        \ 'meta': g:timl#nil,
        \ 'i': a:0 ? a:1 : 0})
  lockvar 1 cc
  return cc
endfunction

function! timl#array_seq#car(seq) abort
  return get(a:seq.array, a:seq.i, g:timl#nil)
endfunction

function! timl#array_seq#cdr(seq) abort
  if len(a:seq.array) - a:seq.i <= 1
    return g:timl#empty_list
  else
    return timl#array_seq#create(a:seq.array, a:seq.i+1)
  endif
endfunction

function! timl#array_seq#length(this) abort
  return len(a:this.array) - a:this.i
endfunction

let s:chunk_size = 32

function! timl#array_seq#chunk_first(this) abort
  return a:this.array[a:this.i : min([a:this.i+s:chunk_size, len(a:this.array)])-1]
endfunction

function! timl#array_seq#chunk_rest(this) abort
  if len(a:this.array) - a:this.i <= s:chunk_size
    return g:timl#empty_list
  else
    return timl#array_seq#create(a:this.array, a:this.i+s:chunk_size)
  endif
endfunction

let s:type = timl#type#core_define('ArraySeq', ['array', 'i', 'meta'], {
      \ 'get-meta': 'timl#meta#from_attribute',
      \ 'with-meta': 'timl#meta#copy_assign_lock',
      \ 'seq': 'timl#function#identity',
      \ 'equiv': 'timl#equality#seq',
      \ 'car': 'timl#array_seq#car',
      \ 'cdr': 'timl#array_seq#cdr',
      \ 'length': 'timl#array_seq#length',
      \ 'conj': 'timl#cons#conj',
      \ 'empty': 'timl#list#empty',
      \ 'chunk-first': 'timl#array_seq#chunk_first',
      \ 'chunk-rest': 'timl#array_seq#chunk_rest'})


================================================
FILE: autoload/timl/atom.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_atom")
  finish
endif
let g:autoloaded_timl_atom = 1

function! timl#atom#create(state, meta, validator) abort
  if a:validator is# g:timl#nil || timl#truth(timl#invoke(a:validator, a:state))
    return s:type.__call__([a:state, a:meta, a:validator, g:timl#nil])
  endif
  throw 'timl: invalid state'
endfunction

function! timl#atom#deref(this) abort
  return a:this.state
endfunction

function! timl#atom#reset(this, state) abort
  if a:this.validator is# g:timl#nil || timl#truth(timl#invoke(a:this.validator, a:state))
    let a:this.state = a:state
    return a:state
  endif
  throw 'timl: invalid state'
endfunction

function! timl#atom#swap(this, fn, ...) abort
  return timl#atom#reset(a:this, timl#call(a:fn, [a:this.state] + a:000))
endfunction

function! timl#atom#compare_and_set(this, old, new) abort
  if a:this.state is# a:this.old
  return timl#atom#reset(a:this, a:new)
endfunction

function! timl#atom#reset_meta(this, meta) abort
  let a:this.meta = a:meta
  return a:this
endfunction

function! timl#atom#set_validator(this, validator) abort
  if a:validator is g:timl#nil || timl#truth(timl#invoke(a:validator, a:this.state))
    let a:this.validator = a:validator
    return a:this
  endif
  throw 'timl: invalid state'
endfunction

function! timl#atom#get_validator(this) abort
  return a:this.validator
endfunction

let s:type = timl#type#core_define('Atom', ['state', 'meta', 'validator', 'watches'], {
      \ 'get-meta': 'timl#meta#from_attribute',
      \ 'reset!': 'timl#atom#reset',
      \ 'swap!': 'timl#atom#swap',
      \ 'compare-and-set!': 'timl#atom#compare_and_set',
      \ 'reset-meta!': 'timl#atom#reset_meta',
      \ 'set-validator!': 'timl#atom#set_validator',
      \ 'get-validator': 'timl#atom#get_validator',
      \ 'deref': 'timl#atom#deref'})


================================================
FILE: autoload/timl/bootstrap.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists("g:autoloaded_timl_bootstrap")
  finish
endif
let g:autoloaded_timl_bootstrap = 1

" Section: Setup

function! s:function(name) abort
  return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '.*\zs<SNR>\d\+_'),''))
endfunction

function! s:implement(type, ...) abort
  let type = timl#symbol#intern(a:type)
  for i in range(0, a:0-1, 2)
    call timl#type#define_method(s:ns, timl#symbol#intern(a:000[i]), type, s:function(a:000[i+1]))
  endfor
endfunction

let s:fn_type = timl#type#core_create('Function')
function! s:intern_fn(name, apply, ...) abort
  let fn = {'name': a:name, 'ns': s:ns}
  if a:0
    call extend(fn, a:1)
  endif
  call timl#type#bless(s:fn_type, fn)
  let fn.__call__ = s:function(a:apply)
  call timl#namespace#intern(s:ns, a:name, fn)
endfunction

let s:ns = timl#namespace#create(timl#symbol#intern('timl.core'))
let s:langns = timl#namespace#create(timl#symbol#intern('timl.lang'))
let s:vimns = timl#namespace#create(timl#symbol#intern('vim'))

function! s:apply(_) dict abort
  return call(self.invoke, a:_, self)
endfunction

function! s:predicate(_) dict abort
  return call(self.test, a:_, self) ? g:timl#true : g:timl#false
endfunction

let s:k_help = timl#keyword#intern('help')
function! s:define_call(name, fn) abort
  if a:fn =~# '^[a-z0-9_]\+$'
    let name = timl#symbol#intern_with_meta(a:name, timl#map#create([s:k_help, a:fn.'()']))
  else
    let name = timl#symbol#intern(a:name)
  endif
  call s:intern_fn(name, 's:apply', {'invoke': s:function(a:fn)})
endfunction

function! s:define_pred(name, fn) abort
  if a:fn =~# '^[a-z0-9_]\+$'
    let name = timl#symbol#intern_with_meta(a:name, timl#map#create([s:k_help, a:fn.'()']))
  else
    let name = timl#symbol#intern(a:name)
  endif
  call s:intern_fn(name, 's:predicate', {'test': s:function(a:fn)})
endfunction

function! s:define_apply(name, fn) abort
  call s:intern_fn(timl#symbol#intern(a:name), a:fn)
endfunction

" Section: Namespace

call s:define_apply('load', 'timl#loader#all_relative')
call s:define_apply('require', 'timl#loader#require_all')
call s:define_apply('use', 'timl#loader#use_all')
call s:define_call('create-ns', 'timl#namespace#create')
call s:define_call('find-ns', 'timl#namespace#find')
call s:define_call('the-ns', 'timl#namespace#the')
call s:define_call('ns-name', 'timl#namespace#name')
call s:define_call('ns-map', 'timl#namespace#map')
call s:define_call('ns-aliases', 'timl#namespace#aliases')
call s:define_call('all-ns', 'timl#namespace#all')
call s:define_call('in-ns', 'timl#namespace#select')
call s:define_call('refer', 'timl#namespace#refer')
call s:define_call('alias', 'timl#namespace#alias')
call s:define_call('intern', 'timl#namespace#intern')

" Section: Var

call s:define_call('var-get', 'timl#var#get')
call s:define_call('find-var', 'timl#var#find')
call s:define_pred('var?', 'timl#var#test')
call s:define_call('munge', 'timl#var#munge')

" Section: Type Sytem

call s:define_pred('isa?', 'timl#type#isap')
call s:define_pred('can?', 'timl#type#canp')

call s:implement('timl.lang/Type',
      \ 'hash', 'timl#hash#str_attribute',
      \ 'call', 'timl#function#call')

" Section: Meta

call s:define_call('meta', 'timl#meta#get')
call s:define_call('vary-meta', 'timl#meta#vary')
call s:define_call('alter-meta!', 'timl#meta#alter')

" Section: Symbol/Keyword

call s:define_call('symbol', 'timl#symbol#intern')
call s:define_call('keyword', 'timl#keyword#intern')
call s:define_call('gensym', 'timl#symbol#gen')
call s:define_pred('symbol?', 'timl#symbol#test')
call s:define_pred('keyword?', 'timl#keyword#test')

" Section: Equality

call s:define_apply('identical?', 'timl#equality#identical')
call s:define_apply('=', 'timl#equality#all')
call s:define_apply('not=', 'timl#equality#not')

" Section: Nil

call s:define_pred('nil?', 'timl#nil#test')
call timl#nil#identity()

" Section: Number

call timl#type#define(s:vimns, timl#symbol('Number'), g:timl#nil)
call s:implement('vim/Number',
      \ 'hash', 'timl#function#identity',
      \ 'to-string', 'string')

call s:define_call('num', 'timl#num#coerce')
call s:define_call('int', 'timl#number#int')
call s:define_call('float', 'timl#number#float')
call s:define_pred('number?', 'timl#number#test')
call s:define_pred('integer?', 'timl#number#integerp')
call s:define_pred('float?', 'timl#number#floatp')
call s:define_apply('+', 'timl#number#sum')
call s:define_apply('*', 'timl#number#product')
call s:define_apply('-', 'timl#number#minus')
call s:define_apply('/', 'timl#number#solidus')
call s:define_apply('>', 'timl#number#gt')
call s:define_apply('<', 'timl#number#lt')
call s:define_apply('>=', 'timl#number#gteq')
call s:define_apply('<=', 'timl#number#lteq')
call s:define_apply('==', 'timl#number#equiv')
call s:define_apply('max', 'max')
call s:define_apply('min', 'min')
call s:define_call('inc', 'timl#number#inc')
call s:define_call('dec', 'timl#number#dec')
call s:define_call('rem', 'timl#number#rem')
call s:define_call('quot', 'timl#number#quot')
call s:define_call('mod', 'timl#number#mod')
call s:define_call('bit-not', 'timl#number#bit_not')
call s:define_apply('bit-or', 'timl#number#bit_or')
call s:define_apply('bit-xor', 'timl#number#bit_xor')
call s:define_apply('bit-and', 'timl#number#bit_and')
call s:define_apply('bit-and-not', 'timl#number#bit_and_not')
call s:define_call('bit-shift-left', 'timl#number#bit_shift_left')
call s:define_call('bit-shift-right', 'timl#number#bit_shift_right')
call s:define_call('bit-flip', 'timl#number#bit_flip')
call s:define_call('bit-set', 'timl#number#bit_set')
call s:define_call('bit-clear', 'timl#number#bit_clear')
call s:define_pred('bit-test', 'timl#number#bit_test')
call s:define_call('not-negative', 'timl#number#not_negative')
call s:define_pred('zero?', 'timl#number#zerop')
call s:define_pred('nonzero?', 'timl#number#nonzerop')
call s:define_pred('pos?', 'timl#number#posp')
call s:define_pred('neg?', 'timl#number#negp')
call s:define_pred('odd?', 'timl#number#oddp')
call s:define_pred('even?', 'timl#number#evenp')

call s:define_call('str2nr', 'str2nr')
if has('float')
  call timl#type#define(s:vimns, timl#symbol('Float'), g:timl#nil)
  call s:implement('vim/Float',
        \ 'to-string', 'string')
  call s:define_call('str2float', 'str2float')
  call s:define_call('float2nr', 'float2nr')
endif

" Section: String

call timl#type#define(s:vimns, timl#symbol('String'), g:timl#nil)

call s:implement('vim/String',
      \ 'to-string', 'timl#function#identity',
      \ 'hash', 'timl#hash#string',
      \ 'funcref', 'function',
      \ 'seq', 'timl#string#seq',
      \ 'lookup', 'timl#string#lookup',
      \ 'length', 'timl#string#length')

call s:define_call('format', 'printf')
call s:define_apply('str', 'timl#string#join')
call s:define_call('join', 'timl#string#join')
call s:define_call('split', 'timl#string#split')
call s:define_call('replace', 'timl#string#replace')
call s:define_call('replace-one', 'timl#string#replace_one')
call s:define_call('re-quote-replacement', 'timl#string#re_quote_replacement')
call s:define_call('re-find', 'timl#string#re_find')
call s:define_call('subs', 'timl#string#sub')
call s:define_apply('pr-str', 'timl#string#pr')
call s:define_apply('prn-str', 'timl#string#prn')
call s:define_apply('print-str', 'timl#string#print')
call s:define_apply('println-str', 'timl#string#println')

call s:define_pred('string?', 'timl#string#test')

call s:define_call('char2nr', 'char2nr')
call s:define_call('nr2char', 'nr2char')

" Section: Boolean

let s:boolean = timl#type#core_define('Boolean', g:timl#nil, {
      \ 'hash': 'len'})

if !exists('g:timl#false')
  call timl#false#identity()
  call timl#true#identity()
endif

call s:define_pred('boolean', 'timl#truth')
call s:define_pred('false?', 'timl#false#test')
call s:define_pred('true?', 'timl#true#test')

" Section: Function

call timl#type#define(s:vimns, timl#symbol('Funcref'), g:timl#nil)

call s:implement('timl.lang/Function',
      \ 'hash', 'timl#function#hash',
      \ 'call', 'timl#function#call')

call s:implement('timl.lang/MultiFn',
      \ 'hash', 'timl#function#hash',
      \ 'call', 'timl#type#dispatch')

call s:implement('vim/Funcref',
      \ 'funcref', 'timl#function#identity',
      \ 'to-string', 'timl#funcref#string',
      \ 'hash', 'timl#funcref#hash',
      \ 'call', 'timl#funcref#call')

call s:define_pred('funcref?', 'timl#funcref#test')

call s:define_apply('apply', 'timl#function#apply')
call s:define_call('identity', 'timl#function#identity')

call s:define_call('fn', 'timl#function#fn')
call s:define_call('defn', 'timl#function#defn')
call s:define_call('defmacro', 'timl#function#defmacro')
for s:x in ['fn', 'defn', 'defmacro']
  let s:y = timl#namespace#maybe_resolve(s:ns, timl#symbol#intern(s:x))
  let s:y.meta = timl#map#create([timl#keyword#intern('macro'), g:timl#true])
endfor
unlet s:x s:y

" Section: Array (Vim List)

call timl#type#define(s:vimns, timl#symbol('List'), g:timl#nil)
call s:implement('vim/List',
      \ 'seq', 'timl#array#seq',
      \ 'car', 'timl#array#car',
      \ 'cdr', 'timl#array#cdr',
      \ 'lookup', 'timl#array#lookup',
      \ 'nth', 'timl#array#nth',
      \ 'length', 'len',
      \ 'conj', 'timl#array#conj',
      \ 'empty', 'timl#array#empty')

call s:implement('vim/List',
      \ 'equiv', 'timl#equality#seq',
      \ 'conj!', 'timl#array#conjb',
      \ 'assoc!', 'timl#array#assocb',
      \ 'dissoc!', 'timl#array#dissocb',
      \ 'persistent!', 'timl#array#persistentb')

call s:define_apply('array', 'timl#array#coerce')

" Section: Vector

call timl#type#define(s:langns, timl#symbol('Vector'), g:timl#nil)

call s:implement('timl.lang/Vector',
      \ 'seq', 'timl#vector#seq',
      \ 'car', 'timl#vector#car',
      \ 'cdr', 'timl#vector#cdr',
      \ 'lookup', 'timl#vector#lookup',
      \ 'nth', 'timl#vector#nth',
      \ 'length', 'timl#vector#length',
      \ 'conj', 'timl#vector#conj',
      \ 'empty', 'timl#vector#empty',
      \ 'call', 'timl#vector#call')

call s:implement('timl.lang/Vector',
      \ 'equiv', 'timl#equality#seq',
      \ 'transient', 'timl#vector#transient')

call s:define_call('subvec', 'timl#vector#sub')
call s:define_pred('vector?', 'timl#vector#test')
call s:define_call('vec', 'timl#vector#coerce')
call s:define_apply('vector', 'timl#vector#coerce')

" Section: Cons

call s:define_call('cons', 'timl#cons#create')
call s:define_apply('list*', 'timl#cons#spread')

" Section: List

let g:timl#empty_list = timl#list#empty()

call s:define_apply('list', 'timl#list#create')
call s:define_pred('list?', 'timl#list#test')

" Section: Seq

call s:define_call('first', 'timl#coll#first')
call s:define_call('next', 'timl#coll#next')
call s:define_call('rest', 'timl#coll#rest')
call s:define_pred('empty?', 'timl#coll#emptyp')
call s:define_call('ffirst', 'timl#coll#ffirst')
call s:define_call('fnext', 'timl#coll#fnext')
call s:define_call('nfirst', 'timl#coll#nfirst')
call s:define_call('nnext', 'timl#coll#nnext')
call s:define_call('second', 'timl#coll#fnext')

" Section: Chunked Cons

call s:define_call('chunk-cons', 'timl#chunked_cons#create')

" Section: Dictionary

call timl#type#define(s:vimns, timl#symbol('Dictionary'), g:timl#nil)
call s:implement('vim/Dictionary',
      \ 'seq', 'timl#dictionary#seq',
      \ 'lookup', 'timl#dictionary#lookup',
      \ 'empty', 'timl#dictionary#empty',
      \ 'conj', 'timl#dictionary#conj',
      \ 'length', 'len',
      \ 'equiv', 'timl#map#equal')

call s:implement('vim/Dictionary',
      \ 'assoc', 'timl#dictionary#assoc',
      \ 'dissoc', 'timl#dictionary#dissoc',
      \ 'transient', 'timl#dictionary#transient')

call s:implement('vim/Dictionary',
      \ 'conj!', 'timl#dictionary#conjb',
      \ 'assoc!', 'timl#dictionary#assocb',
      \ 'dissoc!', 'timl#dictionary#dissocb',
      \ 'persistent!', 'timl#dictionary#persistentb')

call s:define_pred('dict?', 'timl#dictionary#test')
call s:define_apply('dict', 'timl#dictionary#create')

" Section: Hash Map

call timl#type#define(s:langns, timl#symbol('HashMap'), g:timl#nil)

call s:implement('timl.lang/HashMap',
      \ 'seq', 'timl#map#seq',
      \ 'lookup', 'timl#map#lookup',
      \ 'empty', 'timl#map#empty',
      \ 'conj', 'timl#map#conj',
      \ 'length', 'timl#map#length',
      \ 'equiv', 'timl#map#equal')

call s:implement('timl.lang/HashMap',
      \ 'assoc', 'timl#map#assoc',
      \ 'dissoc', 'timl#map#dissoc',
      \ 'call', 'timl#map#call')

call s:define_pred('map?', 'timl#map#test')
call s:define_apply('hash-map', 'timl#map#create')
call s:define_call('zipmap', 'timl#map#zip')

" Section: Hash Set

call s:define_pred('set?', 'timl#set#test')
call s:define_call('set', 'timl#set#coerce')
call s:define_apply('hash-set', 'timl#set#coerce')
runtime! autoload/timl/set.vim

" Section: Collection

call s:define_pred('coll?', 'timl#coll#test')
call s:define_pred('seq?', 'timl#coll#seqp')
call s:define_pred('sequential?', 'timl#coll#sequentialp')
call s:define_pred('chunked-seq?', 'timl#coll#chunked_seqp')
call s:define_call('count', 'timl#coll#count')
call s:define_call('get', 'timl#coll#get')
call s:define_call('into', 'timl#coll#into')
call s:define_call('reduce', 'timl#coll#reduce')
call s:define_pred('contains?', 'timl#coll#containsp')

" Section: Compiler

call s:define_pred('special-symbol?', 'timl#compiler#specialp')
call s:define_call('macroexpand-1', 'timl#compiler#macroexpand_1')
call s:define_call('macroexpand-all', 'timl#compiler#macroexpand_all')

" Section: I/O

call s:define_apply('echo', 'timl#io#echo')
call s:define_apply('echon', 'timl#io#echon')
call s:define_apply('echomsg', 'timl#io#echomsg')
call s:define_apply('print', 'timl#io#echon')
call s:define_apply('println', 'timl#io#println')
call s:define_call('newline', 'timl#io#newline')
call s:define_call('printf', 'timl#io#printf')
call s:define_apply('pr', 'timl#io#pr')
call s:define_apply('prn', 'timl#io#prn')
call s:define_call('spit', 'timl#io#spit')
call s:define_call('slurp', 'timl#io#slurp')
call s:define_call('read-string', 'timl#reader#read_string')

" Section: Reference types

call s:define_call('force', 'timl#delay#force')
call s:define_call('future-call', 'timl#future#call')
runtime! autoload/timl/atom.vim

" Section: Time

call s:define_call('inst', 'timl#inst#create')
call s:define_call('sleep', 'timl#inst#sleep')

" Section: Vim Interop

call s:define_pred('exists?', 'exists')
call s:define_pred('has?', 'has')

" vim:set et sw=2:


================================================
FILE: autoload/timl/buffer.tim
================================================
(ns timl.buffer)

(deftype Buffer [nr])

(defmethod lookup Buffer [self key not-found]
  (get (#*getbufvar (. self nr) "") (str key) not-found))

(defmethod buffer Buffer [buf] buf)
(defmethod buffer vim/Number [nr] (when (nonzero? (#*bufexists nr)) (Buffer nr)))
(defmethod buffer vim/String [name] (when-let [nr (not-negative (#*bufnr name))] (Buffer nr)))


================================================
FILE: autoload/timl/chunked_cons.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_chunked_cons")
  finish
endif
let g:autoloaded_timl_chunked_cons = 1

function! timl#chunked_cons#create(array, rest, ...) abort
  lockvar 1 a:array
  let cc = timl#type#bless(s:type, {
        \ 'array': a:array,
        \ 'rest': a:rest,
        \ 'meta': g:timl#nil,
        \ 'i': a:0 ? a:1 : 0})
  lockvar 1 cc
  return cc
endfunction

function! timl#chunked_cons#car(this) abort
  return get(a:this.array, a:this.i, g:timl#nil)
endfunction

function! timl#chunked_cons#cdr(this) abort
  if len(a:this.array) - a:this.i <= 1
    return a:this.rest
  else
    return timl#chunked_cons#create(a:this.array, a:this.rest, a:this.i+1)
  endif
endfunction

function! timl#chunked_cons#length(this) abort
  let c = len(a:this.array) - a:this.i
  let _ = {'next': timl#coll#seq(a:this.rest)}
  while timl#type#string(_.next) ==# s:type.str
    let c += len(_.next.array) - _.next.i
    let _.next = timl#coll#seq(timl#chunked_cons#chunk_rest(_.next))
  endwhile
  return c + timl#coll#count(_.next)
endfunction

function! timl#chunked_cons#chunk_first(this) abort
  return a:this.array[a:this.i : -1]
endfunction

function! timl#chunked_cons#chunk_rest(this) abort
  return a:this.rest
endfunction

let s:type = timl#type#core_define('ChunkedCons', ['array', 'rest', 'i', 'meta'], {
      \ 'get-meta': 'timl#meta#from_attribute',
      \ 'with-meta': 'timl#meta#copy_assign_lock',
      \ 'seq': 'timl#function#identity',
      \ 'equiv': 'timl#equality#seq',
      \ 'car': 'timl#chunked_cons#car',
      \ 'cdr': 'timl#chunked_cons#cdr',
      \ 'length': 'timl#chunked_cons#length',
      \ 'conj': 'timl#cons#conj',
      \ 'empty': 'timl#list#empty',
      \ 'chunk-first': 'timl#chunked_cons#chunk_first',
      \ 'chunk-rest': 'timl#chunked_cons#chunk_rest'})


================================================
FILE: autoload/timl/coll.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:timl_autoloaded_coll')
  finish
endif
let g:timl_autoloaded_coll = 1

function! timl#coll#test(coll) abort
  return timl#type#canp(a:coll, g:timl#core.conj)
endfunction

function! timl#coll#seq(coll) abort
  return timl#invoke(g:timl#core.seq, a:coll)
endfunction

function! timl#coll#emptyp(seq) abort
  return timl#coll#seq(a:seq) is# g:timl#nil
endfunction

function! timl#coll#sequentialp(coll) abort
  return a:coll isnot# g:timl#nil && timl#type#canp(a:coll, g:timl#core.car)
endfunction

function! timl#coll#seqp(obj) abort
  return timl#type#string(a:obj) =~# '^timl\.lang/\%(Cons\|EmptyList\)$' ||
        \ (timl#type#canp(a:obj, g:timl#core.car) && !timl#vector#test(a:obj))
endfunction

function! timl#coll#first(coll) abort
  if timl#cons#test(a:coll)
    return a:coll.car
  elseif type(a:coll) == type([])
    return get(a:coll, 0, g:timl#nil)
  elseif timl#type#canp(a:coll, g:timl#core.car)
    return timl#invoke(g:timl#core.car, a:coll)
  else
    return timl#invoke(g:timl#core.car, timl#coll#seq(a:coll))
  endif
endfunction

function! timl#coll#rest(coll) abort
  if timl#cons#test(a:coll)
    return a:coll.cdr
  elseif timl#type#canp(a:coll, g:timl#core.cdr)
    return timl#invoke(g:timl#core.cdr, a:coll)
  else
    return timl#invoke(g:timl#core.cdr, timl#coll#seq(a:coll))
  endif
endfunction

function! timl#coll#next(coll) abort
  let rest = timl#coll#rest(a:coll)
  return timl#coll#seq(rest)
endfunction

function! timl#coll#ffirst(seq) abort
  return timl#coll#first(timl#coll#first(a:seq))
endfunction

function! timl#coll#fnext(seq) abort
  return timl#coll#first(timl#coll#next(a:seq))
endfunction

function! timl#coll#nfirst(seq) abort
  return timl#coll#next(timl#coll#first(a:seq))
endfunction

function! timl#coll#nnext(seq) abort
  return timl#coll#next(timl#coll#next(a:seq))
endfunction

function! timl#coll#chunked_seqp(coll) abort
  return timl#type#canp(a:coll, g:timl#core.chunk_first)
endfunction

function! timl#coll#get(coll, key, ...) abort
  if timl#type#canp(a:coll, g:timl#core.lookup)
    return timl#invoke(g:timl#core.lookup, a:coll, a:key, a:0 ? a:1 : g:timl#nil)
  else
    return a:0 ? a:1 : g:timl#nil
  endif
endfunction

function! timl#coll#containsp(coll, val) abort
  let sentinel = {}
  return timl#coll#get(a:coll, a:val, sentinel) isnot# sentinel
endfunction

function! timl#coll#count(counted) abort
  if timl#type#canp(a:counted, g:timl#core.length)
    return timl#invoke(g:timl#core.length, a:counted)
  endif
  let _ = {'seq': timl#coll#seq(a:counted)}
  let c = 0
  while !timl#type#canp(_.seq, g:timl#core.length)
    let _.seq = timl#coll#next(_.seq)
    let c += 1
  endwhile
  return c + timl#invoke(g:timl#core.length, _.seq)
endfunction

function! timl#coll#into(coll, seq) abort
  let t = timl#type#string(a:coll)
  if timl#type#canp(a:coll, g:timl#core.transient)
    let _ = {'coll': timl#invoke(g:timl#core.transient, a:coll), 'seq': timl#coll#seq(a:seq)}
    while _.seq isnot# g:timl#nil
      let _.coll = timl#invoke(g:timl#core.conj_BANG_, _.coll, timl#coll#first(_.seq))
      let _.seq = timl#coll#next(_.seq)
    endwhile
    return timl#invoke(g:timl#core.persistent_BANG_, _.coll)
  else
    let _ = {'coll': a:coll, 'seq': timl#coll#seq(a:seq)}
    while _.seq isnot# g:timl#nil
      let _.coll = timl#invoke(g:timl#core.conj, _.coll, timl#coll#first(_.seq))
      let _.seq = timl#coll#next(_.seq)
    endwhile
    return _.coll
  endif
endfunction

function! timl#coll#reduce(f, coll, ...) abort
  let _ = {}
  if a:0
    let _.val = a:coll
    let _.seq = timl#coll#seq(a:1)
  else
    let _.seq = timl#coll#seq(a:coll)
    if empty(_.seq)
      return g:timl#nil
    endif
    let _.val = timl#coll#first(_.seq)
    let _.seq = timl#coll#rest(_.seq)
  endif
  while _.seq isnot# g:timl#nil
    let _.val = timl#invoke(a:f, _.val, timl#coll#first(_.seq))
    let _.seq = timl#coll#next(_.seq)
  endwhile
  return _.val
endfunction

function! timl#coll#mutating_map(f, coll) abort
  return map(a:coll, 'timl#call(a:f, [v:val])')
endfunction

function! timl#coll#mutating_filter(pred, coll) abort
  return filter(a:coll, 'timl#truth(timl#call(a:pred, [v:val]))')
endfunction


================================================
FILE: autoload/timl/compiler.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_compiler')
  finish
endif
let g:autoloaded_timl_compiler = 1

" Section: Symbol resolution

let s:specials = {
      \ 'if': 1,
      \ 'do': 1,
      \ 'let*': 1,
      \ 'fn*': 1,
      \ 'recur': 1,
      \ 'def': 1,
      \ 'deftype*': 1,
      \ 'set!': 1,
      \ 'execute': 1,
      \ '.': 1,
      \ 'quote': 1,
      \ 'function': 1,
      \ 'var': 1,
      \ 'throw': 1,
      \ 'try': 1,
      \ 'catch': 1,
      \ 'finally': 1}

function! timl#compiler#specialp(sym) abort
  return has_key(s:specials, timl#string#coerce(a:sym))
endfunction

function! timl#compiler#resolve(sym) abort
  if a:sym[0] =~# '^\w:'
    return {'location': timl#var#munge(a:sym[0])}
  elseif a:sym[0][0] ==# '$'
    return {'location': "(exists('".a:sym[0]."') ? ".a:sym[0]." : g:timl#nil)"}
  elseif (a:sym[0] =~# '^&\w' && exists(a:sym[0]))
    return {'location': a:sym[0]}
  elseif a:sym[0] =~# '\.[^/]\+$'
    return {'location': 'g:'.timl#namespace#munge(a:sym[0])}
  endif
  let var = timl#namespace#maybe_resolve(g:timl#core._STAR_ns_STAR_, a:sym)
  if var isnot# g:timl#nil
    return var
  endif
  throw "timl#compiler: could not resolve ".timl#string#coerce(a:sym)
endfunction

" Section: Macroexpand

let s:kmacro = timl#keyword#intern('macro')
function! timl#compiler#macroexpand_1(form) abort
  if timl#coll#seqp(a:form) && timl#symbol#test(timl#coll#first(a:form)) && !timl#compiler#specialp(timl#coll#first(a:form))
    let var = timl#namespace#maybe_resolve(g:timl#core._STAR_ns_STAR_, timl#coll#first(a:form))
    if var isnot# g:timl#nil && timl#truth(timl#coll#get(var.meta, s:kmacro))
      return timl#call(timl#var#get(var), [a:form, {}] + timl#array#coerce(timl#coll#next(a:form)))
    endif
  endif
  return a:form
endfunction

function! timl#compiler#macroexpand_all(form) abort
  let _ = {'last': g:timl#nil, 'this': a:form}
  while _.last isnot# _.this
    let [_.last, _.this] = [_.this, timl#compiler#macroexpand_1(_.this)]
  endwhile
  return _.this
endfunction

" Section: Serialization

let s:escapes = {
      \ "\b": '\b',
      \ "\e": '\e',
      \ "\f": '\f',
      \ "\n": '\n',
      \ "\r": '\r',
      \ "\t": '\t',
      \ "\"": '\"',
      \ "\\": '\\'}

function! timl#compiler#serialize(x) abort
  " TODO: guard against recursion
  if timl#keyword#test(a:x)
    return 'timl#keyword#intern('.timl#compiler#serialize(a:x[0]).')'

  elseif timl#symbol#test(a:x)
    if a:x.meta isnot# g:timl#nil
      return 'timl#symbol#intern_with_meta('.timl#compiler#serialize(a:x[0]).', '.timl#compiler#serialize(a:x.meta).')'
    else
      return 'timl#symbol#intern('.timl#compiler#serialize(a:x[0]).')'
    endif

  elseif a:x is# g:timl#nil
    return 'g:timl#nil'

  elseif a:x is# g:timl#false
    return 'g:timl#false'

  elseif a:x is# g:timl#true
    return 'g:timl#true'

  elseif timl#list#emptyp(a:x)
    if a:x.meta isnot# g:timl#nil
      return 'timl#meta#with(g:timl#empty_list, '.timl#compiler#serialize(a:x.meta).')'
    else
      return 'g:timl#empty_list'
    endif

  elseif type(a:x) == type([])
    return '['.join(map(copy(a:x), 'timl#compiler#serialize(v:val)'), ', ').']'

  elseif timl#vector#test(a:x)
    return 'timl#vector#claim(['.join(map(timl#array#coerce(a:x), 'timl#compiler#serialize(v:val)'), ', ').'])'

  elseif timl#map#test(a:x) && timl#type#string(a:x) !=# 'vim/Dictionary'
    let _ = {}
    let keyvals = []
    let _.seq = timl#coll#seq(a:x)
    while _.seq isnot# g:timl#nil
      call extend(keyvals, timl#array#coerce(timl#coll#first(_.seq)))
      let _.seq = timl#coll#next(_.seq)
    endwhile
    return 'timl#map#create('.timl#compiler#serialize(keyvals).')'

  elseif timl#set#test(a:x)
    let _ = {}
    let keyvals = []
    let _.seq = timl#coll#seq(a:x)
    while _.seq isnot# g:timl#nil
      call add(keyvals, timl#coll#first(_.seq))
      let _.seq = timl#coll#next(_.seq)
    endwhile
    return 'timl#set#coerce('.timl#compiler#serialize(keyvals).')'

  elseif timl#type#string(a:x) ==# 'timl.lang/Cons'
    return 'timl#cons#create('
          \ . timl#compiler#serialize(a:x.car).','
          \ . timl#compiler#serialize(a:x.cdr).','
          \ . timl#compiler#serialize(a:x.meta).')'

  elseif timl#type#string(a:x) ==# 'timl.lang/Type'
    return 'timl#type#find('.timl#compiler#serialize(timl#symbol#intern(a:x.str)).')'

  elseif timl#var#test(a:x)
    return 'timl#var#find('.timl#compiler#serialize(timl#symbol#intern(a:x.str)).')'

  elseif type(a:x) == type('')
    return '"'.substitute(a:x, "[\001-\037\"\\\\]", '\=get(s:escapes, submatch(0), printf("\\%03o", char2nr(submatch(0))))', 'g').'"'
  elseif type(a:x) == 5 && string(a:x) =~# 'n'
    if string(a:x) ==# 'inf'
      return '(1/0.0)'
    elseif string(a:x) ==# '-inf'
      return '(-1/0.0)'
    else
      return '(0/0.0)'
    endif
  elseif type(a:x) != type({})
    return string(a:x)

  elseif timl#type#objectp(a:x)
    return 'timl#type#bless('.timl#compiler#serialize(a:x.__type__) . ', ' . timl#compiler#serialize(filter(copy(a:x), 'v:key !~# "^__.*__$"')).')'

  else
    let acc = []
    for [k, V] in items(a:x)
      call add(acc, timl#compiler#serialize(k) . ': ' . timl#compiler#serialize(V))
      unlet! V
    endfor
    return '{' . join(acc, ', ') . '}'

  endif
endfunction

" Section: Emission

function! s:emitln(file, str) abort
  call add(a:file, a:str)
  return a:file
endfunction

function! s:localfy(name) abort
  return a:name =~# '^\h\w*$' ? 'locals.'.a:name :  'locals['.string(a:name).']'
endfunction

function! s:with_context(env, context) abort
  let env = copy(a:env)
  let env.context = a:context
  return env
endfunction

function! s:copy_locals(env) abort
  let env = copy(a:env)
  let env.locals = copy(a:env.locals)
  return env
endfunction

function! s:let_tmp(file, env, clue, str) abort
  let a:env.temp[a:clue] = get(a:env.temp, a:clue, 0) + 1
  let temp = a:clue . a:env.temp[a:clue]
  call s:emitln(a:file, 'let '.temp.' = '.a:str)
  return temp
endfunction

function! s:wrap_as_expr(file, env, form) abort
  let env = s:with_context(a:env, 'return')
  if has_key(env, 'params')
    call remove(env, 'params')
  endif
  let temp = s:let_tmp(a:file, env, 'thunk', '{"locals": copy(locals)}')
  call s:emitln(a:file, "function ".temp.".call() abort")
  call s:emitln(a:file, "let locals = self.locals")
  call s:emit(a:file, env, a:form)
  call s:emitln(a:file, "endfunction")
  return temp.'.call()'
endfunction

function! s:expr_sf_let_STAR_(file, env, form) abort
  return s:wrap_as_expr(a:file, a:env, a:form)
endfunction

function! s:add_local(env, sym) abort
  let str = timl#symbol#cast(a:sym)[0]
  let a:env.locals[str] = s:localfy(str)
endfunction

let s:k_as = timl#keyword#intern('as')
let s:k_or = timl#keyword#intern('or')

function! s:assign(file, env, key, val) abort
  let _ = {}
  if timl#symbol#test(a:key)
    call s:emitln(a:file, 'let '.s:localfy(a:key[0]).' = '.a:val)
    return s:add_local(a:env, a:key)
  elseif timl#vector#test(a:key)
    let coll = s:let_tmp(a:file, a:env, 'coll', a:val)
    let array = s:let_tmp(a:file, a:env, 'array', 'timl#array#coerce('.coll.')')
    let _.seq = timl#coll#seq(a:key)
    let i = 0
    while _.seq isnot g:timl#nil
      let _.elem = timl#coll#first(_.seq)
      let _.seq = timl#coll#next(_.seq)
      if timl#symbol#is(_.elem, '&')
        call s:assign(a:file, a:env, timl#coll#first(_.seq), 'timl#array#seq('.array.', '.i.')')
        let _.seq = timl#coll#next(_.seq)
      elseif _.elem is# s:k_as
        call s:assign(a:file, a:env, timl#coll#first(_.seq), coll)
        let _.seq = timl#coll#next(_.seq)
      else
        call s:assign(a:file, a:env, _.elem, 'get('.array.', '.i.', g:timl#nil)')
      endif
      let i += 1
    endwhile

  elseif timl#map#test(a:key)
    let as = timl#coll#get(a:key, s:k_as, a:key)
    if as isnot# a:key
      let coll = s:localfy(timl#symbol#cast(as).name)
      call s:emitln(a:file, 'let '.coll.' = '.a:val)
      call s:add_local(a:env, as)
    else
      let coll = s:let_tmp(a:file, a:env, 'coll', a:val)
    endif
    let or = timl#coll#get(a:key, s:k_or)

    let map = s:let_tmp(a:file, a:env, 'map', 'timl#map#soft_coerce('.coll.')')
    let _.seq = timl#coll#seq(a:key)
    while _.seq isnot g:timl#nil
      let _.pair = timl#coll#first(_.seq)
      let _.var = timl#coll#first(_.pair)
      if _.var isnot# s:k_as && _.var isnot# s:k_or
        if timl#coll#get(or, _.var, or) isnot# or
          call s:assign(a:file, a:env, timl#coll#first(_.pair), 'timl#coll#get('.map
                \ . ', ' . s:expr(a:file, a:env, timl#coll#fnext(_.pair))
                \ . ', ' . s:expr(a:file, a:env, timl#coll#get(or, _.var)).')')
        else
          call s:assign(a:file, a:env, _.var, 'timl#coll#get('.map.', '.s:expr(a:file, a:env, timl#coll#fnext(_.pair)).')')
        endif
      endif
      let _.seq = timl#coll#next(_.seq)
    endwhile

  elseif timl#keyword#test(a:key)
    throw 'timl: invalid binding :'.a:key[0]
  else
    throw 'timl: invalid binding type '.timl#type#string(a:key)
  endif
endfunction

function! s:emit_sf_let_STAR_(file, env, form) abort
  if a:env.context ==# 'statement'
    return s:emitln(a:file, 'call '.s:wrap_as_expr(a:file, a:env, a:form))
  endif
  let ary = timl#array#coerce(timl#coll#fnext(a:form))
  let env = s:copy_locals(a:env)
  for i in range(0, len(ary)-1, 2)
    call s:assign(a:file, env, ary[i], s:expr(a:file, env, ary[i+1]))
  endfor
  let body = timl#coll#nnext(a:form)
  if timl#coll#count(body) == 1
    return s:emit(a:file, env, timl#coll#first(body))
  else
    return s:emit_sf_do(a:file, env, timl#cons#create(timl#symbol('do'), body))
  endif
endfunction

function! s:expr_sf_do(file, env, form) abort
  return s:wrap_as_expr(a:file, a:env, a:form)
endfunction

function! s:emit_sf_do(file, env, form) abort
  let ary = timl#array#coerce(timl#coll#next(a:form))
  if empty(ary)
    return s:emit(a:file, a:env, g:timl#nil)
  endif
  for i in range(len(ary) - 1)
    call s:emit(a:file, s:with_context(a:env, 'statement'), ary[i])
  endfor
  call s:emit(a:file, a:env, ary[-1])
endfunction

function! s:expr_sf_if(file, env, form) abort
  let ary = timl#array#coerce(timl#coll#next(a:form))
  return 'timl#truth('.s:emit(a:file, a:env, ary[0]) . ')'
        \ . ' ? ' . s:emit(a:file, a:env, get(ary, 1, g:timl#nil))
        \ . ' : ' . s:emit(a:file, a:env, get(ary, 2, g:timl#nil))
endfunction

function! s:emit_sf_if(file, env, form) abort
  let ary = timl#array#coerce(timl#coll#next(a:form))
  call s:emitln(a:file, 'if timl#truth('.s:expr(a:file, a:env, ary[0]).')')
  call s:emit(a:file, a:env, get(ary, 1, g:timl#nil))
  call s:emitln(a:file, 'else')
  call s:emit(a:file, a:env, get(ary, 2, g:timl#nil))
  call s:emitln(a:file, 'endif')
endfunction

function! s:expr(file, env, form) abort
  return s:emit(a:file, s:with_context(a:env, 'expr'), a:form)
endfunction

function! s:expr_sf_quote(file, env, form) abort
  return timl#compiler#serialize(timl#coll#fnext(a:form))
endfunction

function! s:expr_sf_function(file, env, form) abort
  return "function(".timl#compiler#serialize(timl#string#coerce(timl#coll#fnext(a:form))).")"
endfunction

function! s:expr_sf_var(file, env, form) abort
  let sym = timl#symbol#cast(timl#coll#fnext(a:form))
  let var = timl#namespace#maybe_resolve(g:timl#core._STAR_ns_STAR_, sym)
  if var isnot# g:timl#nil
    return timl#compiler#serialize(var)
  endif
  throw "timl#compiler: could not resolve ".timl#string#coerce(sym)
endfunction

function! s:one_fn(file, env, form, name, temp, catch_errors) abort
  let env = s:copy_locals(a:env)
  let args = timl#array#coerce(timl#coll#first(a:form))
  let env.params = args
  let body = timl#coll#next(a:form)
  let _ = {}
  let positional = []
  let arity = 0
  for _.arg in args
    if timl#symbol#is(_.arg, '&')
      call s:add_local(env, args[-1])
      let rest = env.locals[args[-1][0]]
      let arity += 1000
      break
    else
      call s:add_local(env, _.arg)
      call add(positional, env.locals[_.arg[0]])
      let arity += 1
    endif
  endfor
  call s:emitln(a:file, "function! ".a:temp."(_) abort")
  call s:emitln(a:file, "let locals = copy(self.locals)")
  if len(a:name)
    call s:emitln(a:file, 'let '.s:localfy(a:name).' = self')
  endif
  if a:catch_errors && !empty(positional)
    call s:emitln(a:file, 'try')
  endif
  if !empty(positional)
    call s:emitln(a:file, "let [".join(positional, ', ').(exists('rest') ? '; rest' : '')."] = a:_")
    if exists('rest')
      call s:emitln(a:file, "let ".rest." = timl#array#seq(rest)")
    endif
  elseif exists('rest')
    call s:emitln(a:file, "let ".rest." = timl#array#seq(a:_)")
  endif
  if a:catch_errors && !empty(positional)
    call s:emitln(a:file, 'catch /^Vim(let):E68[78]:/')
    call s:emitln(a:file, "throw 'timl: arity error'")
    call s:emitln(a:file, 'endtry')
  endif
  let c = 0
  call s:emitln(a:file, "while 1")
  if timl#coll#count(body) == 1
    call s:emit(a:file, s:with_context(env, 'return'), timl#coll#first(body))
  else
    call s:emit_sf_do(a:file, s:with_context(env, 'return'), timl#cons#create(timl#symbol('do'), body))
  endif
  call s:emitln(a:file, "break")
  call s:emitln(a:file, "endwhile")
  call s:emitln(a:file, "endfunction")
  return arity
endfunction

function! s:expr_sf_fn_STAR_(file, env, form) abort
  let env = s:copy_locals(a:env)
  let _ = {}
  let _.next = timl#coll#next(a:form)
  if timl#symbol#test(timl#coll#first(_.next))
    let name = timl#coll#first(_.next)[0]
    let env.locals[name] = s:localfy(name)
    let _.next = timl#coll#next(_.next)
  else
    let name = ''
  endif
  let temp = s:let_tmp(a:file, a:env, 'fn', 'timl#function#birth(copy(locals)' . (empty(name) ? '' : ', timl#symbol#intern('.string(name).')').')')
  if timl#vector#test(timl#coll#first(_.next))
    call s:one_fn(a:file, env, _.next, name, temp.".__call__", 1)
  elseif timl#coll#sequentialp(timl#coll#first(_.next))
    let c = char2nr('a')
    let fns = {}
    while _.next isnot# g:timl#nil
      let fns[s:one_fn(a:file, env, timl#coll#first(_.next), name, temp.'.'.nr2char(c), 0)] = nr2char(c)
      let _.next = timl#coll#next(_.next)
      let c += 1
    endwhile
    call s:emitln(a:file, "function! ".temp.".__call__(_) abort")
    call s:emitln(a:file, "if 0")
    for arity in sort(map(keys(fns), 'printf("%04d", v:val)'))
      if arity >= 1000
        call s:emitln(a:file, "elseif len(a:_) >= ".(arity-1000))
      else
        call s:emitln(a:file, "elseif len(a:_) == ".str2nr(arity))
      endif
      call s:emitln(a:file, 'return self.'.fns[str2nr(arity)]. '(a:_)')
    endfor
    call s:emitln(a:file, "else")
    call s:emitln(a:file, "throw 'timl: arity error'")
    call s:emitln(a:file, "endif")
    call s:emitln(a:file, "endfunction")
  endif
  let meta = timl#compiler#location_meta(a:env.file, a:form)
  if !empty(meta)
    call s:emitln(a:file, 'let g:timl_functions[join(['.temp.".__call__])] = ".timl#compiler#serialize(meta))
  endif
  return temp
endfunction

function! s:emit_sf_recur(file, env, form) abort
  if a:env.context !=# 'return' || !has_key(a:env, 'params')
    throw 'timl#compiler: recur outside of tail position'
  endif
  let bindings = map(copy(filter(copy(a:env.params), 'v:val[0] !=# "&"')), 'a:env.locals[v:val[0]]')
  call s:emitln(a:file, 'let ['.join(bindings, ', ').'] = ['.s:expr_args(a:file, a:env, timl#coll#next(a:form)).']')
  call s:emitln(a:file, 'continue')
endfunction

function! s:expr_sf_execute(file, env, form) abort
  return s:wrap_as_expr(a:file, a:env, a:form)
endfunction

function! s:emit_sf_execute(file, env, form) abort
  let expr = map(copy(timl#array#coerce(timl#coll#next(a:form))), 's:expr(a:file, a:env, v:val)')
  call s:emitln(a:file, 'execute '.join(expr, ' '))
  return s:emit(a:file, a:env, g:timl#nil)
endfunction

function! s:expr_sf_try(file, env, form) abort
  return s:wrap_as_expr(a:file, a:env, a:form)
endfunction

function! s:emit_sf_try(file, env, form) abort
  if a:env.context ==# 'statement'
    return s:emitln(a:file, 'call '.s:wrap_as_expr(a:file, a:env, a:form))
  endif
  call s:emitln(a:file, 'try')
  let _ = {}
  let _.seq = timl#coll#next(a:form)
  let body = []
  while _.seq isnot# g:timl#nil
    if timl#coll#seqp(timl#coll#first(_.seq))
      let _.sym = timl#coll#ffirst(_.seq)
      if timl#symbol#is(_.sym, 'catch') || timl#symbol#is(_.sym, 'finally')
        break
      endif
    endif
    call add(body, timl#coll#first(_.seq))
    let _.seq = timl#coll#next(_.seq)
  endwhile
  if timl#coll#count(body) == 1
    call s:emit(a:file, a:env, timl#coll#first(body))
  else
    call s:emit_sf_do(a:file, a:env, timl#cons#create(timl#symbol('do'), body))
  endif
  while _.seq isnot# g:timl#nil
    let _.first = timl#coll#first(_.seq)
    if timl#coll#seqp(_.first) && timl#symbol#is(timl#coll#first(_.first), 'catch')
      call s:emitln(a:file, 'catch /'.escape(timl#coll#fnext(_.first), '/').'/')
      let var = timl#coll#first(timl#coll#nnext(_.first))
      let env = s:copy_locals(a:env)
      if timl#symbol#test(var) && var[0] !=# '_'
        call s:add_local(env, var)
        call s:emitln(a:file, 'let '.env.locals[var[0]].' = timl#exception#build(v:exception, v:throwpoint)')
      endif
      call s:emit_sf_do(a:file, env, timl#cons#create(timl#symbol('do'), timl#coll#next(timl#coll#nnext(_.first))))
    elseif timl#coll#seqp(_.first) && timl#symbol#is(timl#coll#first(_.first), 'finally')
      call s:emitln(a:file, 'finally')
      call s:emit_sf_do(a:file, s:with_context(a:env, 'statement'), timl#cons#create(timl#symbol('do'), timl#coll#next(_.first)))
    else
      throw 'timl#compiler: invalid form after catch or finally try'
    endif
    let _.seq = timl#coll#next(_.seq)
  endwhile
  call s:emitln(a:file, 'endtry')
endfunction

function! s:expr_sf_throw(file, env, form) abort
  return s:wrap_as_expr(a:file, a:env, a:form)
endfunction

function! s:emit_sf_throw(file, env, form) abort
  call s:emitln(a:file, 'throw '.s:expr(a:file, a:env, timl#coll#fnext(a:form)))
endfunction

function! s:expr_sf_set_BANG_(file, env, form) abort
  let target = timl#coll#fnext(a:form)
  let rest = timl#coll#nnext(a:form)
  if timl#symbol#test(target)
    let var = timl#compiler#resolve(target).location
    if rest isnot# g:timl#nil
      let val = s:expr(a:file, a:env, timl#coll#first(rest))
      if var !~# '^[&$]'
        call s:emitln(a:file, 'unlet! '.var)
      endif
      call s:emitln(a:file, 'let '.var.' = '.val)
    else
      call s:emitln(a:file, 'if !exists('.string(var).')')
      call s:emitln(a:file, 'let '.var.' = g:timl#nil')
      call s:emitln(a:file, 'endif')
    endif
    return var
  elseif timl#coll#seqp(target) && timl#symbol#is(timl#coll#first(target), '.')
    let key = substitute(timl#string#coerce(timl#coll#first(timl#coll#nnext(target))), '^-', '', '')
    let target2 = timl#symbol#cast(timl#coll#fnext(target))
    if has_key(a:env.locals, target2[0])
      let var = a:env.locals[target2[0]]
    else
      let var = timl#compiler#resolve(target2).location
    endif
    let val = s:expr(a:file, a:env, timl#coll#first(rest))
    call s:emitln(a:file, 'let '.var.'['.timl#compiler#serialize(key).'] = '.val)
    return var.'['.timl#compiler#serialize(key).']'
  else
    throw 'timl#compiler: unsupported set! form'
  endif
endfunction

let s:kline = timl#keyword#intern('line')
let s:kfile = timl#keyword#intern('file')
function! s:expr_sf_def(file, env, form) abort
  let rest = timl#coll#next(a:form)
  let var = timl#symbol#cast(timl#coll#first(rest))
  if has_key(a:env, 'file')
    let var = timl#meta#vary(var, g:timl#core.assoc, s:kline, a:env.line, s:kfile, a:env.file)
  endif
  if timl#coll#next(rest) isnot# g:timl#nil
    let val = s:expr(a:file, a:env, timl#coll#fnext(rest))
    return 'timl#namespace#intern(g:timl#core._STAR_ns_STAR_, '.timl#compiler#serialize(var).', '.val.')'
  else
    return 'timl#namespace#intern(g:timl#core._STAR_ns_STAR_, '.timl#compiler#serialize(var).')'
  endif
endfunction

function! s:expr_sf_deftype_STAR_(file, env, form) abort
  let rest = timl#coll#next(a:form)
  let var = timl#symbol#cast(timl#coll#first(rest))
  let slots = timl#array#coerce(timl#coll#fnext(rest))
  if has_key(a:env, 'file')
    let var = timl#meta#vary(var, g:timl#core.assoc, s:kline, a:env.line, s:kfile, a:env.file)
  endif
  return 'timl#type#define(g:timl#core._STAR_ns_STAR_, '.timl#compiler#serialize(var).', '.timl#compiler#serialize(slots).')'
endfunction

function! s:expr_dot(file, env, form) abort
  let val = s:expr(a:file, a:env, timl#coll#fnext(a:form))
  let key = timl#coll#first(timl#coll#nnext(a:form))
  if timl#coll#sequentialp(key)
    return val.'['.timl#compiler#serialize(timl#string#coerce(timl#coll#first(key))).']('.s:expr_args(a:file, a:env, timl#coll#next(key)).')'
  else
    return val.'['.timl#compiler#serialize(timl#string#coerce(key)).']'
  endif
endfunction

function! s:expr_map(file, env, form) abort
  let kvs = []
  let _ = {'seq': timl#coll#seq(a:form)}
  while _.seq isnot# g:timl#nil
    call extend(kvs, timl#array#coerce(timl#coll#first(_.seq)))
    let _.seq = timl#coll#next(_.seq)
  endwhile
  return 'timl#map#create(['.join(map(kvs, 's:emit(a:file, s:with_context(a:env, "expr"), v:val)'), ', ').'])'
endfunction

function! s:expr_args(file, env, form) abort
  return join(map(copy(timl#array#coerce(a:form)), 's:emit(a:file, s:with_context(a:env, "expr"), v:val)'), ', ')
endfunction

function! s:emit(file, env, form) abort
  let env = a:env
  try
    if timl#coll#seqp(a:form)
      if get(a:form, 'meta', g:timl#nil) isnot# g:timl#nil && has_key(a:form.meta, 'line')
        let env = copy(env)
        let env.line = a:form.meta.line
      endif
      let First = timl#coll#first(a:form)
      if timl#symbol#is(First, '.')
        let expr = s:expr_dot(a:file, env, a:form)
      elseif timl#symbol#test(First)
        let munged = timl#var#munge(First[0])
        if env.context ==# 'expr' && exists('*s:expr_sf_'.munged)
          let expr = s:expr_sf_{munged}(a:file, env, a:form)
        elseif exists('*s:emit_sf_'.munged)
          return s:emit_sf_{munged}(a:file, env, a:form)
        elseif exists('*s:expr_sf_'.munged)
          let expr = s:expr_sf_{munged}(a:file, env, a:form)
        else
          if has_key(env.locals, First[0])
            let resolved = env.locals[First[0]]
          else
            let var = timl#compiler#resolve(First)
            if get(var, 'meta', g:timl#nil) isnot# g:timl#nil && timl#truth(timl#coll#get(var.meta, s:kmacro))
              let E = timl#call(timl#var#get(var), [a:form, env] + timl#array#coerce(timl#coll#next(a:form)))
              return s:emit(a:file, env, E)
            endif
            let resolved = var.location
          endif
          let args = s:expr_args(a:file, env, timl#coll#next(a:form))
          let expr = resolved.'.__call__(['.args.'])'
        endif
      elseif First is# g:timl#nil && timl#coll#count(a:form) ==# 0
        let expr = timl#compiler#serialize(a:form)
      else
        let args = s:expr_args(a:file, env, timl#coll#next(a:form))
        if timl#coll#seqp(First) && timl#symbol#is(timl#coll#first(First), 'function')
          let expr = timl#var#munge(timl#coll#fnext(First)).'('.args.')'
        elseif type(First) == type(function('tr'))
          let expr = join([First]).'('.args.')'
        else
          let expr = s:expr(a:file, env, First).'.__call__(['.args.'])'
        endif
      endif
    elseif timl#symbol#test(a:form)
      if has_key(env.locals, a:form[0])
        let expr = env.locals[a:form[0]]
      else
        let expr = timl#compiler#resolve(a:form).location
      endif
    elseif type(a:form) == type([]) && a:form isnot# g:timl#nil
      let expr = 'timl#function#identity(['.s:expr_args(a:file, env, a:form).'])'

    elseif timl#vector#test(a:form)
      let expr = 'timl#vector#claim(['.join(map(copy(timl#array#coerce(a:form)), 's:emit(a:file, s:with_context(env, "expr"), v:val)'), ', ').'])'

    elseif timl#set#test(a:form)
      let expr = 'timl#set#coerce(['.join(map(copy(timl#array#coerce(a:form)), 's:emit(a:file, s:with_context(env, "expr"), v:val)'), ', ').'])'

    elseif timl#map#test(a:form)
      let expr = s:expr_map(a:file, env, a:form)
      if timl#type#string(a:form) == 'vim/Dictionary'
        let expr = substitute(expr, '\C#map#', '#dictionary#', '')
      endif

    else
      let expr = timl#compiler#serialize(a:form)
    endif
    if env.context == 'return'
      call s:emitln(a:file, 'return '.expr)
      return ''
    elseif env.context == 'statement'
      if expr !~# '^["'']' && expr =~# '('
        call s:emitln(a:file, 'call '.expr)
      endif
      return ''
    else
      return expr
    endif
  catch /^timl#compiler:/
    let throw = v:exception
    if throw !~# ' on line'
      let throw .= ' in ' . env.file . ' on line ' .env.line
    endif
    throw throw
  endtry
endfunction

if !exists('g:timl_functions')
  let g:timl_functions = {}
endif

function! timl#compiler#location_meta(file, form) abort
  let meta = timl#meta#get(a:form)
  if type(meta) == type({}) && has_key(meta, 'line') && a:file isnot# 'NO_SOURCE_PATH'
    return {'file': a:file, 'line': meta.line}
  else
    return {}
  endif
endfunction

function! s:function_gc() abort
  for fn in keys(g:timl_functions)
    if !timl#funcref#exists(fn)
      call remove(g:timl_functions, fn)
    endif
  endfor
endfunction

augroup timl#compiler#fn
  autocmd!
  autocmd CursorHold * call s:function_gc()
augroup END

" Section: Compilation

function! timl#compiler#build(x, ...) abort
  let filename = a:0 ? a:1 : 'NO_SOURCE_PATH'
  let file = []
  call s:emit(file, {'file': filename, 'line': 1, 'context': 'return', 'locals': {}, 'temp': {}}, a:x)
  let body = join(file, "\n")."\n"
  let s:dict = {}
  let str = "function s:dict.call() abort\n"
        \ . "let locals = {}\n"
        \ . "while 1\n"
        \ . body
        \ . "endwhile\n"
        \ . "endfunction"
  execute str
  let meta = timl#compiler#location_meta(filename, a:x)
  if !empty(meta)
    let g:timl_functions[join([s:dict.call])] = meta
  endif
  return {'body': body, 'call': s:dict.call}
endfunction

" vim:set et sw=2:


================================================
FILE: autoload/timl/cons.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_cons")
  finish
endif
let g:autoloaded_timl_cons = 1

function! timl#cons#test(obj) abort
  return type(a:obj) == type({}) && get(a:obj, '__type__') is# s:type
endfunction

function! timl#cons#create(car, cdr, ...) abort
  if timl#type#canp(a:cdr, g:timl#core.seq)
    let cons = timl#type#bless(s:type, {'car': a:car, 'cdr': a:cdr is# g:timl#nil ? g:timl#empty_list : a:cdr, 'meta': a:0 ? a:1 : g:timl#nil})
    lockvar 1 cons
    return cons
  endif
  throw 'timl: not seqable: '.timl#type#string(a:cdr)
endfunction

function! timl#cons#spread(array) abort
  if empty(a:array)
    throw 'timl: arity error'
  elseif !timl#type#canp(a:array[-1], g:timl#core.seq)
    throw 'timl: seq required'
  endif
  let _ = {'cdr': a:array[-1]}
  for i in range(len(a:array)-2, 0, -1)
    let _.cdr = timl#cons#create(a:array[i], _.cdr)
  endfor
  return _.cdr
endfunction

function! timl#cons#conj(this, ...) abort
  let head = a:this
  let _ = {}
  for _.e in a:000
    let head = timl#cons#create(_.e, head)
  endfor
  return head
endfunction

function! timl#cons#car(this) abort
  return a:this.car
endfunction

function! timl#cons#cdr(this) abort
  return a:this.cdr
endfunction

let s:type = timl#type#core_define('Cons', ['car', 'cdr', 'meta'], {
      \ 'get-meta': 'timl#meta#from_attribute',
      \ 'with-meta': 'timl#meta#copy_assign_lock',
      \ 'seq': 'timl#function#identity',
      \ 'equiv': 'timl#equality#seq',
      \ 'car': 'timl#cons#car',
      \ 'cdr': 'timl#cons#cdr',
      \ 'conj': 'timl#cons#conj',
      \ 'empty': 'timl#list#empty'})


================================================
FILE: autoload/timl/core.tim
================================================
(in-ns 'timl.core)

(defmacro lazy-seq [& body]
  (list '#*timl#lazy_seq#create (cons 'fn* (cons [] body))))

(defmacro let [& args] (cons 'let* args))

(defn concat
  ([] (lazy-seq nil))
  ([x] (lazy-seq x))
  ([x y]
    (lazy-seq
      (let [s (seq x)]
        (if s
          (if (chunked-seq? s)
            (chunk-cons (chunk-first s) (concat (chunk-rest s) y))
            (cons (first s) (concat (rest s) y)))
          y))))
  ([x y & zs]
     (let [cat (fn cat [xys zs]
                 (lazy-seq
                   (let [xys (seq xys)]
                     (if xys
                       (if (chunked-seq? xys)
                         (chunk-cons (chunk-first xys) (cat (chunk-rest xys) zs))
                         (cons (first xys) (cat (rest xys) zs)))
                       (if zs
                         (cat (first zs) (next zs)))))))]
       (cat (concat x y) zs))))

(defmacro defn- [name & fdecl]
  `(defn ~(with-meta name (assoc (meta name) :private true)) ~@fdecl))

(defmacro deftype [name slots & more]
  `(let [type# (deftype* ~name ~slots)]
     type#))

(defmacro when [test & body]
  `(if ~test (do ~@body)))

(defmacro if-let [bindings then & else]
  (let [form (first bindings)
        tst (first (rest bindings))]
    `(let [temp# ~tst]
      (if temp#
        (let [~form temp#] ~then) ~@else))))

(defmacro when-let [bindings & body]
  (let [form (first bindings)
        tst (first (rest bindings))]
    `(let [temp# ~tst]
      (if temp#
        (let [~form temp#] ~@body)))))

(defmacro or
  ([] nil)
  ([x] x)
  ([x & xs] `(let [or# ~x] (if or# or# (or ~@xs)))))

(defmacro and
  ([] true)
  ([x] x)
  ([x & xs] `(let [and# ~x] (if and# (and ~@xs) and#))))

(defn map [f coll]
  (lazy-seq
    (when-let [s (seq coll)]
      (if (can? s chunk-first)
        (concat
          (#*timl#coll#mutating_map f (chunk-first s))
          (map f (chunk-rest s)))
        (cons (f (first s)) (map f (rest s)))))))

(defn dorun
  ([coll]
   (when (seq coll)
     (if (chunked-seq? coll)
       (recur (chunk-rest coll))
       (recur (next coll)))))
  ([n coll]
   (when (and (seq coll) (pos? n))
     (recur (dec n) (next coll)))))

(defn doall
  ([coll]
   (dorun coll)
   coll)
  ([n coll]
   (dorun n coll)
   coll))

(defn nthrest [coll n]
  (if (and (pos? n) (seq coll))
    (recur (rest coll) (dec n))
    coll))

(defn take [n coll]
  (lazy-seq
    (when (pos? n)
      (when-let [s (seq coll)]
        (cons (first s) (take (dec n) (rest s)))))))

(defn drop
  [n coll]
  (let [step (fn [n coll]
              (if-let [s (seq coll)]
                (if (pos? n)
                  (recur (dec n) (rest s))
                  s)))]
    (lazy-seq (step n coll))))

(defn take-while [pred coll]
  (lazy-seq
    (when-let [s (seq coll)]
      (when (pred (first s))
        (cons (first s) (take-while pred (rest s)))))))

(defn partition
  ([n coll]
   (partition n n coll))
  ([n step coll]
   (lazy-seq
     (when-let [s (seq coll)]
       (let [p (doall (take n s))]
         (when (= n (count p))
           (cons p (partition n step (nthrest s step))))))))
  ([n step pad coll]
   (lazy-seq
     (when-let [s (seq coll)]
       (let [p (doall (take n s))]
         (if (= n (count p))
           (cons p (partition n step pad (nthrest s step)))
           (list (take n (concat p pad)))))))))

(defmacro declare [& names]
  `(do ~@(map (fn [n] (list 'def n)) names)))

(defmacro loop [flat & body]
  (let [bindings (partition 2 flat)]
    `((fn ~(vec (map first bindings)) ~@body) ~@(vec (map (fn [x] (first (rest x))) bindings)))))

(defn some
  [pred coll]
  (when (seq coll)
    (or (pred (first coll)) (recur pred (next coll)))))

(defn refer-timl [& args]
  (apply refer 'timl.core args))
(defmacro ns [name & args]
  `(do
     (in-ns '~name)
     ~(if (some #{:refer-timl} (map first args))
        `nil
        `(refer-timl))
     ~@(map (fn [[cmd & args]]
              (or (when (#{:require :use} cmd)
                    (let [qsym (if (#{:require} cmd)
                                 `require
                                 `use)]
                      `(do ~@(map (fn [a1] `(~qsym '~a1)) args))))
                  (when (#{:refer} cmd)
                    `(refer ~@(map (fn [a] `'~a) args)))
                  (when (#{:refer-timl} cmd)
                    `(refer-timl ~@(map (fn [a] `'~a) args)))))
            args)))

(defn ns-resolve
  ([ns sym] (#*timl#namespace#maybe_resolve ns sym))
  ([ns env sym] (if (contains? (:locals env) sym) nil (ns-resolve ns sym))))

(defn resolve
  ([sym] (ns-resolve *ns* sym))
  ([env sym] (ns-resolve *ns* env sym)))

(defmacro defmethod [name type & body]
  `(#*timl#type#define_method *ns* '~name ~(symbol (. (resolve type) str)) (fn ~@body)))

(load "core_macros")
(load "core_basics")
(load "core_seq")
(load "core_coll")
(load "core_ref")
(load "core_vim")


================================================
FILE: autoload/timl/core_basics.tim
================================================
(in-ns 'timl.core)

(declare *1 *2 *3 *e)

(defn not [x] (if x false true))

(defn eval [form] (#*timl#eval form))

(defn constantly [x] (fn [& args] x))

(defn partial
  ([f] f)
  ([f arg1]
   (fn [& args] (apply f arg1 args)))
  ([f arg1 arg2]
   (fn [& args] (apply f arg1 arg2 args)))
  ([f arg1 arg2 arg3]
   (fn [& args] (apply f arg1 arg2 arg3 args)))
  ([f arg1 arg2 arg3 & more]
   (fn [& args] (apply f arg1 arg2 arg3 (concat more args)))))

(defn complement [f]
  (fn [& rest] (not (apply f rest))))

(defn comp
  ([f] f)
  ([f & fns] (fn [& args] (f (apply (apply comp fns) args)))))

(defn max-key
  ([k x] x)
  ([k x y] (if (> (k x) (k y)) x y))
  ([k x y & more]
   (reduce #(max-key k %1 %2) (max-key k x y) more)))


================================================
FILE: autoload/timl/core_coll.tim
================================================
(in-ns 'timl.core)

(defn to-array [x] (#*timl#array#coerce x))

(defn find [m k] (when (contains? m k) [k (get m k)]))
(defn key [x] (first x))
(defn val [x] (second x))
(defn keys [m] (map key m))
(defn vals [m] (map val m))
(defn get-in [m ks] (reduce get m ks))
(defn associative? [c] (can? c assoc))

(defn comparator [>]
  (fn [x y]
    (if (> x y)
      1
      (if (> y x)
        -1
        0))))

(defn sort
  ([xs] (#*sort (to-array xs)))
  ([op xs]
   (let [cmp (comparator op)]
     (#*sort (to-array xs) #*timl#function#invoke_self cmp))))

(defn merge
  [& maps]
  (when (some identity maps)
    (reduce #(conj (or %1 {}) %2) maps)))


================================================
FILE: autoload/timl/core_macros.tim
================================================
(in-ns 'timl.core)

(defmacro defonce [name expr]
  `(when-not (exists? (munge (str "g:" (ns-name *ns*) "#" '~name)))
     (def ~name ~expr)))

(defmacro if-not
  ([cond then] `(if ~cond nil ~then))
  ([cond then else] `(if ~cond ~else ~then)))

(defmacro when-not [cond & body]
  (list 'if cond nil (cons 'do body)))

(defmacro cond [& clauses]
  (when (seq clauses)
    (list 'if (first clauses)
          (first (rest clauses))
          (cons `cond (rest (rest clauses))))))

(defmacro -> [x & forms]
  (if (seq forms)
    (let [form (first forms)
          more (next forms)] (if more `(-> (-> ~x ~form) ~@more) (if (list? form)
          `(~(first form) ~x ~@(rest form))
          (list form x))))
    x))

(defmacro ->> [x & forms]
  (if-let [[form & more] (seq forms)]
    (if (list? form)
      `(->> (~@form ~x) ~@more)
      `(->> (~form ~x) ~@more))
    x))

(defmacro binding [bindings & body]
  (if (seq bindings)
    `(let [old# ~(first bindings)]
       (try
         (set! ~(first bindings) ~(first (rest bindings)))
         (binding ~(vec (rest (rest bindings))) ~@body)
         (finally (set! ~(first bindings) old#))))
    `(do ~@body)))

(defmacro with-out-str [& body]
  `(let [tempname# (#*tempname)]
     (execute "redraw")
     (binding [&verbosefile tempname#]
       (set! l:TimLfn (fn [] ~@body))
       (execute "silent call timl#invoke(l:TimLfn)"))
     (#*substitute (slurp tempname#) "^\n" "" "g")))

(defmacro time [& body]
  `(let [reltime# (#*reltime)
        result# (do ~@body)]
     (printf "Elapsed time: %s secs\n" (#*reltimestr (#*reltime reltime#)))
     result#))

(defmacro comment [& body])


================================================
FILE: autoload/timl/core_ref.tim
================================================
(in-ns 'timl.core)

(defn atom
  ([state] (#*timl#atom#create state nil nil))
  ([state & {v :validator m :meta}] (#*timl#atom#create state m v)))

(defmacro delay [& body] `(#*timl#delay#create (fn [] ~@body)))

(defmacro future [& body] `(future-call (fn [] ~@body)))


================================================
FILE: autoload/timl/core_seq.tim
================================================
(in-ns 'timl.core)

(defn not-empty [xs] (when (seq xs) xs))

(defn filter [pred coll]
  (lazy-seq
    (loop [s (seq coll)]
      (when s
        (if (chunked-seq? s)
          (concat
            (#*timl#coll#mutating_filter pred (chunk-first s))
            (filter pred (chunk-rest s)))
          (let [f (first s) r (rest s)]
            (if (pred f)
              (cons f (filter pred r))
              (recur (seq r)))))))))

(defn iterate [f x]
  (cons x (lazy-seq (iterate f (f x)))))

(defn repeat
  ([x] (lazy-seq (cons x (repeat x))))
  ([n x] (take n (repeat x))))

(defn every?
  [pred coll]
  (cond
   (nil? (seq coll)) true
   (pred (first coll)) (recur pred (next coll))
   :else false))

(defn range
  ([] (range 0 Infinity 1))
  ([end] (range 0 end 1))
  ([start end] (range start end 1))
  ([start end step]
   (let [comp (if (pos? step) < >)
         closest #(if (comp % %2) % %2)
         next-start (closest end (+ start (* 1024 step)))]
     (if (comp start end)
       (if (integer? next-start)
         (chunk-cons
           (#*range start (dec next-start) step)
           (lazy-seq (range next-start end step)))
         (cons start (range (+ start step) end step)))
       ()))))

(defn reductions [f init xs]
  (cons init
        (lazy-seq
          (if xs
            (reductions f (f init (first xs)) (rest xs))))))

(defn last [xs] (if (next xs) (recur (next xs)) (first xs)))
(defn butlast [s]
  (loop [ret '() s s]
    (if (next s)
      (recur (conj ret (first s)) (next s))
      ret)))

(defn remove
  [pred coll]
  (filter (complement pred) coll))


================================================
FILE: autoload/timl/core_vim.tim
================================================
(in-ns 'timl.core)

(defn stacklist []
  (drop 1 (#*timl#exception#loclist (#*expand "<sfile>"))))

(defmacro with-cwd [dir & body]
  `(let [has-local# (when (exists? "*haslocaldir") (nonzero? (#*haslocaldir)))
         chdir# (if has-local# "lchdir" "chdir")
         back# (#*getcwd)]
     (try
       (execute chdir# (#*fnameescape ~dir))
       ~@body
       (finally (execute chdir# (#*fnameescape back#))))))

(defmacro save-excursion [& body]
  `(let [restore# (#*winsaveview)]
     (try
       ~@body
       (finally (#*winrestview restore#)))))


================================================
FILE: autoload/timl/delay.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_delay")
  finish
endif
let g:autoloaded_timl_delay = 1

function! timl#delay#create(fn) abort
  return s:type.__call__([a:fn, g:timl#nil])
endfunction

function! timl#delay#force(this) abort
  if timl#type#string(a:this) !=# s:type.str
    return a:this
  endif
  return timl#delay#deref(a:this)
endfunction

function! timl#delay#deref(this) abort
  if a:this.fn is# g:timl#nil
    return a:this.val
  endif
  let a:this.val = timl#call(a:this.fn, [])
  let a:this.fn = g:timl#nil
  return a:this.val
endfunction

function! timl#delay#realized(this) abort
  return a:this.fn is# g:timl#nil ? g:timl#true : g:timl#false
endfunction

let s:type = timl#type#core_define('Delay', ['fn', 'val'], {
      \ 'realized?': 'timl#delay#realized',
      \ 'deref': 'timl#delay#deref'})


================================================
FILE: autoload/timl/dictionary.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_dictionary")
  finish
endif
let g:autoloaded_timl_dictionary = 1

function! timl#dictionary#test(coll) abort
  return timl#type#string(a:coll) ==# 'vim/Dictionary'
endfunction

function! timl#dictionary#create(_) abort
  let keyvals = len(a:_) == 1 ? a:_[0] : a:_
  if timl#map#test(keyvals)
    let _ = {'seq': timl#coll#seq(keyvals)}
    let dict = {}
    while _.seq isnot# g:timl#nil
      let _.first = timl#coll#first(_.seq)
      let dict[timl#string#coerce(_.first[0])] = _.first[1]
      let _.seq = timl#coll#next(_.seq)
    endwhile
    return dict
  endif
  let dictionary = {}
  for i in range(0, len(keyvals)-1, 2)
    let dictionary[timl#string#coerce(keyvals[i])] = get(keyvals, i+1, g:timl#nil)
  endfor
  return dictionary
endfunction

function! timl#dictionary#seq(dict) abort
  let items = map(filter(items(a:dict), 'v:val[0][0] !=# "#"'), '[v:val[0], v:val[1]]')
  return empty(items) ? g:timl#nil : timl#array_seq#create(items)
endfunction

function! timl#dictionary#lookup(this, key, ...) abort
  return get(a:this, timl#string#coerce(a:key), a:0 ? a:1 : g:timl#nil)
endfunction

function! timl#dictionary#empty(this) abort
  return {}
endfunction

function! timl#dictionary#conj(this, ...) abort
  let orig = a:this
  let this = copy(a:this)
  let _ = {}
  for _.e in a:000
    let this[timl#string#coerce(timl#coll#first(_.e))] = timl#coll#fnext(_.e)
  endfor
  if islocked('orig')
    lockvar 1 this
  endif
  return this
endfunction

function! timl#dictionary#conjb(this, ...) abort
  let _ = {}
  for _.e in a:000
    let a:this[timl#string#coerce(timl#coll#first(_.e))] = timl#coll#fnext(_.e)
  endfor
  return a:this
endfunction

function! timl#dictionary#assoc(this, ...) abort
  let orig = a:this
  let this = copy(a:this)
  for i in range(0, len(a:000)-2, 2)
    let this[timl#string#coerce(a:000[i])] = a:000[i+1]
  endfor
  if islocked('orig')
    lockvar 1 this
  endif
  return this
endfunction

function! timl#dictionary#assocb(this, ...) abort
  for i in range(0, len(a:000)-2, 2)
    let a:this[timl#string#coerce(a:000[i])] = a:000[i+1]
  endfor
  return a:this
endfunction

function! timl#dictionary#dissoc(this, ...) abort
  let _ = {}
  let orig = a:this
  let this = copy(a:this)
  for _.x in a:000
    let key = timl#string#coerce(_.x)
    if has_key(this, key)
      call remove(this, key)
    endif
  endfor
  if islocked('orig')
    lockvar 1 this
  endif
  return this
endfunction

function! timl#dictionary#dissocb(this, ...) abort
  let _ = {}
  for _.x in a:000
    let key = timl#string#coerce(_.x)
    if has_key(a:this, key)
      call remove(a:this, key)
    endif
  endfor
  return a:this
endfunction

function! timl#dictionary#transient(this) abort
  let this = a:this
  return islocked('this') ? copy(this) : this
endfunction

function! timl#dictionary#persistentb(this) abort
  lockvar 1 a:this
  return a:this
endfunction


================================================
FILE: autoload/timl/equality.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_equality')
  finish
endif
let g:autoloaded_timl_equality = 1

function! timl#equality#test(x, y) abort
  if timl#type#canp(a:x, g:timl#core.equiv)
    return timl#truth(timl#invoke(g:timl#core.equiv, a:x, a:y))
  else
    return type(a:x) ==# type(a:y) && a:x ==# a:y
  endif
endfunction

function! timl#equality#all(_) abort
  let _ = {}
  for _.y in a:_[1:-1]
    if !timl#equality#test(a:_[0], _.y)
      return g:timl#false
    endif
  endfor
  return g:timl#true
endfunction

function! timl#equality#not(_) abort
  return timl#equality#all(a:_) ==# g:timl#false ? g:timl#true : g:timl#false
endfunction

function! timl#equality#identical(_) abort
  let _ = {}
  for _.y in a:_[1:-1]
    if a:_[0] isnot# _.y
      return g:timl#false
    endif
  endfor
  return g:timl#true
endfunction

function! timl#equality#seq(x, y) abort
  if a:x is# a:y
    return g:timl#true
  elseif !timl#coll#sequentialp(a:y)
    return g:timl#false
  endif
  let _ = {'x': timl#coll#seq(a:x), 'y': timl#coll#seq(a:y)}
  while _.x isnot# g:timl#nil && _.y isnot# g:timl#nil
    if !timl#equality#test(timl#coll#first(_.x), timl#coll#first(_.y))
      return g:timl#false
    endif
    let _.x = timl#coll#next(_.x)
    let _.y = timl#coll#next(_.y)
  endwhile
  return _.x is# g:timl#nil && _.y is# g:timl#nil ? g:timl#true : g:timl#false
endfunction


================================================
FILE: autoload/timl/exception.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_exception')
  finish
endif
let g:autoloaded_timl_exception = 1

let s:loctype = timl#type#core_create('Location', ['bufnr', 'filename', 'lnum',
      \ 'pattern', 'col', 'vcol', 'nr', 'text', 'type'])
let s:locproto = timl#type#bless(s:loctype,
      \ {'bufnr': 0, 'filename': '', 'lnum': 0, 'pattern': '', 'col': 0, 'vcol': 0, 'nr': 0, 'text': '', 'type': ''})
function! timl#exception#loclist(throwpoint) abort
  let list = []
  if a:throwpoint !~# '^function '
    call add(list, {"filename": matchstr(a:throwpoint, '^.\{-\}\ze\.\.')})
  endif
  for fn in split(matchstr(a:throwpoint, '\%( \|\.\.\)\zs.\{-\}\ze\%(,\|$\)'), '\.\.')
    call insert(list, copy(s:locproto))
    let list[0].text = fn
    if has_key(g:timl_functions, fn)
      let list[0].filename = g:timl_functions[fn].file
      let list[0].lnum = g:timl_functions[fn].line
    else
      try
        redir => out
        exe 'silent verbose function '.(fn =~# '^\d' ? '{'.fn.'}' : fn)
      catch
      finally
        redir END
      endtry
      if fn !~# '^\d'
        let list[0].filename = expand(matchstr(out, "\n\tLast set from \\zs[^\n]*"))
        let list[0].pattern = '^\s*fu\%[nction]!\=\s*'.substitute(fn,'^<SNR>\d\+_','s:','').'\s*('
      endif
    endif
  endfor
  return list
endfunction

let s:type = timl#type#core_create('Exception')
function! timl#exception#build(exception, throwpoint) abort
  let dict = {"exception": a:exception, "throwpoint": a:throwpoint}
  let dict.line = +matchstr(a:throwpoint, '\d\+$')
  let dict.qflist = timl#exception#loclist(a:throwpoint)
  return timl#type#bless(s:type, dict)
endfunction


================================================
FILE: autoload/timl/false.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists("g:autoloaded_timl_false")
  finish
endif
let g:autoloaded_timl_false = 1

if !exists('g:timl#false')
  let g:timl#false = timl#type#bless(timl#type#core_create('Boolean'), {'val': 0})
  lockvar 1 g:timl#false
endif

function! timl#false#identity() abort
  return g:timl#false
endfunction

function! timl#false#test(val) abort
  return a:val is# g:timl#false
endfunction


================================================
FILE: autoload/timl/file.tim
================================================
(ns timl.file)

(defn slash [] (if (and (exists? "+shellslash") (not &shellslash)) "\\" "/"))

(defn ^{:help "filereadable()"} filereadable? [f] (nonzero? (#*filereadable f)))
(defn filewritable? [f] (nonzero? (#*filewritable f)))
(defn directory? [f] (nonzero? (#*isdirectory f)))
(defn ftype [f]
  (let [type (#*getftype f)] (when (not= "" type) (keyword type))))
(defn file? [f] (= "file" (#*getftype f)))
(defn mtime [f] (let [time (#*getftime f)] (when (not= -1 time) (inst time))))
(defn fsize [f] (not-negative (#*getfsize f)))
(defn expand [f] (#*expand f))
(defn delete [f] (zero? (#*delete f)))
(defn rename [from to] (zero? (#*rename from to)))

(defn absolute [f] (#*fnamemodify f ":p"))
(defn relative [f] (#*fnamemodify f ":."))
(defn basename [f] (#*fnamemodify f ":t"))
(defn dirname [f] (#*fnamemodify f ":h"))
(defn shortname [f] (#*fnamemodify f ":~:."))
(defn extname [f] (#*fnamemodify f ":e"))
(defn rootname [f] (#*fnamemodify f ":r"))

(defn join-path [path]
  (if (string? path)
    path
    (join "," (map #(#*escape % ",") path))))
(defn glob [pat]
  (binding [&suffixes ""
            &wildignore ""]
    (split (#*glob pat) "\n")))
(defn glob-path [path pat]
  (binding [&suffixes ""
            &wildignore ""]
    (split (#*globpath (join-path path) pat) "\n")))
; TODO: findfile, finddir

(defn help-topics [pattern]
  (binding [&tags (#*escape (join-path (map #(str % "/doc/tags") (split &runtimepath ","))) " ")]
    (#*taglist pattern)))


================================================
FILE: autoload/timl/ftplugin.tim
================================================
(ns timl.ftplugin)
(require '[timl.plugin-helper :as ph])

(defmacro include-guard [& default]
  (let [param (or (first default) 'b:did-ftplugin)]
   `(ph/include-guard ~param)))

; should append to b:undo-ftplugin
(defmacro setlocal [& opts]
  `(do
     (execute (str "setlocal " ~(ph/build-option-string opts)))
     (set! b:undo-ftplugin ~(ph/extract-option-restore opts))))


================================================
FILE: autoload/timl/funcref.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_funcref")
  finish
endif
let g:autoloaded_timl_funcref = 1

function! timl#funcref#call(this, _) abort
  return call(a:this, a:_)
endfunction

let s:type = type(function('tr'))
function! timl#funcref#test(this) abort
  return type(a:this) == s:type
endfunction

function! timl#funcref#string(this) abort
  return join([a:this])
endfunction

function! timl#funcref#hash(this) abort
  return timl#hash#string(string(a:this))
endfunction

function! timl#funcref#exists(name) abort
  return exists(a:name =~# '^\d\+$' ? '*{'.a:name.'}' : '*'.a:name)
endfunction

function! timl#funcref#anonymous() abort
  let d = {}
  function! d.f() abort
    return +matchstr(expand('<sfile>'), '\d\+$')
  endfunction
  return d.f
endfunction


================================================
FILE: autoload/timl/function.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_function')
  finish
endif
let g:autoloaded_timl_function = 1

let s:type = timl#type#core_create('Function')

function! timl#function#unimplemented(...) abort
  throw 'timl: unimplemented'
endfunction

function! timl#function#birth(locals, ...) abort
  return timl#type#bless(s:type, {
        \ 'ns': g:timl#core._STAR_ns_STAR_,
        \ 'name': a:0 ? a:1 : g:timl#nil,
        \ 'locals': a:locals,
        \ '__call__': function('timl#function#unimplemented')})
endfunction

function! timl#function#call(this, _) abort
  return a:this.__call__(a:_)
endfunction

function! timl#function#apply(_) abort
  if len(a:_) < 2
    throw 'timl: arity error'
  endif
  let [F; args] = a:_
  let args = args[0:-2] + timl#array#coerce(args[-1])
  return timl#call(F, args)
endfunction

function! timl#function#identity(x) abort
  return a:x
endfunction

function! timl#function#invoke_self(...) dict abort
  return self.__call__(a:000)
endfunction

function! timl#function#hash(fn) abort
  return timl#hash#string(string(a:fn.__call__))
endfunction

let s:def = timl#symbol('def')
let s:let = timl#symbol('timl.core/let')
let s:fns = timl#symbol('fn*')
let s:fn = timl#symbol('timl.core/fn')
let s:defn = timl#symbol('timl.core/defn')
let s:setq = timl#symbol('set!')
let s:dot = timl#symbol('.')
let s:form = timl#symbol('&form')
let s:env = timl#symbol('&env')

function! timl#function#destructure(params, body) abort
  let lets = []
  let params = []
  let _ = {}
  for _.param in timl#array#coerce(a:params)
    if timl#symbol#test(_.param)
      call add(params, _.param)
    else
      call add(params, timl#symbol#gen("p__"))
      call extend(lets, [_.param, params[-1]])
    endif
  endfor
  if empty(lets)
    return timl#cons#create(timl#vector#claim(params), a:body)
  else
    return timl#list(timl#vector#claim(params), timl#cons#create(s:let, timl#cons#create(timl#vector#claim(lets), a:body)))
  endif
endfunction

function! timl#function#fn(form, env, ...) abort
  let _ = {}
  let _.sigs = timl#list#create(a:000)
  if timl#symbol#test(a:000[0])
    let name = a:000[0]
    let _.sigs = timl#coll#next(_.sigs)
  endif
  if timl#vector#test(timl#coll#first(_.sigs))
    let _.sigs = timl#function#destructure(timl#coll#first(_.sigs), timl#coll#next(_.sigs))
  else
    let sigs = []
    while _.sigs isnot# g:timl#nil
      call add(sigs, timl#function#destructure(timl#coll#ffirst(_.sigs), timl#coll#nfirst(_.sigs)))
      let _.sigs = timl#coll#next(_.sigs)
    endwhile
    let _.sigs = timl#list#create(sigs)
  endif
  if exists('name')
    let _.sigs = timl#cons#create(name, _.sigs)
  endif
  return timl#cons#create(s:fns, _.sigs, timl#meta#get(a:form))
endfunction

function! timl#function#defn(form, env, name, ...) abort
  return timl#list#create([s:def, a:name, timl#meta#with(timl#list#create([s:fn, a:name] + a:000), timl#meta#get(a:form))])
endfunction

let s:kmacro = timl#keyword#intern('macro')
function! timl#function#defmacro(form, env, name, params, ...) abort
  let extra = [s:form, s:env]
  if timl#vector#test(a:params)
    let body = [timl#vector#claim(extra + timl#array#coerce(a:params))] + a:000
  else
    let _ = {}
    let body = []
    for _.list in [a:params] + a:000
      call add(body, timl#cons#create(timl#vector#claim(extra + timl#array#coerce(timl#coll#first(_.list))), timl#coll#next(_.list)))
    endfor
  endif
  let name = copy(a:name)
  let name.meta = timl#invoke(g:timl#core.assoc, get(a:name, 'meta', g:timl#nil), s:kmacro, g:timl#true)
  let fn = timl#symbol#gen('fn')
  return timl#list#create([s:defn, name] + body)
endfunction


================================================
FILE: autoload/timl/future.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_future")
  finish
endif
let g:autoloaded_timl_future = 1

if !exists('s:queue')
  let s:queue = []
endif

function! timl#future#call(fn) abort
  let future = s:type.__call__([a:fn, g:timl#nil, g:timl#nil])
  call add(s:queue, future)
  return future
endfunction

function! timl#future#realize(this) abort
  if a:this.fn isnot# g:timl#nil
    try
      let a:this.val = timl#call(a:this.fn, [])
    catch /^\%(Vim:Interrupt\)\@!.*/
      let a:this.exception = timl#exception#build(v:exception, v:throwpoint)
    endtry
    let a:this.fn = g:timl#nil
  endif
  return a:this
endfunction

function! timl#future#deref(this) abort
  if a:this.fn isnot# g:timl#nil
    call timl#future#realize(a:this)
  endif
  if a:this.exception is# g:timl#nil
    return a:this.val
  endif
  throw substitute(a:this.exception.exception, '^Vim', 'Tim', '')
endfunction

function! timl#future#realized(this) abort
  return a:this.fn is# g:timl#nil ? g:timl#true : g:timl#false
endfunction

function! timl#future#process() abort
  while !empty(s:queue) && !getchar(1)
    call timl#future#realize(remove(s:queue, 0))
  endwhile
endfunction

let s:type = timl#type#core_define('Future', ['fn', 'val', 'exception'], {
      \ 'realized?': 'timl#future#realized',
      \ 'deref': 'timl#future#deref'})

augroup timl_future
  autocmd!
  autocmd CursorHold * call timl#future#process()
augroup END


================================================
FILE: autoload/timl/hash.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_hash')
  finish
endif
let g:autoloaded_timl_hash = 1

function! timl#hash#compute(obj) abort
  if type(a:obj) == type('')
    let hash = timl#hash#string(a:obj)
  elseif type(a:obj) == type(0)
    let hash = a:obj
  elseif timl#type#canp(a:obj, g:timl#core.hash)
    let hash = timl#invoke(g:timl#core.hash, a:obj)
  elseif timl#type#canp(a:obj, g:timl#core.seq)
    let hash = timl#hash#sequential(a:obj)
  else
    let hash = timl#invoke(g:timl#core.hash, a:obj)
  endif
  if exists('hash')
    let hash = hash % 0x40000000
    if hash < 0
      let hash += 0x40000000
    endif
    return hash
  endif
endfunction

function! timl#hash#string(str) abort
  let r = 0
  let l = len(a:str)
  let i = 0
  while i < l
    let r = 31 * r + char2nr(a:str[i])
    let i += 1
  endwhile
  return r
endfunction

function! timl#hash#str_attribute(obj) abort
  return timl#hash#string(a:obj.str)
endfunction

function! timl#hash#sequential(s) abort
  let r = 0
  let _ = {'seq': timl#coll#seq(a:s)}
  while _.seq isnot# g:timl#nil
    let r += timl#hash#compute(timl#coll#first(a:s))
    let _.seq = timl#coll#next(_.seq)
  endwhile
  return r
endfunction

let s:idx = '0123456789abcdefghijklmnopqrstuv'
function! s:idx_for(hash, level) abort
  return s:idx[(a:hash/a:level) % 32]
endfunction

function! timl#hash#find(node, key) abort
  let hash = timl#hash#compute(a:key)
  let level = 1
  let node = a:node
  let idx = s:idx_for(hash, level)
  while has_key(node, idx)
    if type(node[idx]) == type([])
      for pair in node[idx]
        if timl#equality#test(a:key, pair[0])
          return pair
        endif
      endfor
      return g:timl#nil
    endif
    let level = level * 32
    let node = node[idx]
    let idx = s:idx_for(hash, level)
  endwhile
  return g:timl#nil
endfunction

function! timl#hash#items(node) abort
  let _ = {}
  let array = []
  for [k, _.v] in items(a:node)
    if type(_.v) == type([])
      call extend(array, _.v)
    else
      call extend(array, timl#hash#items(_.v))
    endif
  endfor
  return array
endfunction

function! timl#hash#assoc(node, key, val) abort
  let hash = timl#hash#compute(a:key)
  return s:assoc(a:node, hash, a:key, a:val, 1)
endfunction

function! s:assoc(node, hash, key, val, level) abort
  let idx = s:idx_for(a:hash, a:level)
  if !has_key(a:node, idx)
    return [extend({idx : [[a:key, a:val]]}, a:node), 1]
  elseif type(a:node[idx]) == type([])
    let hash2 = timl#hash#compute(a:node[idx][0][0])
    if hash2 == a:hash
      for i in range(len(a:node[idx]))
        if timl#equality#test(a:key, a:node[idx][i][0])
          if a:node[idx][i][1] is# a:val
            return [a:node, 0]
          endif
          let node = extend({idx : copy(a:node[idx])}, a:node, 'keep')
          let node[idx][i] = [a:key, a:val]
          return [node, 0]
        endif
      endfor
      let node = copy(a:node)
      let node[idx] += [[a:key, a:val]]
      return [node, 1]
    else
      let node = extend({idx : {}}, a:node, 'keep')
      for old in a:node[idx]
        let [node, _] = s:assoc(node, hash2, old[0], old[1], a:level)
      endfor
      return s:assoc(node, a:hash, a:key, a:val, a:level)
    endif
  else
    let [node, c] = s:assoc(a:node[idx], a:hash, a:key, a:val, a:level * 32)
    if a:node[idx] is# node
      return [a:node, c]
    else
      return [extend({idx : node}, a:node, 'keep'), c]
    endif
  endif
endfunction

function! timl#hash#dissoc(node, key) abort
  let hash = timl#hash#compute(a:key)
  return s:dissoc(a:node, hash, a:key, 1)
endfunction

function! s:dissoc(node, hash, key, level) abort
  let idx = s:idx_for(a:hash, a:level)
  if !has_key(a:node, idx)
    return [a:node, 0]
  elseif type(a:node[idx]) == type([])
    let hash2 = timl#hash#compute(a:node[idx][0][0])
    if hash2 == a:hash
      for i in range(len(a:node[idx]))
        if timl#equality#test(a:key, a:node[idx][i][0])
          let node = extend({idx : copy(a:node[idx])}, a:node, 'keep')
          call remove(node[idx], i)
          return [node, 1]
        endif
      endfor
    endif
    return [a:node, 0]
  else
    let [node, c] = s:dissoc(a:node[idx], a:hash, a:key, a:level * 32)
    if node is# a:node[idx]
      return [a:node, c]
    elseif empty(node)
      let node2 = copy(node)
      call remove(node2, idx)
      return [node2, c]
    else
      return [extend({idx : node}, a:node, 'keep'), c]
    endif
  endif
endfunction


================================================
FILE: autoload/timl/indent.tim
================================================
(ns timl.indent)
(require '[timl.plugin-helper :as ph])

(defmacro include-guard [& default]
  (let [param (or (first default) 'b:did-indent)]
   `(ph/include-guard ~param)))

(defmacro setlocal [& opts]
  `(do
     (execute (str "setlocal " ~(ph/build-option-string opts)))
     (set! b:undo-indent ~(ph/extract-option-restore opts))))


================================================
FILE: autoload/timl/inst.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_inst')
  finish
endif
let g:autoloaded_timl_inst = 1

function! timl#inst#sleep(msec) abort
  execute 'sleep' a:msec.'m'
  return g:timl#nil
endfunction

function! timl#inst#create(...) abort
  if !a:0
    return timl#inst#now()
  elseif type(a:1) == type('')
    return timl#inst#parse(a:1)
  elseif type(a:1) == type(0)
    return timl#inst#from_ts(a:1)
  elseif type(a:1) == 5
    return timl#inst#from_ts(float2nr(a:1), float2nr(1000000*abs(a:1-trunc(a:1))))
  elseif type(a:1) == type({}) && get(a:1, '__type__') == s:type
    return a:1
  endif
  throw "timl: can't create Instant from ".timl#type#string(a:1)
endfunction

" In Vim, -4 / 3 == -1.  Let's return -2 instead.
function! s:div(a,b) abort
  if a:a < 0 && a:b > 0
    return (a:a-a:b+1)/a:b
  elseif a:a > 0 && a:b < 0
    return (a:a-a:b-1)/a:b
  else
    return a:a / a:b
  endif
endfunction

function! timl#inst#jd(year, mon, day) abort
  let y = a:year + 4800 - (a:mon <= 2)
  let m = a:mon + (a:mon <= 2 ? 9 : -3)
  let jul = a:day + (153*m+2)/5 + s:div(1461*y,4) - 32083
  return jul - s:div(y,100) + s:div(y,400) + 38
endfunction

let s:jdepoch = timl#inst#jd(1970, 1, 1)
function! timl#inst#ts(year, mon, day, hour, min, sec) abort
  return (timl#inst#jd(a:year, a:mon, a:day) - s:jdepoch) * 86400 + a:hour * 3600 + a:min * 60 + a:sec
endfunction

function! timl#inst#parse(str) abort
  let str = timl#string#coerce(a:str)
  let results = matchlist(str, '\c\v(\d{4})-(\d\d)-(\d\d)t(\d\d):(\d\d):(\d\d)%(\.(\d+))=%(z|([+-]\d\d):(\d\d))$')
  if !empty(results)
    call remove(results, 0)
    let results[6] = results[6][0:5] . repeat('0', 6-len(results[6]))
    call map(results, 'str2nr(v:val)')
    let t = {}
    let [t.year, t.mon, t.day, t.hour, t.min, t.sec, t.usec] = results[0:6]
    let t.offset = results[7] * 60 + results[8]
    let t.unix = timl#inst#ts(t.year, t.mon, t.day, t.hour, t.min-t.offset, t.sec)
    return timl#type#bless(s:type, t)
  endif
  throw "timl: invalid date string ".str
endfunction

function! timl#inst#from_ts(sec, ...) abort
  let t = {'unix': a:sec, 'usec': a:0 ? a:1 : 0}
  let components = map(split(strftime("%Y %m %d %H %M %S", t.unix), ' '), 'str2nr(v:val)')
  let t.offset = (call('timl#inst#ts', components) - t.unix)/60
  let [t.year, t.mon, t.day, t.hour, t.min, t.sec] = components
  return timl#type#bless(s:type, t)
endfunction

function! timl#inst#now() abort
  if has('unix')
    return call('timl#inst#from_ts', reltime())
  elseif has('ruby')
    ruby VIM.command('return timl#inst#from_ts(%s, str2nr("%s"[0:5]))' % Time.now.to_f.to_s.split('.'))
  else
    return timl#inst#from_ts(localtime())
  endif
endfunction

function! timl#inst#to_string(t) abort
  let min_offset = a:t.offset % 60
  return printf('%04d-%02d-%02dT%02d:%02d:%02d.%06d%+03d:%02d', a:t.year, a:t.mon, a:t.day, a:t.hour, a:t.min, a:t.sec, a:t.usec, a:t.offset/60, (a:t.offset < 0 ? -1 : 1) * a:t.offset % 60)
endfunction

let s:type = timl#type#core_define('Instant', ['year', 'mon', 'day', 'hour', 'min', 'sec', 'offset', 'unix'], {
      \ 'to-string': 'timl#inst#to_string'})


================================================
FILE: autoload/timl/interactive.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_interactive')
  finish
endif
let g:autoloaded_timl_interactive = 1

function! s:function(name) abort
  return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '.*\zs<SNR>\d\+_'),''))
endfunction

function! s:lencompare(a, b) abort
  return len(a:a) - len(a:b)
endfunction

function! timl#interactive#ns_for_file(file) abort
  let file = fnamemodify(a:file, ':p')
  let candidates = []
  for glob in split(&runtimepath, ',')
    let candidates += filter(split(glob(glob), "\n"), 'file[0 : len(v:val)-1] ==# v:val && file[len(v:val)] =~# "[\\/]"')
  endfor
  if empty(candidates)
    return 'user'
  endif
  let dir = sort(candidates, s:function('s:lencompare'))[-1]
  let path = file[len(dir)+1 : -1]
  return substitute(tr(fnamemodify(path, ':r:r'), '\/_', '..-'), '^\%(autoload\|plugin\|test\).', '', '')
endfunction

function! timl#interactive#ns_for_cursor(...) abort
  call timl#loader#init()
  let pattern = '\c(\%(in-\)\=ns\s\+''\=[[:alpha:]]\@='
  let line = 0
  if !a:0 || a:1
    let line = search(pattern, 'bcnW')
  endif
  if !line
    let i = 1
    while i < line('$') && i < 100
      if getline(i) =~# pattern
        let line = i
        break
      endif
      let i += 1
    endwhile
  endif
  if line
    let ns = matchstr(getline(line), pattern.'\zs[[:alnum:]._-]\+')
  else
    let ns = timl#interactive#ns_for_file(expand('%:p'))
  endif
  let nsobj = timl#namespace#find(timl#symbol#intern(ns))
  if nsobj isnot# g:timl#nil
    return ns
  else
    return 'user'
  endif
endfunction

let s:skip = "comment\\|string\\|regex\\|character"
function! s:beginning_of_sexp() abort
  let open = '[[{(]'
  let close = '[]})]'
  let skip = 'synIDattr(synID(line("."),col("."),1),"name") =~? s:skip'
  let pos = searchpairpos(open, '', close, 'bn', skip)
  if pos[0]
    if pos[1] > 2 && getline(pos[0])[pos[1]-3 : pos[1]-2] ==# '#*'
      let pos[1] -= 2
    endif
    while pos[1] > 1 && getline(pos[0])[pos[1]-2] =~# '[#''`~@]'
      let pos[1] -= 1
    endwhile
    return [0] + pos + [0]
  else
    return [0, line('.'), 1, 0]
  endif
endfunction

function! timl#interactive#eval_opfunc(type) abort
  let selection = &selection
  let clipboard = &clipboard
  let reg = @@
  try
    set selection=inclusive clipboard=
    if a:type =~# '^\d\+$'
      let open = '[[{(]'
      let close = '[]})]'
      let skip = 'synIDattr(synID(line("."),col("."),1),"name") =~? s:skip'
      if searchpair(open, '', close, 'rc', skip)
        call setpos("']", getpos("."))
        call setpos("'[", s:beginning_of_sexp())
      else
        call setpos("'[", [0, line("."), 1, 0])
        call setpos("']", [0, line("."), col("$"), 0])
      endif
      silent exe "normal! `[v`]y"
    elseif a:type =~# "[vV\C-V]"
      silent exe "normal! `<" . a:type . "`>y"
    elseif a:type ==# 'line'
      silent exe "normal! '[V']y"
    elseif a:type ==# 'block'
      silent exe "normal! `[\<C-V>`]y"
    elseif a:type ==# 'char'
      silent exe "normal! `[v`]y"
    else
      return
    endif
    let string = repeat("\n", line("'[")-1) . repeat(" ", col("'[")-1) . @@
  finally
    let &selection = selection
    let &clipboard = clipboard
    let @@ = reg
  endtry
  let ns = g:timl#core._STAR_ns_STAR_
  let port = timl#reader#open_string(string, expand('%:p'))
  try
    let g:timl#core._STAR_ns_STAR_ = timl#namespace#find(timl#symbol#intern(timl#interactive#ns_for_cursor()))
    echo timl#printer#string(timl#loader#consume(port))
    let &syntax = &syntax
  catch //
    echohl ErrorMsg
    echo v:exception
    echohl NONE
    unlet! g:timl#core._STAR_e
    let g:timl#core._STAR_e = timl#exception#build(v:exception, v:throwpoint)
  finally
    call timl#reader#close(port)
    let g:timl#core._STAR_ns_STAR_ = ns
  endtry
endfunction

function! timl#interactive#return() abort
  if !empty(getline('.')[col('.')]) || synIDattr(synID(line('.'), col('.')-1, 1), 'name') =~? s:skip || getline('.') =~# '^\s*\%(;.*\)\=$'
    return "\<CR>"
  endif
  let beg = s:beginning_of_sexp()
  let end = getpos(".")
  if beg[1] == end[1]
    let string = getline(beg[1])[beg[2]-1 : end[2]-1]
  else
    let string = getline(beg[1])[beg[2]-1 : -1] . "\n"
          \ . join(map(getline(beg[1]+1, end[1]-1), 'v:val . "\n"'))
          \ . getline(end[1])[0 : end[2]-1]
  endif
  let string = repeat("\n", beg[1]-1) . repeat(" ", beg[2]-1) . string
  let ns = g:timl#core._STAR_ns_STAR_
  let port = timl#reader#open_string(string, expand('%:p'))
  try
    let g:timl#core._STAR_ns_STAR_ = timl#namespace#find(timl#symbol#intern(timl#interactive#ns_for_cursor()))
    let body = ";= " . timl#printer#string(timl#loader#consume(port))
    call setloclist(0, [])
    let &syntax = &syntax
  catch //
    unlet! g:timl#core._STAR_e
    let g:timl#core._STAR_e = timl#exception#build(v:exception, v:throwpoint)
    call setloclist(0, g:timl#core._STAR_e.qflist)
    let body = ";! " . timl#printer#string(g:timl#core._STAR_e)
  finally
    call timl#reader#close(port)
    let g:timl#core._STAR_ns_STAR_ = ns
  endtry
  if len(substitute(body.getline('.'), '.', '.', 'g')) < 80
    return " ".body."\<CR>"
  else
    return "\<CR>".body."\<CR>"
  endif
endfunction

function! timl#interactive#omnicomplete(findstart, base) abort
  if a:findstart
    let line = getline('.')[0 : col('.')-2]
    return col('.') - strlen(matchstr(line, '\k\+$')) - 1
  endif
  let results = []
  let ns = timl#interactive#ns_for_cursor()
  if timl#namespace#find(ns) is g:timl#nil
    let ns = 'user'
  endif
  let results = map(keys(timl#namespace#map(timl#namespace#find(ns))), '{"word": v:val}')
  return filter(results, 'v:val.word[0] !=# "#" && (a:base ==# "" || a:base ==# v:val.word[0 : strlen(a:base)-1])')
endfunction

function! timl#interactive#input_complete(A, L, P) abort
  let prefix = matchstr(a:A, '\%(.* \|^\)\%(#\=[\[{('']\)*')
  let keyword = a:A[strlen(prefix) : -1]
  return sort(map(timl#interactive#omnicomplete(0, keyword), 'prefix . v:val.word'))
endfunction

function! timl#interactive#repl(...) abort
  if a:0
    let ns = g:timl#core._STAR_ns_STAR_
    try
      let g:timl#core._STAR_ns_STAR_ = timl#namespace#create(timl#symbol#intern(a:1))
      call timl#loader#require(timl#symbol#intern('timl.repl'))
      call timl#namespace#refer(timl#symbol#intern('timl.repl'))
      return timl#interactive#repl()
    finally
      let g:timl#core._STAR_ns_STAR_ = ns
    endtry
  endif

  let cmpl = 'customlist,timl#interactive#input_complete'
  let more = &more
  try
    set nomore
    call timl#loader#require(timl#symbol#intern('timl.repl'))
    if timl#namespace#name(g:timl#core._STAR_ns_STAR_).str ==# 'user'
      call timl#namespace#refer(timl#symbol#intern('timl.repl'))
    endif
    let input = input(timl#namespace#name(g:timl#core._STAR_ns_STAR_).str.'=> ', '', cmpl)
    if input =~# '^:q\%[uit]'
      return ''
    elseif input =~# '^:'
      return input
    endif
    let _ = {}
    while !empty(input)
      echo "\n"
      try
        while 1
          try
            let read = timl#reader#read_string_all(input)
            break
          catch /^timl#reader: unexpected EOF/
            let space = repeat(' ', len(timl#namespace#name(g:timl#core._STAR_ns_STAR_).str)-2)
            let input .= "\n" . input(space.'#_=> ', '', cmpl)
            echo "\n"
          endtry
        endwhile
        let _.val = timl#loader#eval(timl#cons#create(timl#symbol#intern('do'), read))
        call extend(g:, {
              \ 'timl#core#_STAR_3': g:timl#core._STAR_2,
              \ 'timl#core#_STAR_2': g:timl#core._STAR_1,
              \ 'timl#core#_STAR_1': _.val})
        echo timl#printer#string(_.val)
      catch /^timl#repl: exit/
        redraw
        return v:exception[16:-1]
      catch /^Vim\%((\a\+)\)\=:E168/
        return ''
      catch
        unlet! g:timl#core._STAR_e
        let g:timl#core._STAR_e = timl#exception#build(v:exception, v:throwpoint)
        echohl ErrorMSG
        echo v:exception
        echohl NONE
      endtry
      let input = input(timl#namespace#name(g:timl#core._STAR_ns_STAR_).str.'=> ', '', cmpl)
    endwhile
    return input
  finally
    let &more = more
  endtry
endfunction

function! timl#interactive#scratch() abort
  if exists('s:scratch') && bufnr(s:scratch) !=# -1
    execute bufnr(s:scratch) . 'sbuffer'
    return ''
  elseif !exists('s:scratch')
    let s:scratch = tempname().'.tim'
    execute 'silent' (empty(bufname('')) && !&modified ? 'edit' : 'split') s:scratch
  else
    execute 'split '.s:scratch
  endif
  call setline(1, [
        \ ";; This buffer is for notes you don't want to save, and for TimL evaluation.",
        \ ";; Use cpp to evaluate the top level form under the cursor,",
        \ ";; or cp{motion} to evaluate an arbitrary selection.",
        \ ""])
  setlocal bufhidden=hide filetype=timl nomodified
  let &l:statusline = '#<Namespace %{timl#interactive#ns_for_cursor()}>%='.get(split(&statusline, '%='), 1, '')
  autocmd BufLeave <buffer> update
  inoremap <buffer><silent> <CR> <C-r>=timl#interactive#return()<CR>
  return '$'
endfunction

function! timl#interactive#copen(error) abort
  if !empty(a:error)
    call setqflist(a:error.qflist)
    copen
    let w:quickfix_title = a:error.exception . " @ line " . a:error.line
  endif
endfunction


================================================
FILE: autoload/timl/io.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_io")
  finish
endif
let g:autoloaded_timl_io = 1

function! timl#io#echon(_) abort
  echon join(map(copy(a:_), 'timl#string#coerce(v:val)'), ' ')
  return g:timl#nil
endfunction

function! timl#io#echo(_) abort
  echo join(map(copy(a:_), 'timl#string#coerce(v:val)'), ' ')
  return g:timl#nil
endfunction

function! timl#io#echomsg(_) abort
  echomsg join(map(copy(a:_), 'timl#string#coerce(v:val)'), ' ')
  return g:timl#nil
endfunction

function! timl#io#println(_) abort
  echon join(map(copy(a:_), 'timl#string#coerce(v:val)'), ' ')."\n"
  return g:timl#nil
endfunction

function! timl#io#newline() abort
  echon "\n"
  return g:timl#nil
endfunction

function! timl#io#printf(fmt, ...) abort
  echon call('printf', [timl#string#coerce(a:fmt)] + a:000)."\n"
  return g:timl#nil
endfunction

function! timl#io#pr(_) abort
  echon join(map(copy(a:_), 'timl#printer#string(v:val)'), ' ')
  return g:timl#nil
endfunction

function! timl#io#prn(_) abort
  echon join(map(copy(a:_), 'timl#printer#string(v:val)'), ' ')."\n"
  return g:timl#nil
endfunction

function! timl#io#spit(filename, body) abort
  if type(body) == type([])
    call writefile(body, a:filename)
  else
    call writefile(split(body, "\n"), a:filename, 'b')
endfunction

function! timl#io#slurp(filename) abort
  return join(readfile(a:filename, 'b'), "\n")
endfunction


================================================
FILE: autoload/timl/keyword.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_keyword")
  finish
endif
let g:autoloaded_timl_keyword = 1

if !exists('s:keywords')
  let s:keywords = {}
endif

function! timl#keyword#intern(str) abort
  if !has_key(s:keywords, a:str)
    let end = matchend(a:str, '^\%(&\=\w:\|\$\|&\%($\|form$\|env$\)\@!\|[^/]*/\).\@=')
    let keyword = timl#type#bless(s:type, {
          \ '0': a:str,
          \ 'str': a:str,
          \ 'namespace': end == -1 ? '' : a:str[0 : end-(a:str[end-1] ==# '/' ? 2 : 1)],
          \ 'name': end == -1 ? a:str : a:str[end : -1]})
    lockvar 1 keyword
    let s:keywords[a:str] = keyword
  endif
  return s:keywords[a:str]
endfunction

function! timl#keyword#test(keyword) abort
  return type(a:keyword) == type({}) && get(a:keyword, '__type__') is# s:type
endfunction

function! timl#keyword#cast(keyword) abort
  if timl#keyword#test(a:keyword)
    return a:keyword
  endif
  throw 'timl: keyword expected but received '.timl#type#string(a:keyword)
endfunction

function! timl#keyword#to_string(this) abort
  return a:this.str
endfunction

function! timl#keyword#name(this) abort
  return a:this.name
endfunction

function! timl#keyword#namespace(this) abort
  return a:this.namespace
endfunction

function! timl#keyword#call(this, _) abort
  if len(a:_) < 1 || len(a:_) > 2
    throw 'timl: arity error'
  endif
  return call('timl#coll#get', [a:_[0], a:this] + a:_[1:-1])
endfunction

let s:type = timl#type#core_create('Keyword')


================================================
FILE: autoload/timl/lazy_seq.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_lazy_seq")
  finish
endif
let g:autoloaded_timl_lazy_seq = 1

let s:placeholder = {}
function! timl#lazy_seq#create(fn) abort
  return timl#type#bless(s:type, {'fn': a:fn, 'val': g:timl#nil, 'seq': s:placeholder, 'meta': g:timl#nil})
endfunction

function! timl#lazy_seq#with_meta(this, meta) abort
  return timl#type#bless(s:type, {'fn': g:timl#nil, 'val': s:val(a:this), 'seq': a:this.seq, 'meta': a:meta})
endfunction

function! s:val(lseq) abort
  if a:lseq.fn isnot# g:timl#nil
    let a:lseq.val = timl#call(a:lseq.fn, [])
    let a:lseq.fn = g:timl#nil
  endif
  return a:lseq.val
endfunction

function! timl#lazy_seq#seq(lseq) abort
  if a:lseq.seq is# s:placeholder
    let _ = {'seq': a:lseq}
    let i = 0
    while timl#type#string(_.seq) ==# s:type.str
      let i += 1
      let _.seq = s:val(_.seq)
    endwhile
    let a:lseq.seq = timl#invoke(g:timl#core.seq, _.seq)
  endif
  return a:lseq.seq
endfunction

function! timl#lazy_seq#car(lseq) abort
  return timl#coll#first(timl#lazy_seq#seq(a:lseq))
endfunction

function! timl#lazy_seq#cdr(lseq) abort
  return timl#coll#rest(timl#lazy_seq#seq(a:lseq))
endfunction

function! timl#lazy_seq#realized(lseq) abort
  return a:lseq.fn is# g:timl#nil ? g:timl#true : g:timl#false
endfunction

let s:type = timl#type#core_define('LazySeq', ['fn', 'val', 'seq', 'meta'], {
      \ 'get-meta': 'timl#meta#from_attribute',
      \ 'with-meta': 'timl#lazy_seq#with_meta',
      \ 'seq': 'timl#lazy_seq#seq',
      \ 'car': 'timl#lazy_seq#car',
      \ 'cdr': 'timl#lazy_seq#cdr',
      \ 'equiv': 'timl#equality#seq',
      \ 'realized?': 'timl#lazy_seq#realized',
      \ 'conj': 'timl#cons#conj',
      \ 'empty': 'timl#list#empty'})


================================================
FILE: autoload/timl/list.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_list")
  finish
endif
let g:autoloaded_timl_list = 1

let s:cons_type = timl#type#core_create('Cons', ['car', 'cdr', 'meta'])

function! timl#list#create(array, ...) abort
  if a:0 && empty(a:array)
    return timl#type#bless(s:empty_type, {'meta': a:1})
  endif
  let _ = {'cdr': s:empty}
  for i in range(len(a:array)-1, 0, -1)
    let _.cdr = timl#cons#create(a:array[i], _.cdr)
  endfor
  if a:0
    let _.cdr.meta = a:1
  endif
  return _.cdr
endfunction

function! timl#list#with_meta(this, meta) abort
  if a:this.meta is# a:meta
    return a:this
  endif
  let this = copy(a:this)
  let this.meta = a:meta
  lockvar 1 this
  return this
endfunction

function! timl#list#empty() abort
  return s:empty
endfunction

function! timl#list#emptyp(obj) abort
  return type(a:obj) == type({}) && get(a:obj, '__type__') is# s:empty_type
endfunction

function! timl#list#test(obj) abort
  return type(a:obj) == type({}) && (get(a:obj, '__type__') is# s:cons_type || get(a:obj, '__type__') is# s:empty_type)
endfunction

let s:empty_type = timl#type#core_define('EmptyList', ['meta'], {
      \ 'get-meta': 'timl#meta#from_attribute',
      \ 'with-meta': 'timl#list#with_meta',
      \ 'seq': 'timl#nil#identity',
      \ 'equiv': 'timl#equality#seq',
      \ 'car': 'timl#nil#identity',
      \ 'cdr': 'timl#function#identity',
      \ 'length': 'timl#nil#length',
      \ 'conj': 'timl#cons#conj',
      \ 'empty': 'timl#function#identity'})

if !exists('s:empty')
  let s:empty = timl#type#bless(s:empty_type, {'meta': g:timl#nil})
  lockvar 1 s:empty
endif


================================================
FILE: autoload/timl/loader.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_loader')
  finish
endif
let g:autoloaded_timl_loader = 1

function! timl#loader#eval(x) abort
  return timl#compiler#build(a:x).call()
endfunction

function! timl#loader#consume(port) abort
  let _ = {'result': g:timl#nil}
  let eof = []
  let _.read = timl#reader#read(a:port, eof)
  while _.read isnot# eof
    let _.result = timl#compiler#build(_.read, get(a:port, 'filename', 'NO_SOURCE_PATH')).call()
    let _.read = timl#reader#read(a:port, eof)
  endwhile
  return _.result
endfunction

let s:dir = (has('win32') ? '$APPCACHE/Vim' :
      \ match(system('uname'), "Darwin") > -1 ? '~/Library/Vim' :
      \ empty($XDG_CACHE_HOME) ? '~/.cache/vim' : '$XDG_CACHE_HOME/vim').'/timl'

function! s:cache_filename(path) abort
  let base = expand(s:dir)
  if !isdirectory(base)
    call mkdir(base, 'p')
  endif
  let filename = tr(substitute(fnamemodify(a:path, ':~'), '^\~.', '', ''), '\/:', '%%%') . '.vim'
  return base . '/' . filename
endfunction

let s:myftime = getftime(expand('<sfile>'))

if !exists('g:timl_functions')
  let g:timl_functions = {}
endif

function! timl#loader#source(filename) abort
  let path = fnamemodify(a:filename, ':p')
  let old_ns = g:timl#core._STAR_ns_STAR_
  let cache = s:cache_filename(path)
  try
    let g:timl#core._STAR_ns_STAR_ = timl#namespace#find(timl#symbol#intern('user'))
    let ftime = getftime(cache)
    if !exists('$TIML_EXPIRE_CACHE') && ftime > getftime(path) && ftime > s:myftime
      try
        execute 'source '.fnameescape(cache)
      catch
        let error = v:exception
      endtry
      if !exists('error')
        return
      endif
    endif
    let file = timl#reader#open(path)
    let strs = ["let s:d = {}"]
    let _ = {}
    let _.read = g:timl#nil
    let eof = []
    while _.read isnot# eof
      let _.read = timl#reader#read(file, eof)
      let obj = timl#compiler#build(_.read, path)
      call obj.call()
      call add(strs, "function! s:d.f() abort\nlet locals = {}\n".obj.body."endfunction\n")
      let meta = timl#compiler#location_meta(path, _.read)
      if !empty(meta)
        let strs[-1] .= 'let g:timl_functions[join([s:d.f])] = '.string(meta)."\n"
      endif
      let strs[-1] .= "call s:d.f()\n"
    endwhile
    call add(strs, 'unlet s:d')
    call writefile(split(join(strs, "\n"), "\n"), cache)
  catch /^Vim\%((\a\+)\)\=:E168/
  finally
    let g:timl#core._STAR_ns_STAR_ = old_ns
    if exists('file')
      call timl#reader#close(file)
    endif
  endtry
endfunction

function! timl#loader#relative(path) abort
  if !empty(findfile('autoload/'.a:path.'.vim', &rtp))
    execute 'runtime! autoload/'.a:path.'.vim'
    return g:timl#nil
  endif
  for file in findfile('autoload/'.a:path.'.tim', &rtp, -1)
    call timl#loader#source(file)
    return g:timl#nil
  endfor
  throw 'timl: could not load '.a:path
endfunction

function! timl#loader#all_relative(paths) abort
  for path in timl#array#coerce(a:paths)
    if path[0] ==# '/'
      let path = path[1:-1]
    else
      let path = substitute(tr(timl#namespace#name(g:timl#core._STAR_ns_STAR_).str, '.-', '/_'), '[^/]*$', '', '') . path
    endif
    call timl#loader#relative(path)
  endfor
  return g:timl#nil
endfunction

if !exists('g:timl_requires')
  let g:timl_requires = {}
endif

function! timl#loader#require(ns, ...) abort
  let ns = timl#symbol#cast(a:ns).name
  if !has_key(g:timl_requires, ns) || a:0 && a:1
    call timl#loader#relative(tr(ns, '.-', '/_'))
    let g:timl_requires[ns] = 1
  endif
endfunction

let s:k_reload = timl#keyword#intern('reload')
let s:k_as = timl#keyword#intern('as')
let s:k_refer = timl#keyword#intern('refer')
let s:k_all = timl#keyword#intern('all')
let s:k_only = timl#keyword#intern('only')
function! timl#loader#require_all(_) abort
  let _ = {}
  let reload = 0
  for option in filter(copy(a:_), 'timl#keyword#test(v:val)')
    if option is# s:k_reload
      let reload = 1
    else
      throw 'timl#loader: unsupported require option :'.option[0]
    endif
  endfor
  for _.spec in a:_
    if timl#symbol#test(_.spec)
      call timl#loader#require(_.spec, reload)
    elseif timl#vector#test(_.spec)
      let _.lib = timl#coll#first(_.spec)
      call timl#loader#require(_.lib, reload)
      if timl#coll#fnext(_.spec) is# s:k_as
        call timl#namespace#alias(timl#coll#first(timl#coll#nnext(_.spec)), _.lib)
      elseif timl#coll#fnext(_.spec) is# s:k_refer
        let _.qualifier = timl#coll#first(timl#coll#nnext(_.spec))
        if _.qualifier is# s:k_all
          call timl#namespace#refer(_.lib)
        else
          call timl#namespace#refer(_.lib, s:k_only, _.qualifier)
        endif
      endif
    elseif !timl#keyword#test(_.spec)
      throw 'timl#loader: invalid loading spec type '.timl#type#string(_.spec)
    endif
  endfor
  return g:timl#nil
endfunction

function! timl#loader#use_all(_) abort
  let _ = {}
  for _.spec in a:_
    call timl#loader#require(_.spec)
    return timl#namespace#refer(_.spec)
  endfor
endfunction

function! timl#loader#init() abort
endfunction

if !exists('g:autoloaded_timl_bootstrap')
  runtime! autoload/timl/bootstrap.vim
endif

let s:core = timl#namespace#create(timl#symbol#intern('timl.core'))
let s:user = timl#namespace#create(timl#symbol#intern('user'))
call timl#namespace#intern(s:core, timl#symbol#intern('*ns*'), s:user)
let s:user.__mappings__['in-ns'] = s:core.__mappings__['in-ns']
call timl#loader#require(timl#symbol#intern('timl.core'))
call timl#namespace#refer(timl#symbol#intern('timl.core'))

" vim:set et sw=2:


================================================
FILE: autoload/timl/map.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_map")
  finish
endif
let g:autoloaded_timl_map = 1

function! timl#map#test(coll) abort
  return timl#type#canp(a:coll, g:timl#core.dissoc)
endfunction

let s:type = timl#type#core_create('HashMap')
function! timl#map#create(_) abort
  let keyvals = len(a:_) == 1 ? a:_[0] : a:_
  let map = s:empty
  for i in range(0, len(keyvals)-1, 16)
    let map = call('timl#map#assoc', [map] + keyvals[i : i+15])
  endfor
  lockvar 1 map
  return map
endfunction

function! timl#map#zip(keys, vals) abort
  let _ = {}
  let args = []
  let [_.keys, _.vals] = [timl#coll#seq(a:keys), timl#coll#seq(a:vals)]
  while _.keys isnot# g:timl#nil && _.vals isnot# g:timl#nil
    call extend(args, [timl#coll#first(_.keys), timl#coll#first(_.vals)])
    let [_.keys, _.vals] = [timl#coll#next(_.keys), timl#coll#next(_.vals)]
  endwhile
  return timl#map#create(args)
endfunction

function! timl#map#soft_coerce(coll) abort
  if timl#coll#sequentialp(a:coll)
    return timl#map#create(timl#array#coerce(a:coll))
  else
    return a:coll
  endif
endfunction

function! timl#map#to_array(this) abort
  return map(filter(items(a:this), 'v:val[0][0:1] !=# "__"'), '[timl#keyword#intern(v:val[0]), v:val[1]]') + timl#hash#items(a:this.__root)
endfunction

function! timl#map#length(this) abort
  return a:this.__length
endfunction

function! timl#map#equal(this, that) abort
  if a:this is# a:that
    return g:timl#true
  elseif !timl#map#test(a:that)
    return g:timl#false
  endif
  if timl#coll#count(a:this) !=# timl#coll#count(a:that)
    return g:timl#false
  endif
  let _ = {'seq': timl#coll#seq(a:this)}
  while _.seq isnot# g:timl#nil
    let _.other = timl#coll#get(a:that, timl#coll#ffirst(_.seq), _)
    if _.other is# _ || !timl#equality#test(timl#coll#first(timl#coll#nfirst(_.seq)), _.other)
      return g:timl#false
    endif
    let _.seq = timl#coll#next(_.seq)
  endwhile
  return g:timl#true
endfunction

function! timl#map#seq(this) abort
  let items = timl#map#to_array(a:this)
  return empty(items) ? g:timl#nil : timl#array_seq#create(items)
endfunction

function! timl#map#lookup(this, key, ...) abort
  if timl#keyword#test(a:key) && a:key.str !~# '^__'
    return get(a:this, a:key.str, a:0 ? a:1 : g:timl#nil)
  else
    return get(timl#hash#find(a:this.__root, a:key), 1, a:0 ? a:1 : g:timl#nil)
  endif
endfunction

if !exists('s:empty')
  let s:empty = timl#type#bless(s:type, {'__root': {}, '__length': 0})
  lockvar s:empty
endif
function! timl#map#empty(this) abort
  return s:empty
endfunction

function! timl#map#conj(this, ...) abort
  let _ = {}
  let this = a:this
  for _.e in a:000
    let this = timl#map#assoc(this, timl#coll#first(_.e), timl#coll#fnext(_.e))
  endfor
  return this
endfunction

function! timl#map#assoc(this, ...) abort
  let this = copy(a:this)
  for i in range(0, len(a:000)-2, 2)
    if timl#keyword#test(a:000[i]) && a:000[i].str !~# '^__'
      if !has_key(this, a:000[i].str)
        let this.__length += 1
      endif
      let this[a:000[i].str] = a:000[i+1]
    else
      let [this.__root, c] = timl#hash#assoc(this.__root, a:000[i], a:000[i+1])
      let this.__length += c
    endif
  endfor
  lockvar 1 this
  return this
endfunction

function! timl#map#dissoc(this, ...) abort
  let _ = {}
  let this = copy(a:this)
  for _.x in a:000
    if timl#keyword#test(_.x) && _.x.str !~# '^__'
      if has_key(this, _.x.str)
        call remove(this, _.x.str)
        let this.__length -= 1
      endif
    else
      let [this.__root, c] = timl#hash#dissoc(this.__root, _.x)
      let this.__length -= c
    endif
  endfor
  lockvar 1 this
  return this
endfunction

function! timl#map#call(this, _) abort
  return call('timl#map#lookup', [a:this] + a:_)
endfunction


================================================
FILE: autoload/timl/meta.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_meta')
  finish
endif
let g:autoloaded_timl_meta = 1

function! timl#meta#get(obj) abort
  if !timl#type#canp(a:obj, g:timl#core.get_meta)
    return g:timl#nil
  endif
  return timl#invoke(g:timl#core.get_meta, a:obj)
endfunction

function! timl#meta#with(obj, meta) abort
  return timl#invoke(g:timl#core.with_meta, a:obj, a:meta)
endfunction

function! timl#meta#vary(obj, fn, ...) abort
  return timl#meta#with(a:obj, timl#call(a:fn, [timl#meta#get(a:obj)] + a:000))
endfunction

function! timl#meta#alter(obj, fn, ...) abort
  return timl#call(g:timl#core.reset_meta_BANG_, [a:obj, timl#call(a:fn, [timl#meta#get(a:obj)] + a:000)])
endfunction

function! timl#meta#from_attribute(obj) abort
  return get(a:obj, 'meta', g:timl#nil)
endfunction

function! timl#meta#copy_assign_lock(obj, meta) abort
  if a:obj.meta isnot# a:meta
    let obj = copy(a:obj)
    let obj.meta = a:meta
    lockvar 1 obj
    return obj
  endif
  return a:obj
endfunction

function! timl#meta#copy_assign(obj, meta) abort
  if a:obj.meta isnot# a:meta
    let obj = copy(a:obj)
    let obj.meta = a:meta
    return obj
  endif
  return a:obj
endfunction


================================================
FILE: autoload/timl/namespace.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_namespace")
  finish
endif
let g:autoloaded_timl_namespace = 1

if !exists('g:timl#namespaces')
  let g:timl#namespaces = {}
endif

function! timl#namespace#munge(str) abort
  return tr(a:str, '-.', '_#')
endfunction

function! timl#namespace#create(name) abort
  let name = timl#symbol#cast(a:name)
  if !has_key(g:timl#namespaces, name[0])
    let ns = timl#type#bless(s:type, {'__name__': name, '__aliases__': {}, '__mappings__': {}})
    let g:timl#namespaces[name[0]] = ns
    let g:{timl#namespace#munge(name[0])} = ns
  endif
  return g:timl#namespaces[name[0]]
endfunction

function! timl#namespace#name(ns) abort
  return timl#namespace#the(a:ns).__name__
endfunction

function! timl#namespace#map(ns) abort
  return timl#namespace#the(a:ns).__mappings__
endfunction

function! timl#namespace#aliases(ns) abort
  return timl#namespace#the(a:ns).__aliases__
endfunction

function! timl#namespace#select(name) abort
  let g:timl#core._STAR_ns_STAR_ = timl#namespace#create(a:name)
  return g:timl#core._STAR_ns_STAR_
endfunction

function! timl#namespace#refer(name, ...) abort
  let me = g:timl#core._STAR_ns_STAR_
  let sym = timl#symbol#cast(a:name)
  let ns = timl#namespace#find(sym)
  let i = 0
  let only = keys(ns.__mappings__)
  let exclude = []
  if !exists('s:k_only')
    let s:k_only = timl#keyword#intern('only')
    let s:k_exclude = timl#keyword#intern('exclude')
  endif
  while i < a:0
    if a:000[i] is# s:k_only
      let only = map(copy(timl#array#coerce(get(a:000, i+1, []))), 'timl#symbol#cast(v:val).name')
      let i += 2
    elseif a:000[i] is# s:k_exclude
      let exclude = map(copy(timl#array#coerce(get(a:000, i+1, []))), 'timl#symbol#cast(v:val).name')
      let i += 2
    elseif timl#keyword#test(a:000[i])
      throw 'timl#namespace: invalid option :'.a:000[i][0]
    else
      throw 'timl#namespace: invalid option type '.timl#type#string(a:000[i][0])
    endif
  endwhile
  let _ = {}
  for name in only
    if !has_key(ns.__mappings__, name)
      throw 'timl#namespace: no such mapping '.name
    endif
    let var = ns.__mappings__[name]
    let _.private = get(var.meta, 'private', g:timl#nil)
    if var.ns is# ns && (_.private is# g:timl#false || _.private is# g:timl#nil) && index(exclude, name) == -1
      let me.__mappings__[name] = var
    endif
  endfor
  return g:timl#nil
endfunction

function! timl#namespace#alias(alias, name) abort
  let me = g:timl#core._STAR_ns_STAR_
  let me.__aliases__[timl#symbol#cast(a:alias).name] = a:name
  return g:timl#nil
endfunction

function! timl#namespace#find(name) abort
  return get(g:timl#namespaces, type(a:name) == type('') ? a:name : a:name.name, g:timl#nil)
endfunction

function! timl#namespace#the(name) abort
  if timl#type#string(a:name) ==# s:type.str
    return a:name
  endif
  let name = type(a:name) == type('') ? a:name : a:name.name
  if has_key(g:timl#namespaces, name)
    return g:timl#namespaces[name]
  endif
  throw 'timl: no such namespace '.name
endfunction

function! timl#namespace#maybe_resolve(ns, sym, ...) abort
  let ns = timl#namespace#the(a:ns)
  let sym = timl#symbol#cast(a:sym)
  if has_key(ns.__mappings__, sym.str)
    return ns.__mappings__[sym.str]
  endif
  if !empty(sym.namespace)
    if has_key(ns.__aliases__, sym.namespace)
      let aliasns = timl#namespace#the(ns.__aliases__[sym.namespace])
      if has_key(aliasns.__mappings__, sym.name)
        return aliasns.__mappings__[sym.name]
      endif
    endif
    if has_key(g:timl#namespaces, sym.namespace) && has_key(g:timl#namespaces[sym.namespace].__mappings__, sym.name)
      return g:timl#namespaces[sym.namespace].__mappings__[sym.name]
    endif
  endif
  return a:0 ? a:1 : g:timl#nil
endfunction

function! timl#namespace#all() abort
  return timl#coll#seq(values(g:timl#namespaces))
endfunction

function! timl#namespace#intern(ns, name, ...) abort
  let ns = timl#namespace#the(a:ns)
  let nsname = timl#namespace#name(ns).str
  let str = nsname.'/'.timl#symbol#cast(a:name).str
  let nsglobal = timl#namespace#munge(nsname)
  let key = timl#var#munge(a:name.str)
  let meta = copy(a:name.meta is# g:timl#nil ? timl#map#create([]) : a:name.meta)
  let meta.name = a:name
  let meta.ns = ns
  lockvar 1 meta
  if has_key(ns.__mappings__, a:name[0]) && ns.__mappings__[a:name[0]].ns is# ns
    let var = ns.__mappings__[a:name[0]]
    let var.meta = meta
  else
    let var = timl#type#bless(s:var_type, {'ns': ns, 'str': str, 'funcname': nsglobal.'#'.key, 'location': 'g:'.nsglobal.'.'.key, 'meta': meta})
  endif
  if a:0
    let ns[key] = a:1
  elseif !has_key(ns, key)
    let ns[key] = g:timl#nil
  endif
  let ns.__mappings__[a:name[0]] = var
  return var
endfunction

let s:type = timl#type#core_create('Namespace')
let s:var_type = timl#type#core_create('Var')

call timl#type#core_define('Type', g:timl#nil, {})
call timl#type#core_define('Namespace', g:timl#nil, {})
call timl#type#core_define('Var', g:timl#nil, {
      \ 'hash': 'timl#hash#str_attribute',
      \ 'get-meta': 'timl#meta#from_attribute',
      \ 'reset-meta!': 'timl#var#reset_meta',
      \ 'call': 'timl#var#call',
      \ 'funcref': 'timl#var#funcref',
      \ 'deref': 'timl#var#get'})
call timl#type#core_define('Symbol', g:timl#nil, {
      \ 'get-meta': 'timl#meta#from_attribute',
      \ 'with-meta': 'timl#meta#copy_assign_lock',
      \ 'equiv': 'timl#symbol#equal',
      \ 'hash': 'timl#hash#str_attribute',
      \ 'to-string': 'timl#keyword#to_string',
      \ 'name': 'timl#keyword#name',
      \ 'namespace': 'timl#keyword#namespace',
      \ 'call': 'timl#keyword#call'})
call timl#type#core_define('Keyword', g:timl#nil, {
      \ 'to-string': 'timl#keyword#to_string',
      \ 'hash': 'timl#hash#str_attribute',
      \ 'name': 'timl#keyword#name',
      \ 'namespace': 'timl#keyword#namespace',
      \ 'call': 'timl#keyword#call'})


================================================
FILE: autoload/timl/nil.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_nil")
  finish
endif
let g:autoloaded_timl_nil = 1

function! s:freeze(...) abort
  return a:000
endfunction

if !exists('g:timl#nil')
  let g:timl#nil = s:freeze()
  lockvar 1 g:timl#nil
endif

function! timl#nil#identity(...) abort
  return g:timl#nil
endfunction

function! timl#nil#length(...) abort
  return 0
endfunction

function! timl#nil#to_string(...) abort
  return ''
endfunction

function! timl#nil#test(this) abort
  return a:this is# g:timl#nil
endfunction

function! timl#nil#lookup(this, key, default) abort
  return a:default
endfunction

function! timl#nil#cons(this, ...) abort
  return call('timl#cons#conj', [timl#list#empty()] + a:000)
endfunction

function! timl#nil#assoc(this, ...) abort
  return timl#map#create(a:000)
endfunction

call timl#type#core_define('Nil', g:timl#nil, {
      \ 'seq': 'timl#nil#identity',
      \ 'to-string': 'timl#nil#to_string',
      \ 'empty': 'timl#nil#identity',
      \ 'car': 'timl#nil#identity',
      \ 'cdr': 'timl#list#empty',
      \ 'conj': 'timl#nil#cons',
      \ 'assoc': 'timl#nil#assoc',
      \ 'length': 'timl#nil#length',
      \ 'hash': 'timl#nil#length',
      \ 'lookup': 'timl#nil#lookup'})


================================================
FILE: autoload/timl/number.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_number")
  finish
endif
let g:autoloaded_timl_number = 1

let s:int = type(0)
let s:float = 5

function! timl#number#coerce(obj) abort
  if type(a:obj) == s:int || type(a:obj) == s:float
    return a:obj
  endif
  throw "timl: not a number"
endfunction

function! timl#number#int(obj) abort
  if type(a:obj) == s:int
    return a:obj
  elseif type(a:obj) == s:float
    return float2nr(a:obj)
  endif
  throw "timl: not a number"
endfunction

function! timl#number#float(obj) abort
  if type(a:obj) == s:tfloat
    return a:obj
  elseif type(a:obj) == s:tint
    return 0.0 + a:obj
  endif
  throw "timl: not a float"
endfunction

function! timl#number#test(obj) abort
  return type(a:obj) == s:int || type(a:obj) == s:float
endfunction

function! timl#number#integerp(obj) abort
  return type(a:obj) == s:int
endfunction

function! timl#number#floatp(obj) abort
  return type(a:obj) == s:float
endfunction

function! timl#number#sum(_) abort
  let acc = 0
  for elem in a:_
    let acc += elem
  endfor
  return acc
endfunction

function! timl#number#product(_) abort
  let acc = 1
  for elem in a:_
    let acc = acc * elem
  endfor
  return acc
endfunction

function! timl#number#minus(_) abort
  if len(a:_) ==# 1
    return 0 - a:_[0]
  elseif len(a:_)
    let acc = timl#number#coerce(a:_[0])
    for elem in a:_[1:-1]
      let acc -= elem
    endfor
    return acc
  endif
  throw 'timl: arity error'
endfunction

function! timl#number#solidus(_) abort
  if len(a:_) ==# 1
    return 1 / a:_[0]
  elseif len(a:_)
    let acc = timl#number#coerce(a:_[0])
    for elem in a:_[1:-1]
      let acc = acc / elem
    endfor
    return acc
  endif
  throw 'timl: arity error'
endfunction

function! timl#number#gt(_) abort
  if empty(a:_)
    throw 'timl: arity error'
  endif
  let x = timl#number#coerce(a:_[0])
  for y in map(a:_[1:-1], 'timl#number#coerce(v:val)')
    if !(x > y)
      return g:timl#false
    endif
    let x = y
  endfor
  return g:timl#true
endfunction

function! timl#number#lt(_) abort
  if empty(a:_)
    throw 'timl: arity error'
  endif
  let x = timl#number#coerce(a:_[0])
  for y in map(a:_[1:-1], 'timl#number#coerce(v:val)')
    if !(x < y)
      return g:timl#false
    endif
    let x = y
  endfor
  return g:timl#true
endfunction

function! timl#number#gteq(_) abort
  if empty(a:_)
    throw 'timl: arity error'
  endif
  let x = timl#number#coerce(a:_[0])
  for y in map(a:_[1:-1], 'timl#number#coerce(v:val)')
    if !(x >= y)
      return g:timl#false
    endif
    let x = y
  endfor
  return g:timl#true
endfunction

function! timl#number#lteq(_) abort
  if empty(a:_)
    throw 'timl: arity error'
  endif
  let x = timl#number#coerce(a:_[0])
  for y in map(a:_[1:-1], 'timl#number#coerce(v:val)')
    if !(x <= y)
      return g:timl#false
    endif
    let x = y
  endfor
  return g:timl#true
endfunction

function! timl#number#equiv(_) abort
  if empty(a:_)
    throw 'timl: arity error'
  endif
  let x = timl#number#coerce(a:_[0])
  for y in map(a:_[1:-1], 'timl#number#coerce(v:val)')
    if x != y
      return g:timl#false
    endif
  endfor
  return g:timl#true
endfunction

function! timl#number#inc(x) abort
  return timl#number#coerce(a:x) + 1
endfunction

function! timl#number#dec(x) abort
  return timl#number#coerce(a:x) - 1
endfunction

function! timl#number#rem(x, y) abort
  return timl#number#coerce(a:x) % a:y
endfunction

function! timl#number#quot(x, y) abort
  return type(a:x) == 5 || type(a:y) == 5 ? trunc(a:x/a:y) : timl#number#coerce(a:x)/a:y
endfunction

function! timl#number#mod(x, y) abort
  if (timl#number#coerce(a:x) < 0 && timl#number#coerce(a:y) > 0 || timl#number#coerce(a:x) > 0 && timl#number#coerce(a:y) < 0) && a:x % a:y != 0
    return (a:x % a:y) + a:y
  else
    return a:x % a:y
  endif
endfunction

function! timl#number#bit_not(x) abort
  return invert(a:x)
endfunction

function! timl#number#bit_or(_) abort
  let acc = 0
  for i in map(copy(a:_), 'timl#number#int(v:val)')
    let acc = or(acc, i)
  endfor
  return acc
endfunction

function! timl#number#bit_xor(_) abort
  let acc = 0
  for i in map(copy(a:_), 'timl#number#int(v:val)')
    let acc = xor(acc, i)
  endfor
  return acc
endfunction

function! timl#number#bit_and(_) abort
  let acc = -1
  for i in map(copy(a:_), 'timl#number#int(v:val)')
    let acc = and(acc, i)
  endfor
  return acc
endfunction

function! timl#number#bit_and_not(_) abort
  let acc = timl#number#int(a:_[0])
  for i in map(a:_[1:-1], 'timl#number#int(v:val)')
    let acc = and(acc, invert(i))
  endfor
  return acc
endfunction

function! timl#number#bit_shift_left(x, n) abort
  let x = timl#number#int(a:x)
  for i in range(timl#number#int(a:n))
    let x = x * 2
  endfor
  return x
endfunction

function! timl#number#bit_shift_right(x, n) abort
  let x = timl#number#int(a:x)
  for i in range(timl#number#int(a:n))
    let x = x / 2
  endfor
  return x
endfunction

function! timl#number#bit_flip(x, n) abort
  return xor(a:x, g:timl#core.bit_shift_left.call(1, a:n))
endfunction

function! timl#number#bit_set(x, n) abort
  return or(a:x, g:timl#core.bit_shift_left.call(1, a:n))
endfunction

function! timl#number#bit_clear(x, n) abort
  return and(a:x, invert(g:timl#core.bit_shift_left.call(1, a:n)))
endfunction

function! timl#number#bit_test(x, n) abort
  return and(a:x, g:timl#core.bit_shift_left.call(1, a:n))
endfunction

function! timl#number#not_negative(x) abort
  return timl#number#coerce(a:x) < 0 ? g:timl#nil : a:x
endfunction

function! timl#number#zerop(x) abort
  return timl#number#coerce(a:x) == 0
endfunction

function! timl#number#nonzerop(x) abort
  return timl#number#coerce(a:x) != 0
endfunction

function! timl#number#posp(x) abort
  return timl#number#coerce(a:x) > 0
endfunction

function! timl#number#negp(x) abort
  return timl#number#coerce(a:x) < 0
endfunction

function! timl#number#oddp(x) abort
  return timl#number#coerce(a:x) % 2
endfunction

function! timl#number#evenp(x) abort
  return timl#number#coerce(a:x) % 2 == 0
endfunction


================================================
FILE: autoload/timl/plugin_helper.tim
================================================
(ns timl.plugin-helper)

(defmacro include-guard [var]
  (let [string (munge (str var))]
   `(if (exists? ~string)
     (execute "finish")
     (set! ~var 1))))

(defn build-option-string [args]
  (subs
    (loop [s ""
           x (first args)
           more (rest args)]
      (if (nil? x)
        s
        (recur
          (if (symbol? x) (str s " " x) (str s (#*fnameescape (str x))))
          (first more) (rest more))
        )) 1))

(defn extract-option-names [args]
  (map (fn [x] (#*matchstr (str x) #"%(inv|no)?\zs\w+")) (filter symbol? args)))

(defn extract-option-restore [args]
  (if-let [options (extract-option-names args)]
    (str "setlocal " (join "< " (map str options)) "<")))

(defmacro setlocal [& opts]
  `(execute (str "setlocal " ~(build-option-string opts))))

(defmacro setglobal [& opts]
  `(execute (str "setlocal " ~(build-option-string opts))))


================================================
FILE: autoload/timl/printer.vim
================================================
" Maintainer:   Tim Pope <http://tpo.pe/>

if exists("g:autoloaded_timl_printer")
  finish
endif
let g:autoloaded_timl_printer = 1

let s:escapes = {
      \ "\n": '\n',
      \ "\r": '\r',
      \ "\t": '\t',
      \ "\"": '\"',
      \ "\\": '\\'}

function! timl#printer#string(x) abort
  " TODO: guard against recursion
  let type = timl#type#string(a:x)
  if type ==# 'timl.lang/Symbol'
    return a:x[0]

  elseif type ==# 'timl.lang/Keyword'
    return ':'.a:x[0]

  elseif type ==# 'timl.lang/Nil'
    return 'nil'

  elseif type ==# 'timl.lang/Boolean'
    return get(a:x, 'val') ? 'true' : 'false'

  elseif type ==# 'timl.lang/Function'
    return '#<'
          \ . get(a:x, 'ns', {'name': ['...']}).__name__[0] . '/'
          \ . (get(a:x, 'name', g:timl#nil) is g:timl#nil ? '...' : a:x.name.name)
          \ . ' #*'.join([get(a:x, '__call__', '???')]).'>'

  elseif type ==# 'timl.lang/MultiFn'
    return '#<'
          \ . get(a:x, 'ns', {'__name__': ['...']}).__name__[0] . '/'
          \ . (get(a:x, 'name', g:timl#nil) is g:timl#nil ? '...' : a:x.name.name)
          \ . ' multi>'

  elseif type ==# 'timl.lang/Namespace'
    return '#<Namespace '.get(a:x, '__name__', '')[0].'>'

  elseif type ==# 'timl.lang/Var'
    return "#'".a:x.str

  elseif type ==# 'timl.lang/Exception'
    return '#<Exception '.a:x.exception.' @ '.a:x.throwpoint.'>'

  elseif type(a:x) == type('')
    return '"'.substitute(a:x, "[\n\r\t\"\\\\]", '\=get(s:escapes, submatch(0))', 'g').'"'

  elseif type(a:x) == type([])
    return '#*['.join(map(a:x[:], 'timl#printer#string(v:val)'), ' ') . ']'

  elseif type == 'vim/Dictionary'
    let acc = []
    for [k, V] in items(a:x)
      call add(acc, timl#printer#string(k) . ' ' . timl#printer#string(V))
      unlet! V
    endfor
    return '#*{' . join(acc, ' ') . '}'

  elseif type == 'timl.lang/Type'
    return a:x.str

  elseif timl#vector#test(a:x)
    return '['.join(map(timl#array#coerce(a:x), 'timl#printer#string(v:val)'), ' ') . ']'

  elseif timl#map#test(a:x)
    let acc = []
    let _ = {'seq': timl#coll#seq(a:x)}
    while _.seq isnot# g:timl#nil
      call add(acc, timl#printer#string(timl#coll#first(_.seq))[3:-2])
      let _.seq = timl#coll#next(_.seq)
    endwhile
    return '{' . join(acc, ', ') . '}'

  elseif timl#set#test(a:x)
    let acc = []
    let _ = {'seq': timl#coll#seq(a:x)}
    while _.seq isnot# g:timl#nil
      call add(acc, timl#printer#string(timl#coll#first(_.seq)))
      let _.seq = timl#coll#next(_.seq)
    endwhile
    return '#{' . join(acc, ' ') . '}'

  elseif timl#coll#seqp(a:x)
    let _ = {'seq': timl#coll#seq(a:x)}
    let output = []
    while _.seq isnot# g:timl#nil
      call add(output, timl#printer#string(timl#coll#first(_.seq)))
      let _.seq = timl#coll#next(_.seq)
    endwhile
    return '('.join(output, ' ').')'

  elseif type(a:x) == type(function('tr'))
    return '#*'.substitute(join([a:x]), '[{}]', '', 'g')

  elseif type ==# 'timl.lang/Instant'
    return '#inst "'.timl#inst#to_string(a:x).'"'

  elseif type ==# 'vim/Float' && string(a:x) =~# 'n'
    if string(a:x) ==# 'inf'
      return 'Infinity'
    elseif string(a:x) ==# '-inf'
      return '-Infinity'
    else
      return 'NaN'
    endif

  elseif type =~# '^vim/'
    return string(a:x)

  else
    let acc = []
    for [k, V] in items(a:x)
      if k !~# '^__'
        call add(acc, k . '=' . timl#printer#string(V))
      endif
      unlet! V
    endfor
    return '#<'.type.' ' . join(acc, ', ') . '>'

  endif
endfunction

" Section: Tests {{{1

if !$TIML_TEST
  finish
endif

command! -nargs=1 TimLPAssert
      \ try |
      \ if !eval(<q-args>) |
      \ echomsg "Failed: ".<q-args> |
      \   endif |
      \ catch /.*/ |
      \  echomsg "Error:  ".<q-args>." (".v:exception.")" |
      \ endtry

TimLPAssert timl#printer#string('foo') ==# '"foo"'
TimLPAssert timl#printer#string(timl#symbol('foo')) ==# 'foo'
TimLPAssert timl#printer#string(timl#vector#claim([1,2])) ==# '[1 2]'
TimLPAssert timl#printer#string({"a": 1, "b": 2}) ==# '#*{"a" 1 "b" 2}'

delcommand TimLPAssert

" }}}1

" vim:set et sw=2:


================================================
FILE: autoload/timl/reader.vim
================================================
" Maintainer:   Tim Pope <http://tpo.pe/>

if exists("g:autoloaded_timl_reader")
  finish
endif
let g:autoloaded_timl_reader = 1

let s:iskeyword = '[[:alnum:]_=?!#$%&*+|./<>:-]'

function! s:read_token(port) abort
  let pat = '^\%(#"\%(\\\@<!\%(\\\\\)*\\"\|[^"]\)*"\|"\%(\\.\|[^"]\)*"\|[[:space:],]\+\|\%(;\|#!\)[^'."\n".']*\|\~@\|#[[:punct:]]\|'.s:iskeyword.'\+\|\\\%(space\|tab\|newline\|return\|.\)\|.\)'
  let match = ' '
  while match =~# '^[[:space:],]'
    let [pos, line] = [a:port.pos, a:port.line]
    let match = matchstr(a:port.str, pat, a:port.pos)
    let a:port.pos += len(match)
    let a:port.line += len(substitute(match, "[^\n]", '', 'g'))
  endwhile
  return [match, pos, line]
endfunction

function! timl#reader#eofp(port) abort
  return a:port.pos >= len(a:port.str)
endfunction

let g:timl#reader#eof = []

function! timl#reader#read(port, ...) abort
  let error = 'timl#reader: unexpected EOF'
  try
    let val = s:read(a:port)
    if val isnot# g:timl#reader#eof
      return val
    elseif a:0
      return a:1
    endif
  catch /^timl.*/
    let error = v:exception
  endtry
  throw error
endfunction

let s:found = {}
function! s:read_until(port, char) abort
  let list = []
  let _ = {}
  let _.read = s:read(a:port, a:char)
  while _.read isnot# s:found && _.read isnot# g:timl#reader#eof
    call add(list, _.read)
    let _.read = s:read(a:port, a:char)
  endwhile
  if _.read is# s:found
    lockvar 1 list
    return list
  endif
  throw 'timl#reader: unexpected EOF'
endfunction

let s:constants = {
      \ '\space': " ",
      \ '\tab': "\t",
      \ '\newline': "\n",
      \ '\return': "\r",
      \ '\formfeed': "\f",
      \ '\backspace': "\b"}

function! s:add_meta(data, meta) abort
  let _ = {}
  let _.meta = timl#meta#get(a:data)
  if _.meta is g:timl#nil
    let _.meta = a:meta
  else
    let _.meta = timl#coll#into(_.meta, a:meta)
  endif
  return timl#meta#with(a:data, _.meta)
endfunction

let s:map_type = timl#type#core_create('HashMap')
function! s:read(port, ...) abort
  let port = a:port
  let [token, pos, line] = s:read_token(a:port)
  let wanted = a:0 ? a:1 : ''
  if token ==# '('
    let meta = timl#type#bless(s:map_type, {'line': line, '__length': 1, '__root': {}})
    return timl#list#create(s:read_until(port, ')'), meta)
  elseif token == '['
    return timl#vector#claim(s:read_until(port, ']'))
  elseif token == '{'
    let list = s:read_until(port, '}')
    if len(list) % 2 != 0
      let error = 'timl#reader: invalid hash map literal'
    else
      return timl#map#create(list)
    endif
  elseif token == '#{'
    return timl#set#coerce(s:read_until(port, '}'))
  elseif has_key(s:constants, token)
    return s:constants[token]
  elseif token ==# 'nil'
    return g:timl#nil
  elseif token ==# 'false'
    return g:timl#false
  elseif token ==# 'true'
    return g:timl#true
  elseif token ==# 'Infinity' || token ==# '+Infinity'
    return 1/(0.0)
  elseif token ==# '-Infinity'
    return -1/(0.0)
  elseif token ==# 'NaN'
    return 0/(0.0)
  elseif token =~# '^\d\+e\d\+$'
    return eval(substitute(token, 'e', '.0e', ''))
  elseif token =~# '^\.\d'
    return eval('0'.token)
  elseif token =~# '^"\|^[+-]\=\d\%(.*\d\)\=$'
    return eval(token)
  elseif token =~# '^#"'
    return '\C\v'.substitute(token[2:-2], '\\\@<!\(\%(\\\\\)*\)\\"', '\1"', 'g')
  elseif token[0] ==# '\'
    return token[1]
  elseif token ==# "'"
    return timl#list(timl#symbol('quote'), s:read_bang(port))
  elseif token ==# '`'
    return timl#reader#syntax_quote(s:read_bang(port), {})
  elseif token ==# '~'
    return timl#list(s:unquote, s:read_bang(port))
  elseif token ==# '~@'
    return timl#list(s:unquote_splicing, s:read_bang(port))
  elseif token ==# "#'"
    return timl#list(timl#symbol('var'), s:read_bang(port))
  elseif token ==# '#*'
    let next = s:read_bang(port)
    if timl#map#test(next)
      return timl#dictionary#create([next])
    elseif timl#vector#test(next)
      return timl#array#coerce(next)
    else
      return timl#list(timl#symbol('function'), next)
    endif
  elseif token[0] ==# ';' || token =~# '^#!'
    return s:read(port, wanted)
  elseif token ==# '#_'
    call s:read(port)
    return s:read(port, wanted)
  elseif token ==# '#('
    if has_key(port, 'argsyms')
      throw "timl#reader: can't nest #()"
    endif
    try
      let port.argsyms = {}
      let list = s:read_until(port, ')')
      let rest = has_key(port.argsyms, '%&')
      let args = map(range(1, len(port.argsyms) - rest), 'port.argsyms["%".v:val]')
      if rest
        call add(args, a:port.argsyms['%&'])
      endif
      return timl#list(timl#symbol('fn*'), args, timl#list#create(list))
    finally
      unlet! a:port.argsyms
    endtry
  elseif token =~# '^%\d*$\|^%&$' && has_key(port, 'argsyms')
    let token = (token ==# '%' ? '%1' : token)
    if !has_key(port.argsyms, token)
      let port.argsyms[token] = timl#symbol#gen('p1__')
    endif
    return port.argsyms[token]

  elseif token ==# '#uuid'
    return tolower(s:read(port))

  elseif token ==# '#inst'
    return timl#inst#parse(s:read(port))

  elseif token =~# '^#\a'
    let next = s:read(port)
    unlockvar 1 next
    let token = token[1:-1]
    if token !~# '[/.]'
      let token = 'timl.lang/'.token
    endif
    let munged = timl#var#munge(token)
    if timl#map#test(next) && exists("g:".substitute(munged, '.*\zs#', '#map__GT_', ''))
      return timl#invoke(g:{substitute(munged, '.*\zs#', '#map__GT_', '')}, next)
    elseif timl#vector#test(next) && exists("g:".substitute(munged, '.*\zs#', '#__GT_', ''))
      return timl#call(g:{substitute(munged, '.*\zs#', '#__GT_', '')}, timl#array#coerce(next))
    else
      throw 'timl#reader: invalid tag ' . token . ' on ' . timl#type#string(next)
    endif
  elseif token =~# '^::.\+/.'
    let alias = matchstr(token[2:-1], '.*\ze/.')
    let ns = get(timl#namespace#aliases(g:timl#core._STAR_ns_STAR_), alias, {})
    if empty(ns)
      let error = 'timl#reader: unknown ns alias '.alias.' in keyword'
    else
      return timl#keyword#intern(timl#namespace#the(ns).name[0].matchstr(token, '.*\zs/.\+'))
    endif
  elseif token =~# '^::.'
    return timl#keyword#intern(timl#namespace#name(g:timl#core._STAR_ns_STAR_).str.'/'.token[2:-1])
  elseif token =~# '^:.'
    return timl#keyword#intern(token[1:-1])
  elseif token =~# '^'.s:iskeyword
    return timl#symbol(token)
  elseif token ==# '^'
    let _meta = s:read(port)
    let data = s:read(port)
    if timl#keyword#test(_meta)
      let meta = timl#map#create([_meta, g:timl#true])
    elseif timl#symbol#test(_meta) || type(_meta) == type('')
      let meta = timl#map#create([timl#keyword#intern('tag'), _meta])
    elseif timl#map#test(_meta)
      let meta = _meta
    else
      throw 'timl#reader: metadata must be symbol, string, keyword, or map'
    endif
    if timl#type#objectp(data)
      return s:add_meta(data, meta)
    endif
    return data
    let error = 'timl#reader: cannot attach metadata to a '.timl#type#string(data)
  elseif token ==# '@'
    return timl#list(timl#symbol('timl.core/deref'), s:read_bang(port))
  elseif empty(token)
    return g:timl#reader#eof
  elseif token ==# wanted
    return s:found
  else
    let error = 'timl#reader: unexpected token '.string(token)
  endif
  throw error . ' on line ' . line
endfunction

function! s:read_bang(port) abort
  let val = s:read(a:port)
  if val isnot# g:timl#reader#eof
    return val
  endif
  throw 'timl#reader: unexpected EOF'
endfunction

let s:quote = timl#symbol('quote')
let s:unquote = timl#symbol('unquote')
let s:unquote_splicing = timl#symbol('unquote-splicing')
let s:function = timl#symbol('function')
let s:list = timl#symbol('timl.core/list')
let s:concat = timl#symbol('timl.core/concat')
let s:seq = timl#symbol('timl.core/seq')
let s:vec = timl#symbol('timl.core/vec')
let s:set = timl#symbol('timl.core/set')
let s:hash_map = timl#symbol('timl.core/hash-map')
function! timl#reader#syntax_quote(form, gensyms) abort
  if timl#symbol#test(a:form)
    if a:form[0] =~# '^[^/]\+#$'
      if !has_key(a:gensyms, a:form[0])
        let a:gensyms[a:form[0]] = timl#symbol(timl#symbol#gen(a:form[0][0:-2].'__')[0].'__auto__')
      endif
      let quote = s:quote
      let x = timl#list(s:quote, a:gensyms[a:form[0]])
      return timl#list(s:quote, a:gensyms[a:form[0]])
    elseif !timl#compiler#specialp(a:form[0]) && a:form[0] !~# ':\|^[&$]'
      return timl#list(s:quote, timl#symbol(timl#namespace#maybe_resolve(
            \ g:timl#core._STAR_ns_STAR_,
            \ a:form,
            \ {'str': (a:form[0] =~# '/.' ? '' : timl#namespace#name(g:timl#core._STAR_ns_STAR_).str.'/').a:form[0]}).str))
    else
      return timl#list(s:quote, a:form)
    endif
  elseif timl#vector#test(a:form)
    return timl#list(s:vec, timl#cons#create(s:concat, s:sqexpandlist(a:form, a:gensyms)))
  elseif timl#set#test(a:form)
    return timl#list(s:set, timl#cons#create(s:concat, s:sqexpandlist(a:form, a:gensyms)))
  elseif timl#map#test(a:form)
    let _ = {'seq': timl#coll#seq(a:form)}
    let keyvals = []
    while _.seq isnot# g:timl#nil
      call extend(keyvals, timl#array#coerce(timl#coll#first(_.seq)))
      let _.seq = timl#coll#next(_.seq)
    endwhile
    return timl#list(s:hash_map, timl#cons#create(s:concat, s:sqexpandlist(keyvals, a:gensyms)))

  elseif timl#coll#test(a:form)
    let first = timl#coll#first(a:form)
    if first is# s:unquote
      return timl#coll#first(timl#coll#rest(a:form))
    elseif first is# s:unquote_splicing
      throw 'timl#reader: unquote-splicing used outside of list'
    elseif first is# s:function
      return a:form
    else
      return timl#list(s:seq, timl#cons#create(s:concat, s:sqexpandlist(a:form, a:gensyms)))
    endif
  else
    return a:form
  endif
endfunction

function! s:sqexpandlist(seq, gensyms) abort
  let result = []
  let _ = {'seq': timl#coll#seq(a:seq)}
  while _.seq isnot# g:timl#nil
    let _.this = timl#coll#first(_.seq)
    if timl#coll#seqp(_.this)
      if timl#coll#first(_.this) is# s:unquote
        call add(result, timl#list(s:list, timl#coll#first(timl#coll#rest(_.this))))
      elseif timl#coll#first(_.this) is# s:unquote_splicing
        call add(result, timl#coll#first(timl#coll#rest(_.this)))
      else
        call add(result, timl#list(s:list, timl#reader#syntax_quote(_.this, a:gensyms)))
      endif
    else
      call add(result, timl#list(s:list, timl#reader#syntax_quote(_.this, a:gensyms)))
    endif
    let _.seq = timl#coll#next(_.seq)
  endwhile
  return result
endfunction

function! timl#reader#open(filename) abort
  let str = join(readfile(a:filename), "\n")
  return {'str': str, 'filename': fnamemodify(a:filename, ':p'), 'pos': 0, 'line': 1}
endfunction

function! timl#reader#open_string(string, ...) abort
  let port = {'str': a:string, 'pos': 0, 'line': a:0 > 1 ? a:2 : 1}
  if a:0
    let port.filename = a:1
  endif
  return port
endfunction

function! timl#reader#close(port) abort
  return a:port
endfunction

function! timl#reader#read_all(port) abort
  let all = []
  let _ = {}
  try
    while 1
      let _.form = s:read(a:port)
      if _.form is# g:timl#reader#eof
        return all
      endif
      call add(all, _.form)
    endwhile
  catch /^timl.*/
    let error = v:exception
  endtry
  throw error
endfunction

function! timl#reader#read_string_all(str) abort
  return timl#reader#read_all({'str': a:str, 'pos': 0, 'line': 1})
endfunction

function! timl#reader#read_string(str) abort
  return timl#reader#read({'str': a:str, 'pos': 0, 'line': 1})
endfunction

" Section: Tests {{{1

if !$TIML_TEST
  finish
endif

command! -nargs=1 TimLRAssert
      \ try |
      \ if !eval(<q-args>) |
      \ echomsg "Failed: ".<q-args> |
      \   endif |
      \ catch /.*/ |
      \  echomsg "Error:  ".<q-args>." (".v:exception.")" |
      \ endtry

TimLRAssert timl#equality#test(timl#reader#read_string('foo'), timl#symbol('foo'))
TimLRAssert timl#equality#test(timl#reader#read_string('":)"'), ':)')
TimLRAssert timl#equality#test(timl#reader#read_string('#"\(a\\\)"'), '\C\v\(a\\\)')
TimLRAssert timl#equality#test(timl#reader#read_string('#"\""'), '\C\v"')
TimLRAssert timl#equality#test(timl#reader#read_string('(first [1 2])'), timl#list(timl#symbol('first'), timl#vector#claim([1, 2])))
TimLRAssert timl#equality#test(timl#reader#read_string('#*{"a" 1 "b" 2}'), {"a": 1, "b": 2})
TimLRAssert timl#equality#test(timl#reader#read_string('{"a" 1 :b 2 3 "c"}'), timl#map#create(["a", 1, timl#keyword#intern('b'), 2, 3, "c"]))
TimLRAssert timl#equality#test(timl#reader#read_string("[1]\n; hi\n"), timl#vector#claim([1]))
TimLRAssert timl#equality#test(timl#reader#read_string("'[1 2 3]"), timl#list(timl#symbol('quote'), timl#vector#claim([1, 2, 3])))
TimLRAssert timl#equality#test(timl#reader#read_string("#*tr"), timl#list(timl#symbol('function'), timl#symbol('tr')))
TimLRAssert timl#equality#test(timl#reader#read_string("(1 #_2 3)"), timl#list(1, 3))
TimLRAssert timl#equality#test(timl#reader#read_string("^:foo ()"),
      \ timl#meta#with(g:timl#empty_list, timl#map#create([timl#keyword#intern('foo'), g:timl#true])))

TimLRAssert timl#equality#test(timl#reader#read_string("~foo"), timl#list(s:unquote, timl#symbol('foo')))
TimLRAssert timl#coll#first(timl#coll#rest(timl#reader#read_string("`foo#")))[0] =~# '^foo__\d\+__auto__'

delcommand TimLRAssert

" }}}1

" vim:set et sw=2:


================================================
FILE: autoload/timl/repl.tim
================================================
(ns timl.repl)

(defn qf
  ([] (qf *e))
  ([e]
   (#*timl#interactive#copen e)
   (throw "timl#repl: exit")))

(defn breakpoint-fn [env]
  (let [str (#*input (format "%s=>> " (str (ns-name *ns*))))]
    (when (#*len str)
      (newline)
      (try
        (prn (#*timl#loader#eval (read-string str) (ns-name *ns*) env))
        (catch "" e (set! *e e) (println (. e exception))))
      (recur env))))

(defmacro breakpoint []
  `(timl.repl/breakpoint-fn ~(list #*eval "locals")))

(defmacro breakadd []
  `(execute "execute 'breakadd func '.(1+expand('<slnum>')).' '.matchstr(expand('<sfile>'), '.*\\.\\zs.*')"))
(defn breakme []
  (breakadd)
  (+ 1 (* 2 3)))

(defn compile [body]
  (print (. (#*timl#compiler#build body) body)))

(defn help-topic [sym]
  (if (special-symbol? sym)
    (str "timl-" sym)
    (if-let [v (resolve sym)]
      (:help (meta v) (. v location))
      (str sym))))

(defmacro help [sym]
  `(throw (str "timl#repl: exit help " ~(help-topic sym))))

(defmacro edit [sym]
  `(let [m (meta (var ~sym))]
     (if (not= (:file m "NO_SOURCE_PATH") "NO_SOURCE_PATH")
       (throw (str "timl#repl: exit edit +" (:line m) " " (#*fnameescape (:file m)))))))


================================================
FILE: autoload/timl/set.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_set")
  finish
endif
let g:autoloaded_timl_set = 1

function! timl#set#test(coll) abort
  return timl#type#canp(a:coll, g:timl#core.disj)
endfunction

function! timl#set#key(key) abort
  if type(a:key) == type(0)
    return string(a:key)
  elseif timl#keyword#test(a:key) && a:key[0][0:1] !=# '__'
    return a:key[0]
  elseif timl#symbol#test(a:key)
    return "'".a:key[0]
  elseif type(a:key) == type('')
    return '"'.a:key[0]
  elseif a:key is# g:timl#nil
    return ' '
  else
    return ''
  endif
endfunction

function! timl#set#coerce(seq) abort
  if timl#set#test(a:seq)
    return a:seq
  endif
  let _ = {}
  let dict = timl#type#bless(s:transient_type, {'__extra': []})
  if type(a:seq) == type([])
    for _.val in a:seq
      call timl#set#conjb(dict, _.val)
    endfor
  else
    let _.seq = timl#coll#seq(a:seq)
    while _.seq isnot# g:timl#nil
      call timl#set#conjb(dict, timl#coll#first(_.seq))
      let _.seq = timl#coll#next(_.seq)
    endwhile
  endif
  return timl#set#persistentb(dict)
endfunction

function! timl#set#to_array(this) abort
  return extend(map(filter(items(a:this), 'v:val[0][0:1] !=# "__"'), 'v:val[1]'), a:this.__extra)
endfunction

function! timl#set#length(this) abort
  return len(timl#set#to_array(a:this))
endfunction

function! timl#set#seq(this) abort
  let items = timl#set#to_array(a:this)
  return empty(items) ? g:timl#nil : timl#array_seq#create(items)
endfunction

function! timl#set#equal(this, that) abort
  if a:this is# a:that
    return g:timl#true
  elseif !timl#set#test(a:that)
    return g:timl#false
  endif
  if timl#coll#count(a:this) !=# timl#coll#count(a:that)
    return g:timl#false
  endif
  let _ = {'seq': timl#coll#seq(a:this)}
  while _.seq isnot# g:timl#nil
    if timl#coll#get(a:that, timl#coll#first(_.seq), _) is# _
      return g:timl#false
    endif
    let _.seq = timl#coll#next(_.seq)
  endwhile
  return g:timl#true
endfunction

function! timl#set#lookup(this, key, ...) abort
  let _ = {}
  let key = timl#set#key(a:key)
  if empty(key)
    for _.v in a:this.__extra
      if timl#equality#test(_.v, a:key)
        return _.v
      endif
    endfor
    return a:0 ? a:1 g:timl#nil
  else
    return get(a:this, key, a:0 ? a:1 : g:timl#nil)
  endif
endfunction

function! timl#set#empty(this) abort
  return s:empty
endfunction

function! timl#set#conj(this, ...) abort
  return timl#set#persistentb(call('timl#set#conjb', [timl#set#transient(a:this)] + a:000))
endfunction

function! timl#set#conjb(this, ...) abort
  let _ = {}
  for _.e in a:000
    let key = timl#set#key(_.e)
    if empty(key)
      let found = 0
      for i in range(len(a:this.__extra))
        if timl#equality#test(a:this.__extra[i], _.e)
          let a:this.__extra[i] = _.e
          let found = 1
          break
        endif
      endfor
      if !found
        call add(a:this.__extra, _.e)
      endif
    else
      let a:this[key] = _.e
    endif
  endfor
  return a:this
endfunction

function! timl#set#disj(this, ...) abort
  return timl#set#persistentb(call('timl#set#disjb', [timl#set#transient(a:this)] + a:000))
endfunction

function! timl#set#disjb(this, ...) abort
  let _ = {}
  for _.e in a:000
    let key = timl#set#key(_.e)
    if empty(key)
      for i in range(len(a:this.__extra))
        if timl#equality#test(a:this.__extra[i], _.e)
          call remove(a:this.__extra, i)
          break
        endif
      endfor
    elseif has_key(a:this, key)
      call remove(a:this, key)
    endif
  endfor
  return a:this
endfunction

function! timl#set#transient(this) abort
  let that = copy(a:this)
  let that.__extra = copy(a:this.__extra)
  return timl#type#bless(s:transient_type, that)
endfunction

function! timl#set#persistentb(this) abort
  let this = timl#type#bless(s:type, a:this)
  lockvar 1 a:this.__extra
  lockvar 1 a:this
  return a:this
endfunction

function! timl#set#call(this, _) abort
  return call('timl#set#lookup', [a:this] + a:_)
endfunction

let s:type = timl#type#core_define('HashSet', g:timl#nil, {
      \ 'seq': 'timl#set#seq',
      \ 'lookup': 'timl#set#lookup',
      \ 'empty': 'timl#set#empty',
      \ 'conj': 'timl#set#conj',
      \ 'length': 'timl#set#length',
      \ 'equiv': 'timl#set#equal',
      \ 'disj': 'timl#set#disj',
      \ 'transient': 'timl#set#transient',
      \ 'call': 'timl#set#call'})

let s:transient_type = timl#type#core_define('TransientHashSet', g:timl#nil, {
      \ 'length': 'timl#set#length',
      \ 'lookup': 'timl#set#lookup',
      \ 'conj!': 'timl#set#conjb',
      \ 'disj!': 'timl#set#disjb',
      \ 'persistent!': 'timl#set#persistentb'})

if !exists('s:empty')
  let s:empty = timl#type#bless(s:type, {'__extra': []})
  lockvar 1 s:empty.__extra
  lockvar 1 s:empty
endif


================================================
FILE: autoload/timl/string.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_string')
  finish
endif
let g:autoloaded_timl_string = 1

let s:type = type('')
function! timl#string#test(str) abort
  return type(a:str) == s:type
endfunction

function! timl#string#coerce(val) abort
  if type(a:val) == type('')
    return a:val
  elseif type(a:val) == type(0) || type(a:val) == 5
    return ''.a:val
  elseif timl#symbol#test(a:val) || timl#keyword#test(a:val)
    return a:val.str
  elseif timl#type#canp(a:val, g:timl#core.to_string)
    return timl#invoke(g:timl#core.to_string, a:val)
  else
    return '#<'.timl#type#string(a:val).'>'
  endif
endfunction

" Characters, not bytes
function! timl#string#lookup(this, idx, default) abort
  if type(a:idx) == type(0)
    let ch = matchstr(a:this, repeat('.', a:idx).'\zs.')
    return empty(ch) ? (a:0 ? a:1 : g:timl#nil) : ch
  endif
  return a:default
endfunction

function! timl#string#length(this) abort
  return exists('*strchars') ? strchars(a:this) : len(substitute(a:this, '.', '.', 'g'))
endfunction

function! timl#string#seq(this) abort
  return timl#array_seq#create(split(a:this, '\zs'))
endfunction

function! timl#string#join(sep_or_coll, ...) abort
  return join(
        \ map(copy(timl#array#coerce(a:0 ? a:1 : a:sep_or_coll)), 'timl#string#coerce(v:val)'),
        \ a:0 ? timl#string#coerce(a:sep_or_coll) : '')
endfunction

function! timl#string#split(s, re) abort
  return timl#vector#claim(split(a:s, '\C'.a:re))
endfunction

function! timl#string#replace(s, re, repl) abort
  return substitute(a:s, '\C'.a:re, a:repl, 'g')
endfunction

function! timl#string#replace_one(s, re, repl) abort
  return substitute(a:s, '\C'.a:re, a:repl, '')
endfunction

function! timl#string#re_quote_replacement(re) abort
  return escape(a:re, '\~&')
endfunction

function! timl#string#re_find(re, s) abort
  let result = matchlist(a:s, '\C'.a:re)
  return empty(result) ? g:timl#nil : timl#vector#claim(result)
endfunction

function! timl#string#sub(str, start, ...) abort
  if a:0 && a:1 <= a:start
    return ''
  elseif a:0
    return matchstr(a:str, '.\{,'.(a:1-a:start).'\}', byteidx(a:str, a:start))
  else
    return a:str[byteidx(a:str, a:start) :]
  endif
endfunction

function! timl#string#pr(_) abort
  return join(map(copy(a:_), 'timl#printer#string(v:val)'), ' ')
endfunction

function! timl#string#prn(_) abort
  return join(map(copy(a:_), 'timl#printer#string(v:val)'), ' ')."\n"
endfunction

function! timl#string#print(_) abort
  return join(map(copy(a:_), 'timl#string#coerce(v:val)'), ' ')
endfunction

function! timl#string#println(_) abort
  return join(map(copy(a:_), 'timl#string#coerce(v:val)'), ' ')."\n"
endfunction


================================================
FILE: autoload/timl/symbol.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_symbol")
  finish
endif
let g:autoloaded_timl_symbol = 1

if !exists('s:symbols')
  let s:symbols = {}
endif

function! timl#symbol#intern(str) abort
  if !has_key(s:symbols, a:str)
    let end = matchend(a:str, '^\%(&\=\w:\|\$\|&\%($\|form$\|env$\)\@!\|[^/]*/\).\@=')
    let symbol = timl#type#bless(s:type, {
          \ '0': a:str,
          \ 'str': a:str,
          \ 'meta': g:timl#nil,
          \ 'namespace': end == -1 ? '' : a:str[0 : end-(a:str[end-1] ==# '/' ? 2 : 1)],
          \ 'name': end == -1 ? a:str : a:str[end : -1]})
    lockvar 1 symbol
    let s:symbols[a:str] = symbol
  endif
  return s:symbols[a:str]
endfunction

function! timl#symbol#intern_with_meta(str, meta) abort
  let sym = copy(timl#symbol#intern(a:str))
  let sym.meta = a:meta
  return sym
endfunction

function! timl#symbol#test(symbol) abort
  return type(a:symbol) == type({}) &&
        \ get(a:symbol, '__type__') is# s:type
endfunction

function! timl#symbol#is(symbol, ...) abort
  return type(a:symbol) == type({}) &&
        \ get(a:symbol, '__type__') is# s:type &&
        \ (a:0 ? a:symbol[0] ==# a:1 : 1)
endfunction

function! timl#symbol#cast(symbol) abort
  if !timl#symbol#test(a:symbol)
    throw 'timl: symbol expected but received '.timl#type#string(a:symbol)
  endif
  return a:symbol
endfunction

function! timl#symbol#equal(this, that) abort
  return timl#symbol#test(a:that) && a:this[0] ==# a:that[0] ? g:timl#true : g:timl#false
endfunction

function! timl#symbol#gen(...) abort
  let s:id = get(s:, 'id', 0) + 1
  return timl#symbol((a:0 ? a:1 : 'G__').s:id)
endfunction

let s:type = timl#type#core_create('Symbol')


================================================
FILE: autoload/timl/test.tim
================================================
(ns timl.test)

(defmacro assert [form]
  `(try
     (if ~form
       true
       (echo "Failed: " (pr-str '~form)))
     (catch "" e# (echo "Error on " (pr-str '~form) ": " v:exception))))


================================================
FILE: autoload/timl/true.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists("g:autoloaded_timl_true")
  finish
endif
let g:autoloaded_timl_true = 1

if !exists('g:timl#true')
  let g:timl#true = timl#type#bless(timl#type#core_create('Boolean'), {'val': 1})
  lockvar 1 g:timl#true
endif

function! timl#true#identity() abort
  return g:timl#true
endfunction

function! timl#true#test(val) abort
  return a:val is# g:timl#true
endfunction


================================================
FILE: autoload/timl/type.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe>

if exists("g:autoloaded_timl_type")
  finish
endif
let g:autoloaded_timl_type = 1

function! s:freeze(...) abort
  return a:000
endfunction

if !exists('g:timl#nil')
  let g:timl#nil = s:freeze()
  lockvar 1 g:timl#nil
endif

" Section: Blessing

if !exists('g:timl_tag_sentinel')
  let g:timl_tag_sentinel = s:freeze('blessed object')
  lockvar 1 g:timl_tag_sentinel
endif

if !exists('s:types')
  let s:types = {}
endif

function! timl#type#find(name) abort
  return get(s:types, timl#string#coerce(a:name), g:timl#nil)
endfunction

function! timl#type#create(name, ...) abort
  let munged = tr(a:name, '-./', '_##')
  if !has_key(s:types, a:name)
    let s:types[a:name] = timl#type#bless(s:type_type, {
          \ 'str': a:name,
          \ 'location': 'g:'.munged,
          \ 'slots': g:timl#nil,
          \ '__call__': function('timl#type#constructor')})
  endif
  let s:types[a:name].slots = a:0 ? a:1 : g:timl#nil
  let g:{munged} = s:types[a:name]
  return s:types[a:name]
endfunction

function! timl#type#core_create(name, ...) abort
  return timl#type#create('timl.lang/'.a:name, a:0 ? a:1 : g:timl#nil)
endfunction

function! timl#type#core_define(name, slots, methods) abort
  let ns = timl#namespace#create(timl#symbol#intern('timl.core'))
  let type = timl#type#core_create(a:name, a:slots)
  for [k, v] in items(a:methods)
    call timl#type#define_method(ns, timl#symbol#intern(k), type, function(v))
  endfor
  return type
endfunction

function! timl#type#constructor(_) dict abort
  if get(self, 'slots') is# g:timl#nil
    throw 'timl: constructor not implemented'
  endif
  if len(a:_) != len(self.slots)
    throw 'timl: arity error'
  endif
  let object = {}
  for i in range(len(a:_))
    let object[self.slots[i]] = a:_[i]
  endfor
  return timl#type#bless(self, object)
endfunction

if !has_key(s:types, 'timl.lang/Type')
  let s:types['timl.lang/Type'] = {
        \ 'str': 'timl.lang/Type',
        \ 'location': 'g:timl#lang#Type',
        \ 'slots': g:timl#nil,
        \ '__call__': function('timl#type#constructor')}
endif
let s:type_type = s:types['timl.lang/Type']
function! timl#type#define(ns, var, slots) abort
  let str = timl#namespace#name(a:ns).name . '/' . timl#symbol#cast(a:var).name
  let type = timl#type#create(str)
  if a:slots isnot# g:timl#nil
    let type.slots = map(timl#array#coerce(a:slots), 'timl#symbol#cast(v:val).name')
  endif
  return timl#namespace#intern(a:ns, a:var, type)
endfunction

let s:builtins = {
      \ 0: 'vim/Number',
      \ 1: 'vim/String',
      \ 2: 'vim/Funcref',
      \ 3: 'vim/List',
      \ 4: 'vim/Dictionary',
      \ 5: 'vim/Float'}

function! timl#type#objectp(obj) abort
  return type(a:obj) == type({}) && get(a:obj, '__flag__') is g:timl_tag_sentinel
endfunction

function! timl#type#string(val) abort
  let type = get(s:builtins, type(a:val), 'vim/Unknown')
  if a:val is# g:timl#nil
    return 'timl.lang/Nil'
  elseif type ==# 'vim/Dictionary'
    if get(a:val, '__flag__') is g:timl_tag_sentinel
      return a:val.__type__.str
    endif
  endif
  return type
endfunction

let s:proto = {
      \ '__call__': function('timl#type#dispatch_call'),
      \ '__flag__': g:timl_tag_sentinel}
function! timl#type#bless(type, ...) abort
  let obj = a:0 ? a:1 : {}
  call extend(obj, s:proto, 'keep')
  let obj.__type__ = a:type
  return obj
endfunction

function! timl#type#dispatch_call(_) dict
  return g:timl#core.call.__call__([self, a:_])
endfunction

call timl#type#bless(s:type_type, s:type_type)

" Section: Hierarchy
" Cribbed from clojure.core

function! timl#type#parents(key) abort
  return timl#set#coerce(values(get(g:timl_hierarchy.parents, timl#string#coerce(a:key), {})))
endfunction

function! timl#type#ancestors(key) abort
  return timl#set#coerce(values(get(g:timl_hierarchy.ancestors, timl#string#coerce(a:key), {})))
endfunction

function! timl#type#descendants(key) abort
  return timl#set#coerce(values(get(g:timl_hierarchy.descendants, timl#string#coerce(a:key), {})))
endfunction

function! s:tf(m, source, sources, target, targets) abort
  for k in [a:source] + values(get(a:sources, a:source[0], {}))
    if !has_key(a:targets, k[0])
      let a:targets[k[0]] = {}
    endif
    let a:targets[k[0]][a:target[0]] = a:target
    for j in values(get(a:targets, a:target[0], {}))
      let a:targets[k[0]][j[0]] = j
    endfor
  endfor
endfunction

function! s:isap(tag, parent) abort
  return a:tag ==# a:parent || has_key(get(g:timl_hierarchy.ancestors, a:tag, {}), a:parent)
endfunction

function! timl#type#isap(tag, parent) abort
  return timl#keyword#cast(a:tag) is# timl#keyword#cast(a:parent)
        \ || has_key(get(g:timl_hierarchy.ancestors, a:tag[0], {}), a:parent[0])
endfunction

function! timl#type#derive(tag, parent) abort
  let tp = g:timl_hierarchy.parents
  let td = g:timl_hierarchy.descendants
  let ta = g:timl_hierarchy.ancestors
  let tag = timl#keyword#cast(a:tag)
  let parent = timl#keyword#cast(a:parent)
  if !has_key(tp, tag[0])
    let tp[tag[0]] = {}
  endif
  if !has_key(tp[tag[0]], parent[0])
    if has_key(get(ta, tag[0], {}), parent[0])
      throw "timl#type: :".tag[0]." already has :".parent[0]." as ancestor"
    endif
    if has_key(get(ta, parent[0], {}), tag[0])
      throw "timl#type: :".parent[0]." has :".tag[0]." as ancestor"
    endif
    let tp[tag[0]][parent[0]] = parent
    call s:tf(ta, tag, td, parent, ta)
    call s:tf(td, parent, ta, tag, td)
  endif
  let g:timl_hierarchy = copy(g:timl_hierarchy) " expire caches
  return g:timl_hierarchy
endfunction

" Section: Dispatch

function! timl#type#canp(obj, this) abort
  return s:get_method(a:this, timl#type#string(a:obj)) isnot# g:timl#nil
endfunction

function! s:get_method(this, type) abort
  if a:this.hierarchy isnot# g:timl_hierarchy
    let a:this.cache = {}
    let a:this.hierarchy = g:timl_hierarchy
  endif
  if !has_key(a:this.cache, a:type)
    let _ = {'preferred': g:timl#nil}
    for [_.type, _.fn] in items(a:this.methods)
      if s:isap(a:type, _.type)
        if _.preferred is g:timl#nil || s:isap(_.type, _.preferred[0])
          let _.preferred = [_.type, _.fn]
        elseif !s:isap(_.preferred[0], _.type)
          throw 'timl#type: ambiguous'
        endif
      endif
    endfor
    if _.preferred is# g:timl#nil
      let a:this.cache[a:type] = get(a:this.methods, ' ', g:timl#nil)
    else
      let a:this.cache[a:type] = _.preferred[1]
    endif
  endif
  return get(a:this.cache, a:type, g:timl#nil)
endfunction

let s:t_function = type(function('tr'))
let s:t_dict = type({})
function! timl#type#apply(_) dict abort
  let type = timl#type#string(a:_[0])
  if self.hierarchy isnot# g:timl_hierarchy
    let self.cache = {}
    let self.hierarchy = g:timl_hierarchy
  endif
  let Dispatch = has_key(self.cache, type) ? self.cache[type] : s:get_method(self, type)
  let t = type(Dispatch)
  if t == s:t_function
    return call(Dispatch, a:_)
  elseif t == s:t_dict
    return Dispatch.__call__(a:_)
  endif
  throw 'timl#type: no '.self.ns.__name__[0].'/'.self.name[0].' dispatch for '.type
endfunction

function! timl#type#dispatch(this, _) abort
  return call('timl#type#apply', [a:_], a:this)
endfunction

" Section: Method Creation

function! timl#type#define_method(ns, name, type, fn) abort
  let var = timl#namespace#maybe_resolve(a:ns, timl#symbol#cast(a:name))
  if var is# g:timl#nil || timl#type#string(timl#var#get(var)) isnot# 'timl.lang/MultiFn'
    unlet var
    if !empty(a:name.namespace)
      throw "timl: no such method ".a:name.str
    endif
    let fn = timl#type#bless(s:multifn_type, {
          \ '__call__': function('timl#type#apply'),
          \ 'ns': a:ns,
          \ 'name': a:name,
          \ 'cache': {},
          \ 'hierarchy': g:timl_hierarchy,
          \ 'methods': {}})
    let var = timl#namespace#intern(a:ns, a:name, fn)
  endif
  let multi = timl#var#get(var)
  let multi.methods[a:type is# g:timl#nil ? ' ' : a:type.str] = a:fn
  let multi.cache = {}
  return var
endfunction
let s:multifn_type = timl#type#core_create('MultiFn')

" Section: Initialization

if !exists('g:timl_hierarchy')
  let g:timl_hierarchy = {'parents': {}, 'descendants': {}, 'ancestors': {}}
endif

" vim:set et sw=2:


================================================
FILE: autoload/timl/var.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_var')
  finish
endif
let g:autoloaded_timl_var = 1

function! timl#var#get(var) abort
  return eval(a:var.location)
endfunction

function! timl#var#call(var, _) abort
  return timl#call(eval(a:var.location), a:_)
endfunction

function! timl#var#test(this) abort
  return timl#type#string(a:this) ==# 'timl.lang/Var'
endfunction

function! timl#var#find(sym) abort
  let sym = timl#symbol#cast(a:sym)
  let ns = empty(sym.namespace) ? timl#namespace#name(g:timl#core._STAR_ns_STAR_).str : sym.namespace
  return get(timl#namespace#find(ns).__mappings__, sym.name, g:timl#nil)
endfunction

function! timl#var#funcref(var) abort
  return function(a:var.munged)
endfunction

function! timl#var#reset_meta(var, meta) abort
  let a:var.meta = a:meta
  return a:var
endfunction

" Section: Munging

" From clojure/lang/Compiler.java
let s:munge = {
      \ '.': "#",
      \ ',': "_COMMA_",
      \ ':': "_COLON_",
      \ '+': "_PLUS_",
      \ '>': "_GT_",
      \ '<': "_LT_",
      \ '=': "_EQ_",
      \ '~': "_TILDE_",
      \ '!': "_BANG_",
      \ '@': "_CIRCA_",
      \ "'": "_SINGLEQUOTE_",
      \ '"': "_DOUBLEQUOTE_",
      \ '%': "_PERCENT_",
      \ '^': "_CARET_",
      \ '&': "_AMPERSAND_",
      \ '*': "_STAR_",
      \ '|': "_BAR_",
      \ '{': "_LBRACE_",
      \ '}': "_RBRACE_",
      \ '[': "_LBRACK_",
      \ ']': "_RBRACK_",
      \ '/': "_SLASH_",
      \ '\\': "_BSLASH_",
      \ '?': "_QMARK_"}

let s:demunge = {}
for s:key in keys(s:munge)
  let s:demunge[s:munge[s:key]] = s:key
endfor
unlet! s:key

function! timl#var#munge(var) abort
  let var = type(a:var) == type('') ? a:var : a:var[0]
  return tr(substitute(substitute(var, '[^[:alnum:]:#_-]', '\=get(s:munge,submatch(0), submatch(0))', 'g'), '_SLASH_\ze.', '.', ''), '-', '_')
endfunction

function! timl#var#demunge(var) abort
  let var = type(a:var) == type('') ? a:var : a:var[0]
  return tr(substitute(var, '_\(\u\+\)_', '\=get(s:demunge, submatch(0), submatch(0))', 'g'), '_', '-')
endfunction


================================================
FILE: autoload/timl/vector.vim
================================================
" Maintainer: Tim Pope <http://tpo.pe/>

if exists('g:autoloaded_timl_vector')
  finish
endif
let g:autoloaded_timl_vector = 1

function! timl#vector#test(obj) abort
  return timl#type#canp(a:obj, g:timl#core.nth)
endfunction

let s:type = timl#type#core_create('Vector')
function! timl#vector#claim(array) abort
  lockvar 1 a:array
  let vector = timl#type#bless(s:type, {'array': a:array})
  lockvar 1 vector
  return vector
endfunction

function! timl#vector#coerce(seq) abort
  if a:seq is# g:timl#nil
    return s:empty
  elseif type(a:seq) ==# type([])
    return timl#vector#claim(copy(a:seq))
  elseif timl#type#string(a:seq) ==# s:type.str
    return a:seq
  endif
  let array = []
  let _ = {'seq': timl#coll#seq(a:seq)}
  while _.seq isnot# g:timl#nil
    call add(array, timl#coll#first(_.seq))
    let _.seq = timl#coll#next(_.seq)
  endwhile
  return timl#vector#claim(array)
endfunction

function! timl#vector#seq(this) abort
  return timl#array#seq(a:this.array)
endfunction

function! timl#vector#length(this) abort
  return len(a:this.array)
endfunction

function! timl#vector#car(this) abort
  return get(a:this.array, 0, g:timl#nil)
endfunction

function! timl#vector#cdr(this) abort
  return len(a:this.array) <= 1 ? g:timl#empty_list : timl#array_seq#create(a:this.array, 1)
endfunction

function! timl#vector#lookup(this, idx, ...) abort
  if type(a:idx) == type(0) && a:idx >= 0
    return get(a:this.array, a:idx, a:0 ? a:1 : g:timl#nil)
  endif
  return a:0 ? a:1 : g:timl#nil
endfunction

function! timl#vector#nth(this, idx, ...) abort
  let idx = timl#number#int(a:idx)
  if a:0
    return get(a:this.array, idx, a:1)
  else
    return a:this.array[idx]
  endif
endfunction

function! timl#vector#conj(this, ...) abort
  return timl#vector#claim(a:this.array + a:000)
endfunction

let s:empty = timl#vector#claim([])
function! timl#vector#empty(this) abort
  return s:empty
endfunction

function! timl#vector#transient(this) abort
  return copy(a:this.array)
endfunction

function! timl#vector#sub(this, start, ...) abort
  let array = timl#vector#coerce(a:this).array
  if a:0 && a:1 == 0
    return s:empty
  elseif a:0
    return timl#vector#claim(array[a:start : (a:1 < 0 ? a:1 : a:1-1)])
  else
    return timl#vector#claim(array[a:start :])
  endif
endfunction

function! timl#vector#call(this, _) abort
  return call('timl#vector#lookup', [a:this] + a:_)
endfunction


================================================
FILE: autoload/timl.vim
================================================
" Maintainer:   Tim Pope <http://tpo.pe/>

if exists("g:autoloaded_timl")
  finish
endif
let g:autoloaded_timl = 1

" Section: Util {{{1

function! timl#truth(val) abort
  return a:val isnot# g:timl#nil && a:val isnot# g:timl#false
endfunction

function! timl#keyword(str) abort
  return timl#keyword#intern(a:str)
endfunction

function! timl#symbol(str) abort
  return timl#symbol#intern(a:str)
endfunction

" }}}1
" Section: Lists {{{1

function! timl#seq(coll) abort
  return timl#coll#seq(a:coll)
endfunction

function! timl#first(coll) abort
  return timl#coll#first(a:coll)
endfunction

function! timl#rest(coll) abort
  return timl#coll#rest(a:coll)
endfunction

function! timl#next(coll) abort
  return timl#coll#seq(timl#coll#rest(rest))
endfunction

function! timl#list(...) abort
  return timl#list#create(a:000)
endfunction

" }}}1
" Section: Invocation {{{1

function! timl#call(Func, args, ...) abort
  if type(a:Func) == type(function('tr'))
    return call(a:Func, a:args, a:0 ? a:1 : {})
  else
    return a:Func.__call__(a:args)
  endif
endfunction

function! timl#invoke(Func, ...) abort
  if type(a:Func) == type(function('tr'))
    return call(a:Func, a:000, {})
  else
    return a:Func.__call__(a:000)
  endif
endfunction

" }}}1
" Section: Evaluation {{{1

function! timl#eval(x) abort
  return timl#loader#eval(a:x)
endfunction

function! timl#re(str) abort
  return timl#eval(timl#reader#read_string(a:str))
endfunction

function! timl#rep(str) abort
  return timl#printer#string(timl#re(a:str))
endfunction

" }}}1

runtime! autoload/timl/bootstrap.vim

" vim:set et sw=2:


================================================
FILE: doc/timl.txt
================================================
*timl.txt*  TimL

Author:  Tim Pope <http://tpo.pe/>
Repo:    https://github.com/tpope/timl
License: EPL (http://opensource.org/licenses/eclipse-1.0.php)

USAGE                                           *timl*

TimL files have an extension of ".tim" and a |filetype| of "timl".  If they
are placed in "autoload/" in 'runtimepath', Vim's |autoload| will load them
just the same as ".vim" files.

                                                *:TLrepl*
:TLrepl [ns]            Start a REPL.

:source {file}          Load a TimL file.

:Wepl                   In a TimL file, write, source, and start a REPL in
                        that namespace.

SYNTAX                                          *timl-syntax*

It's Lisp.  TimL files are just sequences of forms.  Evaluation essentially
entails replacing symbols with their values and lists with the result of
calling the first element as function with the remaining elements as
arguments.  An informal summary of the various forms follows:

Notation    Description ~
;           linewise comment
#!          linewise comment (for shebangs)
#_          skip next form
nil         |timl-nil|
false       |timl-boolean|
true        |timl-boolean|
\d...       |timl-number| (see |expr-number|)
\k...       |timl-symbol|
:...        |timl-keyword|
"..."       |timl-string| (see double quoted strings under |expr-string|)
#"..."      |timl-regexp|
(...)       |timl-list|
[...]       |timl-vector|
{...}       |timl-map|
#{...}      |timl-set|
#(...)      |timl-fn|
#*symbol    |timl-funcref|
#*[...]     |timl-array|
#*{...}     |timl-dictionary|
^...        |timl-metadata|
'           |timl-quote|
`           |timl-syntax-quote|
~           |timl-unquote|
~@          |timl-unquote-splicing|
@           |g:timl#core.deref|

TYPES                                           *timl-types*

                                                *timl-number*
Numbers ~
Same as Vim. See |expr-number|.

                                                *timl-strings*
Strings ~
Same as strings in Vim.  The literal syntax is the same as the double quoted
strings under |expr-string|.

                                                *timl-regexps*
Regular Expressions ~
There's not a proper regexp type, but #"..." compiles down to a string of a
very magic |/\v| case sensitive |\/C| regexp string.  Unlike with regular
string literals, you don't need to double your backslashes.

                                                *timl-arrays*
Arrays ~
TimL arrays are actually Vim |Lists|.  They have been rebranded arrays to
avoid confusion with the core Lisp data structure of a singly linked list.
Arrays participate in the expected collection abstractions, but be aware they
mutate, and thus are best avoided except when dealing with interop.

Arrays are shown as #*[...] when printed.  The reader respects this syntax,
but it is preferrable to use |g:timl#core.array| to create a array.

                                *timl-dictionary* *timl-dictionaries*
Dictionaries ~
TimL dictionaries are Vim |Dictionaries|.  TimL uses dictionaries in the
implementation of its type system, so "TimL dictionary" refers to a dictionary
that has not been blessed as any particular type.  Dictionaries can be treated
as maps with forced string keys.

Dictionaries are shown as #*{...} when printed.  The reader respects this
syntax, but it is preferrable to use |g:timl#core.dict| to create a
dictionary.

                                                *timl-funcrefs*
Funcrefs ~
TimL provides a special #*symbol syntax for creating a Vim |Funcref|.
Funcrefs can be called like any other function: (#*bufnr "%").  Vim imposes
certain restrictions on assigning funcrefs to variables, so beware of using
them with |timl-set!| and |timl-def|.

                                                *timl-nil*
Nil ~
VimL has no concept of nil, so this is actually just a special singleton
object.  The literal form is "nil".

                                                *timl-booleans*
Booleans ~
Booleans are the canonical truth values.  There's a literal for each: "true"
and "false".  Nil and false are the only false values in TimL.  Note that in
VimL, zero is false, and built-in Vim functions return that as their false
value.  Compose with |g:timl#core.nonzero_QMARK_| if you want to use the
result of a built-in Vim function in a conditional.

                                                *timl-symbols*
Symbols ~
Any sequence of identifier characters that doesn't start with a number.
Identifier characters include alphanumerics and the special characters
"-_?!*+/<>".  ":" and "#" are reserved for internal use and can be used to
refer to Vim variables (|b:var,| |w:var|, |t:var|, |g:var|, |v:var|).

Since symbols evaluate, you'll need to |timl-quote| one if you want it as a
value: 'symbol.

                                                *timl-keywords*
Keywords ~
Keywords look like symbols preceded by a colon.  Unlike symbols, they evaluate
to themselves, making them good |timl-map| keys.  Calling a keyword as a
function tries to retrieve it from the given collection using
|g:timl#core.get|.

                                                *timl-lists*
Lists ~
Lists are linked lists under the hood, and have a syntax literal of zero or more forms enclosed in parentheses ().  Lists evaluate to a function
call of the first element with the remaining elements as args.  To create a
list value, |timl-quote| it (also prevents evaluation of elements) or use
|g:timl#core.list|.

                                                *timl-vectors*
Vectors ~
An ordered, indexed collection intended for random access.  Created literally
by enclosing zero or more forms in brackets.  Evaluates to a new vector of the
evaluation of the contained elements.

                                                *timl-maps*
Maps ~
Maps are associative, unordered collections.  The syntax literal is {...}.
The definining method of a map is |g:timl#core.dissoc|.

                                                *timl-sets*
Sets ~
A set is an unordered collection of values, and can be thought of as a map
where the keys and values are the same.  The syntax literal is #{...}.  The
defining method of a set is |g:timl#core.disj|.

EVALUATION                                      *timl-evaluation*

It's Lisp.

Symbols evaluate to their value in lexical scope (from let or fn) or the
current namespace.  Symbols evaluating to special forms are handled as
explained under |timl-special-forms|.

Lists evaluate to a function call.  Dictionaries evaluate their
values.  Everything else evaluates to itself.

SPECIAL FORMS                                   *timl-special-forms*

                                                *timl-if*
(if {cond} {then} {else}?) ~
If {cond} is true, evaluate {then}, else evaluate {else}.

                                                *timl-do*
(do {form} ...) ~
Evaluate a series of forms and return the result of the last one.

                                                *timl-let*
(let [{symbol} {value} ...] {body} ...) ~
Bind the given symbols lexically for the scope of the given body.

                                                *timl-fn*
(fn {name}? [{param} ...] {body} ...) ~
#(... % %2 %3 ... %&) ~
Create an anonymous function.

                                                *timl-recur*
In tail position, re-calls the current function or |timl#core#loop| construct
with the given parameters.  See Clojure's documentation at
http://clojure.org/special_forms#recur .

                                                *timl-def*
(def {var} {value}) ~
Define a variable or function.

                                                *timl-set!*
(set! {var} {value}) ~
Set a Vim variable, in a manner similar to |:let|.  |g:var|, |b:var|, |w:var|,
|t:var|, |v:var|, |expr-option|, and variables in the current namespace are
supported. >
        (set! b:did_ftplugin 1)
        (set! &shiftwidth 2)
        (set! *ns* (the-ns 'user))
<
                                                *timl-quote*
(quote {form}) ~
'{form} ~
Return {form} unevaluated.

                                                *timl-function*
(function {form}) ~
#*{form} ~
Return a |Funcref| for a built-in or user defined Vim function.  Can be called
like any other function.

                                        *timl-try* *timl-catch* *timl-finally*
(try {body} ... (catch {pattern} {e} {body} ...) ... (finally {body} ...) ...) ~
Wrap a set of forms in a |:try| block.  The {pattern} is a regexp to match
the string exception as explained under |:catch|, or can also be a Vim error
number.  You can access |v:exception| and |v:throwpoint| for information about
the exception, or look in dictionary {e}.

                                                *timl-throw*
(throw {string}) ~
Pass the given {string} to |:throw|.

                                                *timl-execute*
(execute {string}) ~
Run the given string with |:execute|.

                                                *timl-.* *timl-dot*
(. {dict} -{key}) ~
Retrieve the given key of the given dict.

NAMESPACES                                      *timl-namespaces* *timl-ns*

Namespaces take the Clojure model and adapt it to fit the VimL |autoload|
feature.
>
        (ns foo.bar)
        (def baz 1)
        (in-ns 'user)
        foo.bar/baz            ; evaluates to 1
        (alias 'quux 'foo.bar)
        quux/baz               ; evaluates to 1
        (refer 'foo.bar)
        baz                    ; evaluates to 1
<
You can also use the ns macro from Clojure.
>
        (ns my.ns
          (:refer-timl :exclude [+])
          (:use timl.repl)
          (:require [timl.file :as file]))
<
TimL files placed in the |autoload| directory will automatically be loaded in
the correct namespace.

 vim:tw=78:et:ft=help:norl:


================================================
FILE: doc/timl_core.txt
================================================
                                                *g:timl#core.array*
(timl.core/array & elems)       Create a |timl-array| containing elems.

                                                *g:timl#core.dict*
(timl.core/dict map)            Convert a map to a |timl-dictionary|.
(timl.core/dict keyvals)        Create a |timl-dictionary| from keyvals.
(timl.core/dict & keyvals)      Create a |timl-dictionary| from keyvals.

 vim:tw=78:sw=8:et:ft=help:norl:


================================================
FILE: epl-v10.html
================================================
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Eclipse Public License - Version 1.0</title>
<style type="text/css">
  body {
    size: 8.5in 11.0in;
    margin: 0.25in 0.5in 0.25in 0.5in;
    tab-interval: 0.5in;
    }
  p {
    margin-left: auto;
    margin-top:  0.5em;
    margin-bottom: 0.5em;
    }
  p.list {
    margin-left: 0.5in;
    margin-top:  0.05em;
    margin-bottom: 0.05em;
    }
  </style>

</head>

<body lang="EN-US">

<p align=center><b>Eclipse Public License - v 1.0</b></p>

<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE, REPRODUCTION OR
DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS
AGREEMENT.</p>

<p><b>1. DEFINITIONS</b></p>

<p>&quot;Contribution&quot; means:</p>

<p class="list">a) in the case of the initial Contributor, the initial
code and documentation distributed under this Agreement, and</p>
<p class="list">b) in the case of each subsequent Contributor:</p>
<p class="list">i) changes to the Program, and</p>
<p class="list">ii) additions to the Program;</p>
<p class="list">where such changes and/or additions to the Program
originate from and are distributed by that particular Contributor. A
Contribution 'originates' from a Contributor if it was added to the
Program by such Contributor itself or anyone acting on such
Contributor's behalf. Contributions do not include additions to the
Program which: (i) are separate modules of software distributed in
conjunction with the Program under their own license agreement, and (ii)
are not derivative works of the Program.</p>

<p>&quot;Contributor&quot; means any person or entity that distributes
the Program.</p>

<p>&quot;Licensed Patents&quot; mean patent claims licensable by a
Contributor which are necessarily infringed by the use or sale of its
Contribution alone or when combined with the Program.</p>

<p>&quot;Program&quot; means the Contributions distributed in accordance
with this Agreement.</p>

<p>&quot;Recipient&quot; means anyone who receives the Program under
this Agreement, including all Contributors.</p>

<p><b>2. GRANT OF RIGHTS</b></p>

<p class="list">a) Subject to the terms of this Agreement, each
Contributor hereby grants Recipient a non-exclusive, worldwide,
royalty-free copyright license to reproduce, prepare derivative works
of, publicly display, publicly perform, distribute and sublicense the
Contribution of such Contributor, if any, and such derivative works, in
source code and object code form.</p>

<p class="list">b) Subject to the terms of this Agreement, each
Contributor hereby grants Recipient a non-exclusive, worldwide,
royalty-free patent license under Licensed Patents to make, use, sell,
offer to sell, import and otherwise transfer the Contribution of such
Contributor, if any, in source code and object code form. This patent
license shall apply to the combination of the Contribution and the
Program if, at the time the Contribution is added by the Contributor,
such addition of the Contribution causes such combination to be covered
by the Licensed Patents. The patent license shall not apply to any other
combinations which include the Contribution. No hardware per se is
licensed hereunder.</p>

<p class="list">c) Recipient understands that although each Contributor
grants the licenses to its Contributions set forth herein, no assurances
are provided by any Contributor that the Program does not infringe the
patent or other intellectual property rights of any other entity. Each
Contributor disclaims any liability to Recipient for claims brought by
any other entity based on infringement of intellectual property rights
or otherwise. As a condition to exercising the rights and licenses
granted hereunder, each Recipient hereby assumes sole responsibility to
secure any other intellectual property rights needed, if any. For
example, if a third party patent license is required to allow Recipient
to distribute the Program, it is Recipient's responsibility to acquire
that license before distributing the Program.</p>

<p class="list">d) Each Contributor represents that to its knowledge it
has sufficient copyright rights in its Contribution, if any, to grant
the copyright license set forth in this Agreement.</p>

<p><b>3. REQUIREMENTS</b></p>

<p>A Contributor may choose to distribute the Program in object code
form under its own license agreement, provided that:</p>

<p class="list">a) it complies with the terms and conditions of this
Agreement; and</p>

<p class="list">b) its license agreement:</p>

<p class="list">i) effectively disclaims on behalf of all Contributors
all warranties and conditions, express and implied, including warranties
or conditions of title and non-infringement, and implied warranties or
conditions of merchantability and fitness for a particular purpose;</p>

<p class="list">ii) effectively excludes on behalf of all Contributors
all liability for damages, including direct, indirect, special,
incidental and consequential damages, such as lost profits;</p>

<p class="list">iii) states that any provisions which differ from this
Agreement are offered by that Contributor alone and not by any other
party; and</p>

<p class="list">iv) states that source code for the Program is available
from such Contributor, and informs licensees how to obtain it in a
reasonable manner on or through a medium customarily used for software
exchange.</p>

<p>When the Program is made available in source code form:</p>

<p class="list">a) it must be made available under this Agreement; and</p>

<p class="list">b) a copy of this Agreement must be included with each
copy of the Program.</p>

<p>Contributors may not remove or alter any copyright notices contained
within the Program.</p>

<p>Each Contributor must identify itself as the originator of its
Contribution, if any, in a manner that reasonably allows subsequent
Recipients to identify the originator of the Contribution.</p>

<p><b>4. COMMERCIAL DISTRIBUTION</b></p>

<p>Commercial distributors of software may accept certain
responsibilities with respect to end users, business partners and the
like. While this license is intended to facilitate the commercial use of
the Program, the Contributor who includes the Program in a commercial
product offering should do so in a manner which does not create
potential liability for other Contributors. Therefore, if a Contributor
includes the Program in a commercial product offering, such Contributor
(&quot;Commercial Contributor&quot;) hereby agrees to defend and
indemnify every other Contributor (&quot;Indemnified Contributor&quot;)
against any losses, damages and costs (collectively &quot;Losses&quot;)
arising from claims, lawsuits and other legal actions brought by a third
party against the Indemnified Contributor to the extent cause
Download .txt
gitextract_hyaf864a/

├── .gitignore
├── README.markdown
├── autoload/
│   ├── timl/
│   │   ├── array.vim
│   │   ├── array_seq.vim
│   │   ├── atom.vim
│   │   ├── bootstrap.vim
│   │   ├── buffer.tim
│   │   ├── chunked_cons.vim
│   │   ├── coll.vim
│   │   ├── compiler.vim
│   │   ├── cons.vim
│   │   ├── core.tim
│   │   ├── core_basics.tim
│   │   ├── core_coll.tim
│   │   ├── core_macros.tim
│   │   ├── core_ref.tim
│   │   ├── core_seq.tim
│   │   ├── core_vim.tim
│   │   ├── delay.vim
│   │   ├── dictionary.vim
│   │   ├── equality.vim
│   │   ├── exception.vim
│   │   ├── false.vim
│   │   ├── file.tim
│   │   ├── ftplugin.tim
│   │   ├── funcref.vim
│   │   ├── function.vim
│   │   ├── future.vim
│   │   ├── hash.vim
│   │   ├── indent.tim
│   │   ├── inst.vim
│   │   ├── interactive.vim
│   │   ├── io.vim
│   │   ├── keyword.vim
│   │   ├── lazy_seq.vim
│   │   ├── list.vim
│   │   ├── loader.vim
│   │   ├── map.vim
│   │   ├── meta.vim
│   │   ├── namespace.vim
│   │   ├── nil.vim
│   │   ├── number.vim
│   │   ├── plugin_helper.tim
│   │   ├── printer.vim
│   │   ├── reader.vim
│   │   ├── repl.tim
│   │   ├── set.vim
│   │   ├── string.vim
│   │   ├── symbol.vim
│   │   ├── test.tim
│   │   ├── true.vim
│   │   ├── type.vim
│   │   ├── var.vim
│   │   └── vector.vim
│   └── timl.vim
├── doc/
│   ├── timl.txt
│   └── timl_core.txt
├── epl-v10.html
├── ftplugin/
│   └── timl.tim
├── indent/
│   └── timl.tim
├── plugin/
│   └── timl.vim
├── syntax/
│   └── timl.vim
└── test/
    └── timl/
        ├── core_coll_test.tim
        ├── core_test.tim
        └── number_test.tim
Condensed preview — 65 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (222K chars).
[
  {
    "path": ".gitignore",
    "chars": 10,
    "preview": "/doc/tags\n"
  },
  {
    "path": "README.markdown",
    "chars": 3978,
    "preview": "# Welcome to the future (of the past)\n\nTimL is a Lisp dialect implemented in and compiling down to VimL, the\nscripting l"
  },
  {
    "path": "autoload/timl/array.vim",
    "chars": 2269,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_array')\n  finish\nendif\nlet g:autoloaded_timl_array"
  },
  {
    "path": "autoload/timl/array_seq.vim",
    "chars": 1672,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_array_seq\")\n  finish\nendif\nlet g:autoloaded_timl_ar"
  },
  {
    "path": "autoload/timl/atom.vim",
    "chars": 1864,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_atom\")\n  finish\nendif\nlet g:autoloaded_timl_atom = "
  },
  {
    "path": "autoload/timl/bootstrap.vim",
    "chars": 14495,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists(\"g:autoloaded_timl_bootstrap\")\n  finish\nendif\nlet g:autoloaded_timl_b"
  },
  {
    "path": "autoload/timl/buffer.tim",
    "chars": 359,
    "preview": "(ns timl.buffer)\n\n(deftype Buffer [nr])\n\n(defmethod lookup Buffer [self key not-found]\n  (get (#*getbufvar (. self nr) \""
  },
  {
    "path": "autoload/timl/chunked_cons.vim",
    "chars": 1834,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_chunked_cons\")\n  finish\nendif\nlet g:autoloaded_timl"
  },
  {
    "path": "autoload/timl/coll.vim",
    "chars": 4226,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:timl_autoloaded_coll')\n  finish\nendif\nlet g:timl_autoloaded_coll ="
  },
  {
    "path": "autoload/timl/compiler.vim",
    "chars": 26278,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_compiler')\n  finish\nendif\nlet g:autoloaded_timl_co"
  },
  {
    "path": "autoload/timl/cons.vim",
    "chars": 1625,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_cons\")\n  finish\nendif\nlet g:autoloaded_timl_cons = "
  },
  {
    "path": "autoload/timl/core.tim",
    "chars": 4858,
    "preview": "(in-ns 'timl.core)\n\n(defmacro lazy-seq [& body]\n  (list '#*timl#lazy_seq#create (cons 'fn* (cons [] body))))\n\n(defmacro "
  },
  {
    "path": "autoload/timl/core_basics.tim",
    "chars": 732,
    "preview": "(in-ns 'timl.core)\n\n(declare *1 *2 *3 *e)\n\n(defn not [x] (if x false true))\n\n(defn eval [form] (#*timl#eval form))\n\n(def"
  },
  {
    "path": "autoload/timl/core_coll.tim",
    "chars": 649,
    "preview": "(in-ns 'timl.core)\n\n(defn to-array [x] (#*timl#array#coerce x))\n\n(defn find [m k] (when (contains? m k) [k (get m k)]))\n"
  },
  {
    "path": "autoload/timl/core_macros.tim",
    "chars": 1639,
    "preview": "(in-ns 'timl.core)\n\n(defmacro defonce [name expr]\n  `(when-not (exists? (munge (str \"g:\" (ns-name *ns*) \"#\" '~name)))\n  "
  },
  {
    "path": "autoload/timl/core_ref.tim",
    "chars": 270,
    "preview": "(in-ns 'timl.core)\n\n(defn atom\n  ([state] (#*timl#atom#create state nil nil))\n  ([state & {v :validator m :meta}] (#*tim"
  },
  {
    "path": "autoload/timl/core_seq.tim",
    "chars": 1588,
    "preview": "(in-ns 'timl.core)\n\n(defn not-empty [xs] (when (seq xs) xs))\n\n(defn filter [pred coll]\n  (lazy-seq\n    (loop [s (seq col"
  },
  {
    "path": "autoload/timl/core_vim.tim",
    "chars": 554,
    "preview": "(in-ns 'timl.core)\n\n(defn stacklist []\n  (drop 1 (#*timl#exception#loclist (#*expand \"<sfile>\"))))\n\n(defmacro with-cwd ["
  },
  {
    "path": "autoload/timl/delay.vim",
    "chars": 844,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_delay\")\n  finish\nendif\nlet g:autoloaded_timl_delay "
  },
  {
    "path": "autoload/timl/dictionary.vim",
    "chars": 2953,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_dictionary\")\n  finish\nendif\nlet g:autoloaded_timl_d"
  },
  {
    "path": "autoload/timl/equality.vim",
    "chars": 1404,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_equality')\n  finish\nendif\nlet g:autoloaded_timl_eq"
  },
  {
    "path": "autoload/timl/exception.vim",
    "chars": 1682,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_exception')\n  finish\nendif\nlet g:autoloaded_timl_e"
  },
  {
    "path": "autoload/timl/false.vim",
    "chars": 422,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists(\"g:autoloaded_timl_false\")\n  finish\nendif\nlet g:autoloaded_timl_false"
  },
  {
    "path": "autoload/timl/file.tim",
    "chars": 1473,
    "preview": "(ns timl.file)\n\n(defn slash [] (if (and (exists? \"+shellslash\") (not &shellslash)) \"\\\\\" \"/\"))\n\n(defn ^{:help \"filereadab"
  },
  {
    "path": "autoload/timl/ftplugin.tim",
    "chars": 378,
    "preview": "(ns timl.ftplugin)\n(require '[timl.plugin-helper :as ph])\n\n(defmacro include-guard [& default]\n  (let [param (or (first "
  },
  {
    "path": "autoload/timl/funcref.vim",
    "chars": 794,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_funcref\")\n  finish\nendif\nlet g:autoloaded_timl_func"
  },
  {
    "path": "autoload/timl/function.vim",
    "chars": 3657,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_function')\n  finish\nendif\nlet g:autoloaded_timl_fu"
  },
  {
    "path": "autoload/timl/future.vim",
    "chars": 1442,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_future\")\n  finish\nendif\nlet g:autoloaded_timl_futur"
  },
  {
    "path": "autoload/timl/hash.vim",
    "chars": 4485,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_hash')\n  finish\nendif\nlet g:autoloaded_timl_hash ="
  },
  {
    "path": "autoload/timl/indent.tim",
    "chars": 337,
    "preview": "(ns timl.indent)\n(require '[timl.plugin-helper :as ph])\n\n(defmacro include-guard [& default]\n  (let [param (or (first de"
  },
  {
    "path": "autoload/timl/inst.vim",
    "chars": 3149,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_inst')\n  finish\nendif\nlet g:autoloaded_timl_inst ="
  },
  {
    "path": "autoload/timl/interactive.vim",
    "chars": 9338,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_interactive')\n  finish\nendif\nlet g:autoloaded_timl"
  },
  {
    "path": "autoload/timl/io.vim",
    "chars": 1407,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_io\")\n  finish\nendif\nlet g:autoloaded_timl_io = 1\n\nf"
  },
  {
    "path": "autoload/timl/keyword.vim",
    "chars": 1490,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_keyword\")\n  finish\nendif\nlet g:autoloaded_timl_keyw"
  },
  {
    "path": "autoload/timl/lazy_seq.vim",
    "chars": 1762,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_lazy_seq\")\n  finish\nendif\nlet g:autoloaded_timl_laz"
  },
  {
    "path": "autoload/timl/list.vim",
    "chars": 1628,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_list\")\n  finish\nendif\nlet g:autoloaded_timl_list = "
  },
  {
    "path": "autoload/timl/loader.vim",
    "chars": 5582,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_loader')\n  finish\nendif\nlet g:autoloaded_timl_load"
  },
  {
    "path": "autoload/timl/map.vim",
    "chars": 3786,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_map\")\n  finish\nendif\nlet g:autoloaded_timl_map = 1\n"
  },
  {
    "path": "autoload/timl/meta.vim",
    "chars": 1205,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_meta')\n  finish\nendif\nlet g:autoloaded_timl_meta ="
  },
  {
    "path": "autoload/timl/namespace.vim",
    "chars": 5912,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_namespace\")\n  finish\nendif\nlet g:autoloaded_timl_na"
  },
  {
    "path": "autoload/timl/nil.vim",
    "chars": 1241,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_nil\")\n  finish\nendif\nlet g:autoloaded_timl_nil = 1\n"
  },
  {
    "path": "autoload/timl/number.vim",
    "chars": 6079,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_number\")\n  finish\nendif\nlet g:autoloaded_timl_numbe"
  },
  {
    "path": "autoload/timl/plugin_helper.tim",
    "chars": 880,
    "preview": "(ns timl.plugin-helper)\n\n(defmacro include-guard [var]\n  (let [string (munge (str var))]\n   `(if (exists? ~string)\n     "
  },
  {
    "path": "autoload/timl/printer.vim",
    "chars": 4111,
    "preview": "\" Maintainer:   Tim Pope <http://tpo.pe/>\n\nif exists(\"g:autoloaded_timl_printer\")\n  finish\nendif\nlet g:autoloaded_timl_p"
  },
  {
    "path": "autoload/timl/reader.vim",
    "chars": 13410,
    "preview": "\" Maintainer:   Tim Pope <http://tpo.pe/>\n\nif exists(\"g:autoloaded_timl_reader\")\n  finish\nendif\nlet g:autoloaded_timl_re"
  },
  {
    "path": "autoload/timl/repl.tim",
    "chars": 1175,
    "preview": "(ns timl.repl)\n\n(defn qf\n  ([] (qf *e))\n  ([e]\n   (#*timl#interactive#copen e)\n   (throw \"timl#repl: exit\")))\n\n(defn bre"
  },
  {
    "path": "autoload/timl/set.vim",
    "chars": 4813,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_set\")\n  finish\nendif\nlet g:autoloaded_timl_set = 1\n"
  },
  {
    "path": "autoload/timl/string.vim",
    "chars": 2689,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_string')\n  finish\nendif\nlet g:autoloaded_timl_stri"
  },
  {
    "path": "autoload/timl/symbol.vim",
    "chars": 1703,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_symbol\")\n  finish\nendif\nlet g:autoloaded_timl_symbo"
  },
  {
    "path": "autoload/timl/test.tim",
    "chars": 190,
    "preview": "(ns timl.test)\n\n(defmacro assert [form]\n  `(try\n     (if ~form\n       true\n       (echo \"Failed: \" (pr-str '~form)))\n   "
  },
  {
    "path": "autoload/timl/true.vim",
    "chars": 413,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists(\"g:autoloaded_timl_true\")\n  finish\nendif\nlet g:autoloaded_timl_true ="
  },
  {
    "path": "autoload/timl/type.vim",
    "chars": 8241,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe>\n\nif exists(\"g:autoloaded_timl_type\")\n  finish\nendif\nlet g:autoloaded_timl_type = "
  },
  {
    "path": "autoload/timl/var.vim",
    "chars": 2056,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_var')\n  finish\nendif\nlet g:autoloaded_timl_var = 1"
  },
  {
    "path": "autoload/timl/vector.vim",
    "chars": 2403,
    "preview": "\" Maintainer: Tim Pope <http://tpo.pe/>\n\nif exists('g:autoloaded_timl_vector')\n  finish\nendif\nlet g:autoloaded_timl_vect"
  },
  {
    "path": "autoload/timl.vim",
    "chars": 1600,
    "preview": "\" Maintainer:   Tim Pope <http://tpo.pe/>\n\nif exists(\"g:autoloaded_timl\")\n  finish\nendif\nlet g:autoloaded_timl = 1\n\n\" Se"
  },
  {
    "path": "doc/timl.txt",
    "chars": 9870,
    "preview": "*timl.txt*  TimL\n\nAuthor:  Tim Pope <http://tpo.pe/>\nRepo:    https://github.com/tpope/timl\nLicense: EPL (http://opensou"
  },
  {
    "path": "doc/timl_core.txt",
    "chars": 458,
    "preview": "                                                *g:timl#core.array*\n(timl.core/array & elems)       Create a |timl-array"
  },
  {
    "path": "epl-v10.html",
    "chars": 12654,
    "preview": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www."
  },
  {
    "path": "ftplugin/timl.tim",
    "chars": 893,
    "preview": "(ns ftplugin.timl)\n(use 'timl.ftplugin)\n(include-guard)\n\n(setlocal comments=\":; ,:;;; ,:;; \" commentstring=\"; %s\")\n(setl"
  },
  {
    "path": "indent/timl.tim",
    "chars": 57,
    "preview": "(ns indent.timl)\n(execute \"runtime! indent/clojure.vim\")\n"
  },
  {
    "path": "plugin/timl.vim",
    "chars": 3582,
    "preview": "\" timl.vim - TimL\n\" Maintainer:   Tim Pope <code@tpope.net>\n\nif exists(\"g:loaded_timl\") || v:version < 700 || &cp\n  fini"
  },
  {
    "path": "syntax/timl.vim",
    "chars": 4483,
    "preview": "\" Vim syntax file\n\" Language:     TimL\n\" Maintainer:   Tim Pope <code@tpope.net>\n\" Filenames:    *.timl\n\nif exists(\"b:cu"
  },
  {
    "path": "test/timl/core_coll_test.tim",
    "chars": 444,
    "preview": "(ns timl.core-coll-test)\n(use 'timl.test)\n\n(assert (= 3 (count (list 1 2 3))))\n(assert (= 1 (count (dict \"a\" \"b\"))))\n\n(a"
  },
  {
    "path": "test/timl/core_test.tim",
    "chars": 168,
    "preview": "(ns timl.core-test)\n(use 'timl.test)\n\n(let [sentinel (dict)]\n  (assert (identical? sentinel ((constantly sentinel)))))\n\n"
  },
  {
    "path": "test/timl/number_test.tim",
    "chars": 1956,
    "preview": "(ns timl.number-test)\n(use 'timl.test)\n\n(assert (number? 3))\n(assert (number? 3.0))\n(assert (not (number? \"\")))\n(assert "
  }
]

About this extraction

This page contains the full source code of the tpope/timl GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 65 files (204.7 KB), approximately 70.8k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!