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 ("AGREEMENT"). ANY USE, REPRODUCTION OR
DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS
AGREEMENT.</p>
<p><b>1. DEFINITIONS</b></p>
<p>"Contribution" 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>"Contributor" means any person or entity that distributes
the Program.</p>
<p>"Licensed Patents" 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>"Program" means the Contributions distributed in accordance
with this Agreement.</p>
<p>"Recipient" 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
("Commercial Contributor") hereby agrees to defend and
indemnify every other Contributor ("Indemnified Contributor")
against any losses, damages and costs (collectively "Losses")
arising from claims, lawsuits and other legal actions brought by a third
party against the Indemnified Contributor to the extent cause
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.