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 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 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 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 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(''), '.*\zs\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 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 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 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 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 "")))) (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 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 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 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 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,'^\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 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 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(''), '\d\+$') endfunction return d.f endfunction ================================================ FILE: autoload/timl/function.vim ================================================ " Maintainer: Tim Pope 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 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 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 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 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(''), '.*\zs\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! `[\`]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 "\" 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."\" else return "\".body."\" 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 = '#%='.get(split(&statusline, '%='), 1, '') autocmd BufLeave update inoremap =timl#interactive#return() 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 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 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 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 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 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('')) 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 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 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 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 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 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 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 '#' elseif type ==# 'timl.lang/Var' return "#'".a:x.str elseif type ==# 'timl.lang/Exception' return '#' 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() | \ echomsg "Failed: ". | \ endif | \ catch /.*/ | \ echomsg "Error: ".." (".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 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 = '^\%(#"\%(\\\@= 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 ? 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() | \ echomsg "Failed: ". | \ endif | \ catch /.*/ | \ echomsg "Error: ".." (".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('')).' '.matchstr(expand(''), '.*\\.\\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 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 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 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 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 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 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 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 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 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 ================================================ Eclipse Public License - Version 1.0

Eclipse Public License - v 1.0

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.

1. DEFINITIONS

"Contribution" means:

a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and

b) in the case of each subsequent Contributor:

i) changes to the Program, and

ii) additions to the Program;

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.

"Contributor" means any person or entity that distributes the Program.

"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.

"Program" means the Contributions distributed in accordance with this Agreement.

"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.

2. GRANT OF RIGHTS

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.

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.

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.

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.

3. REQUIREMENTS

A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:

a) it complies with the terms and conditions of this Agreement; and

b) its license agreement:

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;

ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;

iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and

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.

When the Program is made available in source code form:

a) it must be made available under this Agreement; and

b) a copy of this Agreement must be included with each copy of the Program.

Contributors may not remove or alter any copyright notices contained within the Program.

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.

4. COMMERCIAL DISTRIBUTION

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 caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.

This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.

================================================ FILE: ftplugin/timl.tim ================================================ (ns ftplugin.timl) (use 'timl.ftplugin) (include-guard) (setlocal comments=":; ,:;;; ,:;; " commentstring="; %s") (setlocal define="^\\s*(def\\k*") (setlocal formatoptions+=cql) (setlocal omnifunc=timl#interactive#omnicomplete) (execute "nnoremap cp :set opfunc=timl#interactive#eval_opfuncg@") (execute "nnoremap cpp :call timl#interactive#eval_opfunc(v:count)") (execute "nnoremap K :execute 'help' ftplugin#timl#cursor_keyword()") (defn cursor-keyword [] (let [kw (#*expand "") ns (the-ns (symbol (#*timl#interactive#ns_for_cursor)))] (cond (re-find "^#\\*" kw) (str (subs kw 2) "()") (re-find "^&" kw) (str "'" (subs kw 1) "'") (special-symbol? (symbol kw)) (str "timl-" kw) (ns-resolve ns (symbol kw)) (. (ns-resolve ns (symbol kw)) munged) :else kw))) ================================================ FILE: indent/timl.tim ================================================ (ns indent.timl) (execute "runtime! indent/clojure.vim") ================================================ FILE: plugin/timl.vim ================================================ " timl.vim - TimL " Maintainer: Tim Pope if exists("g:loaded_timl") || v:version < 700 || &cp finish endif let g:loaded_timl = 1 if &maxfuncdepth == 100 set maxfuncdepth=200 endif augroup timl autocmd! autocmd BufNewFile,BufReadPost *.tim set filetype=timl autocmd BufNewFile,BufReadPost * \ if getline(1) =~# '^#!' && getline(2) =~# ';.*\')) autocmd SourceCmd *.tim call timl#loader#source(expand("")) autocmd FuncUndefined *#* call s:autoload(expand('')) autocmd VimEnter * nested \ if exists('s:source') | \ redraw! | \ execute 'TLsource '.s:source | \ unlet! s:source | \ endif augroup END command! -bar -nargs=? TLrepl :execute timl#interactive#repl() command! -bar TLscratch :execute timl#interactive#scratch() command! -nargs=1 -complete=expression TLinspect :echo timl#printer#string() command! -nargs=1 -complete=customlist,timl#interactive#input_complete TLeval \ try | \ echo timl#rep() | \ catch | \ unlet! g:timl#core._STAR_e | \ let g:timl#core._STAR_e = timl#exception#build(v:exception, v:throwpoint) | \ echoerr v:exception | \ endtry command! -bar TLcopen :call timl#interactive#copen(get(g:, 'timl#core#_STAR_e', [])) command! -bang -nargs=? -complete=file TLsource \ if has('vim_starting') | \ let s:source = | \ else | \ call timl#loader#source(expand(empty() ? '%' : )) | \ endif function! s:load_filetype(ft) abort if empty(a:ft) return '' endif let ft = split(a:ft)[0] for kind in ['ftplugin', 'indent'] for file in findfile(kind.'/'.ft.'.tim', &rtp, -1) try call timl#loader#source(file) catch unlet! g:timl#core._STAR_e let g:timl#core._STAR_e = timl#exception#build(v:exception, v:throwpoint) | echohl WarningMSG echomsg v:exception echohl NONE endtry endfor endfor endfunction if !exists('g:timl_requires') let g:timl_requires = {} endif function! s:file4ns(ns) abort if !exists('s:tempdir') let s:tempdir = tempname() endif let file = s:tempdir . '/' . a:ns . '.vim' if !isdirectory(fnamemodify(file, ':h')) call mkdir(fnamemodify(file, ':h'), 'p') endif return file endfunction function! s:autoload(function) abort let var = matchstr(a:function, '.*\ze#') let ns = tr(var, '#_', '.-') let base = tr(ns, '.-', '/_') if !has_key(g:timl_requires, ns) if !empty(findfile('autoload/'.base.'.vim')) let g:timl_requires[ns] = 1 else for file in findfile('autoload/'.base.'.tim', &rtp, -1) call timl#loader#source(file) let g:timl_requires[ns] = 1 break endfor endif endif let key = matchstr(a:function, '.*#\zs.*') if has_key(g:, var) && has_key(g:{var}, key) && timl#type#canp(g:{var}[key], g:timl#core.call) let body = ["function ".a:function."(...)", \ " return timl#call(g:".var.".".key.", a:000)", \ "endfunction"] let file = s:file4ns(base) call writefile(body, file) exe 'source '.file endif endfunction ================================================ FILE: syntax/timl.vim ================================================ " Vim syntax file " Language: TimL " Maintainer: Tim Pope " Filenames: *.timl if exists("b:current_syntax") finish endif syntax sync minlines=100 if !exists('s:functions') let s:file = readfile(findfile('syntax/vim.vim', &rtp)) let s:options = split(join(map(filter(copy(s:file), 'v:val =~# "^syn keyword vimOption contained\t[^in]"'), 'substitute(v:val, "^.*\t", "", "g")'), ' '), '\s\+') let s:functions = split(join(map(filter(copy(s:file), 'v:val =~# "^syn keyword vimFuncName contained\t[^in]"'), 'substitute(v:val, "^.*\t", "", "g")'), ' '), ' ') endif setl iskeyword+=?,!,#,$,%,&,*,+,.,/,<,>,:,=,45 let b:syntax_ns_str = timl#interactive#ns_for_cursor(0) let b:syntax_vars = keys(timl#namespace#map(timl#namespace#find(b:syntax_ns_str))) let b:current_syntax = "timl" function! s:syn_keyword(group, keywords) abort if !empty(a:keywords) exe 'syntax keyword '.a:group.' '.join(a:keywords, ' ') endif endfunction call s:syn_keyword('timlSymbol', b:syntax_vars) call s:syn_keyword('timlDefine', filter(copy(b:syntax_vars), 'v:val =~# "^def\\%(ault\\)\\@!"')) syntax keyword timlSpecialParam & &form &env syntax keyword timlConditional if syntax keyword timlDefine def deftype* set! declare syntax keyword timlRepeat loop recur syntax keyword timlStatement do let fn . execute syntax keyword timlSpecial let* fn* var function syntax keyword timlException try catch finally throw syntax keyword timlConstant nil syntax keyword timlBoolean false true syntax match timlKeyword ":\k\+" syntax match timlCharacter "\\\%(space\|tab\|newline\|return\|formfeed\|backspace\|.\)" syntax match timlNumber "\<[-+]\=0\o\+\>" syntax match timlNumber "\<[-+]\=0x\x\+\>" syntax match timlNumber "\<[-+]\=\%([1-9]\d*\|0\)\%(\.\d\+\)\=\%([Ee]\d\+\)\=\>" syntax keyword timlNumber Infinity -Infinity +Infinity NaN syntax region timlString start=/"/ skip=/\\\\\|\\"/ end=/"/ contains=timlStringEscape,@Spell syntax match timlStringEscape "\v\\%([uU]\x{4}|[0-3]\o{2}|\o\{1,2}|[xX]\x{1,2}|[befnrt\\"]|\<[[:alnum:]-]+\>)" contained syntax region timlRegexp start=/#"/ skip=/\\\\\|\\"/ end=/"/ contains=timlRegexpSpecial syntax match timlFuncref "\<#\*" nextgroup=timlVimFunction syntax match timlVarref "\<#'" nextgroup=timlSymbol syntax match timlQuote "'" syntax match timlSyntaxQuote "`" syntax match timlUnquote "\~@\=" syntax match timlDeref "@" syntax match timlMeta "\^" syntax region timlList matchgroup=timlGroup start="(" end=")" contains=TOP,@Spell syntax region timlVector matchgroup=timlGroup start="\[" end="]" contains=TOP,@Spell syntax region timlMap matchgroup=timlGroup start="{" end="}" contains=TOP,@Spell syntax region timlSet matchgroup=timlGroup start="#{" end="}" contains=TOP,@Spell syntax region timlFn matchgroup=timlGroup start="#(" end=")" contains=TOP,@Spell syntax match timlSymbol '\<%[1-9]\d*\>' syntax match timlSymbol '\<%&\=\>' syntax match timlComment "\<#_" syntax match timlComment ";.*$" syntax match timlComment ";= " syntax match timlComment ";! " nextgroup=timlError syntax match timlError ".*$" contained syntax match timlComment "#!.*$" syntax match timlComment ";;.*$" contains=@Spell call s:syn_keyword('timlVimOption', map(copy(s:options), "'&'.v:val")) call s:syn_keyword('timlVimOption', map(copy(s:options), "'&l:'.v:val")) call s:syn_keyword('timlVimOption', map(copy(s:options), "'&g:'.v:val")) exe 'syn match timlVimFunction contained "\%('.join(s:functions, '\|').'\)\>"' syntax match timlVar '\<[glabwtv]:\k\+\>' hi def link timlDefine Define hi def link timlSymbol Identifier hi def link timlSpecialParam Special hi def link timlConditional Conditional hi def link timlRepeat Repeat hi def link timlStatement Statement hi def link timlException Exception hi def link timlBoolean Boolean hi def link timlConstant Constant hi def link timlKeyword Constant hi def link timlCharacter Character hi def link timlString String hi def link timlRegexp String hi def link timlStringEscape Special hi def link timlRegexpSpecial Special hi def link timlNumber Number hi def link timlSpecial Special hi def link timlFuncref Special hi def link timlVarref Special hi def link timlQuote Special hi def link timlSyntaxQuote Special hi def link timlUnquote Special hi def link timlDeref Special hi def link timlMeta Special hi def link timlGroup Special hi def link timlComment Comment hi def link timlError WarningMsg hi def link timlVimFunction Function hi def link timlVimOption Type " vim:set et sw=2: ================================================ FILE: test/timl/core_coll_test.tim ================================================ (ns timl.core-coll-test) (use 'timl.test) (assert (= 3 (count (list 1 2 3)))) (assert (= 1 (count (dict "a" "b")))) (assert (= (list) (empty (list 1 2 3)))) (assert (= (dict) (empty (dict "a" "b")))) (assert (= "" (empty "string"))) (assert (nil? (empty 'symbol))) (assert (nil? (empty 0))) (assert (= (list 2 3 4) (map (partial + 1) (list 1 2 3)))) (assert (= (list "a") (map first (dict "a" "b")))) (assert (= 6 (reduce + (list 1 2 3)))) ================================================ FILE: test/timl/core_test.tim ================================================ (ns timl.core-test) (use 'timl.test) (let [sentinel (dict)] (assert (identical? sentinel ((constantly sentinel))))) (assert (= "42\n" (with-out-str (println 42)))) ================================================ FILE: test/timl/number_test.tim ================================================ (ns timl.number-test) (use 'timl.test) (assert (number? 3)) (assert (number? 3.0)) (assert (not (number? ""))) (assert (integer? 3)) (assert (not (integer? 3.0))) (assert (not (integer? ""))) (assert (not (float? 3))) (assert (float? 3.0)) (assert (not (integer? ""))) (assert (= 0 (+))) (assert (= 1 (+ 1))) (assert (= 3 (+ 1 2))) (assert (= 6 (+ 1 2 3))) (assert (= 4 (inc 3))) (assert (= -1 (- 1))) (assert (= 0 (- 3 1 2))) (assert (= 2 (dec 3))) (assert (= 1 (*))) (assert (= 6 (* 1 2 3))) (assert (= 0 (/ 2))) (assert (= 0.5 (/ 2.0))) (assert (= 0.5 (/ 1 2.0))) (assert (= 0.25 (/ 1 2.0 2.0))) (assert (= 1 (rem 4 3))) (assert (= -1 (rem -4 3))) (assert (= 1 (mod 4 3))) (assert (= 2 (mod -4 3))) (assert (= 0 (mod 0 3))) (assert (= -2 (mod 4 -3))) (assert (= 1.0 (quot 3.0 2))) (assert (= 7 (max 3 7 2 4))) (assert (= 2 (min 3 7 2 4))) (assert (= -1 (bit-not 0))) (assert (= 5 (bit-xor 7 3 1))) (assert (= 4 (bit-and 7 6 5))) (assert (= 7 (bit-or 1 2 4))) (assert (= 6 (bit-and-not 7 1 8))) (assert (= 8 (bit-shift-left 1 3))) (assert (= 1 (bit-shift-right 8 3))) (assert (= 3 (bit-flip 1 1))) (assert (= 3 (bit-set 1 1))) (assert (= 1 (bit-clear 3 1))) (assert (bit-test 3 1)) (assert (not (bit-test 5 1))) (assert (= nil (not-negative -1))) (assert (= 0 (not-negative 0))) (assert (zero? 0)) (assert (not (zero? 1))) (assert (nonzero? 1)) (assert (not (nonzero? 0))) (assert (even? 2)) (assert (not (even? 3))) (assert (odd? 3)) (assert (not (odd? 2))) (assert (> 3 2 1)) (assert (not (> 3 2 2))) (assert (< 1 2 3)) (assert (not (< 1 2 2))) (assert (>= 3 2 2)) (assert (not (>= 3 1 2))) (assert (<= 1 2 2)) (assert (not (< 1 3 2))) (assert (== 0 0.0 0)) (assert (not (== 0 0.0 1))) (defn fact [x] (loop [n x f 1] (if (<= n 1) f (recur (dec n) (* f n))))) (defn fib [n] (first (loop [xs [1 0]] (if (< (count xs) n) (recur (cons (+ (first xs) (second xs)) xs)) xs)))) (assert (= 120 (fact 5)))