aboutsummaryrefslogtreecommitdiff
path: root/coffee/types.coffee
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-11-08 16:56:36 -0600
committerJoel Martin <github@martintribe.org>2015-01-09 16:16:45 -0600
commit891c3f3b478292ad0bfca44b0dc098a2aecc9a5d (patch)
treed30c7923ffee7699cfca94af84f3be297448fff2 /coffee/types.coffee
parent9b3362e86a57ed7f14c5fd018c37713185e0c154 (diff)
downloadmal-891c3f3b478292ad0bfca44b0dc098a2aecc9a5d.tar.gz
mal-891c3f3b478292ad0bfca44b0dc098a2aecc9a5d.zip
CoffeeScript: add all steps. Self-hosting.
Diffstat (limited to 'coffee/types.coffee')
-rw-r--r--coffee/types.coffee115
1 files changed, 115 insertions, 0 deletions
diff --git a/coffee/types.coffee b/coffee/types.coffee
new file mode 100644
index 0000000..8982120
--- /dev/null
+++ b/coffee/types.coffee
@@ -0,0 +1,115 @@
+Env = require("./env.coffee").Env
+
+E = exports
+
+# General functions
+E._obj_type = _obj_type = (obj) ->
+ if _symbol_Q(obj) then 'symbol'
+ else if _list_Q(obj) then 'list'
+ else if _vector_Q(obj) then 'vector'
+ else if _hash_map_Q(obj) then 'hash-map'
+ else if _nil_Q(obj) then 'nil'
+ else if _true_Q(obj) then 'true'
+ else if _false_Q(obj) then 'false'
+ else if _atom_Q(obj) then 'atom'
+ else
+ switch typeof obj
+ when 'number' then 'number'
+ when 'function' then 'function'
+ when 'string' then 'string'
+ else throw new Error "Unknown type '" + typeof(obj) + "'"
+
+E._sequential_Q = _sequential_Q = (o) -> _list_Q(o) or _vector_Q(o)
+
+E._equal_Q = _equal_Q = (a,b) ->
+ [ota, otb] = [_obj_type(a), _obj_type(b)]
+ if !(ota == otb or (_sequential_Q(a) && _sequential_Q(b)))
+ return false
+ switch (ota)
+ when 'symbol' then a.name == b.name
+ when 'list', 'vector'
+ return false if a.length != b.length
+ for av,i in a
+ return false if !_equal_Q(av, b[i])
+ true
+ when 'hash-map'
+ akeys = (key for key of a)
+ bkeys = (key for key of b)
+ return false if akeys.length != bkeys.length
+ for akey,i in akeys
+ bkey = bkeys[i]
+ return false if akey != bkey
+ return false if !_equal_Q(a[akey], b[bkey])
+ true
+ else a == b
+
+E._clone = _clone = (obj) ->
+ switch _obj_type(obj)
+ when 'list' then obj[0..-1]
+ when 'vector' then _vector(obj[0..-1]...)
+ when 'hash-map'
+ new_obj = {}
+ new_obj[k] = v for k,v of obj
+ new_obj
+ when 'function'
+ new_obj = (args...) -> obj(args...)
+ new_obj[k] = v for k,v of obj
+ new_obj
+ else throw new Error "clone called on non-collection" + _obj_type(obj)
+
+
+# Scalars
+E._nil_Q = _nil_Q = (o) -> o == null
+E._true_Q = _true_Q = (o) -> o == true
+E._false_Q = _false_Q = (o) -> o == false
+
+# Symbols
+class Symbol
+ constructor: (@name) ->
+E._symbol = (str) -> new Symbol str
+E._symbol_Q = _symbol_Q = (o) -> o instanceof Symbol
+
+# Functions
+E._function = (evalfn, ast, env, params) ->
+ fn = (args...) -> evalfn(ast, new Env(env, params, args))
+ fn.__ast__ = ast
+ fn.__gen_env__ = (args) -> new Env(env, params, args)
+ fn.__ismacro__ = false
+ fn
+E._function_Q = _function_Q = (o) -> !!o.__ast__
+
+# Lists
+E._list_Q = _list_Q = (o) -> Array.isArray(o) && !o.__isvector__
+
+# Vectors
+E._vector = _vector = (args...) ->
+ v = args
+ v.__isvector__ = true
+ v
+E._vector_Q = _vector_Q = (o) -> Array.isArray(o) && !!o.__isvector__
+
+# Hash Maps
+E._hash_map = (args...) ->
+ args = [{}].concat args
+ _assoc_BANG(args...)
+E._assoc_BANG = _assoc_BANG = (hm, args...) ->
+ if args.length %% 2 == 1
+ throw new Error "Odd number of hash map arguments"
+ hm[k] = args[i+1] for k, i in args when i %% 2 == 0
+ hm
+E._dissoc_BANG = (hm, args...) ->
+ delete hm[k] for k, i in args
+ hm
+E._hash_map_Q = _hash_map_Q = (o) ->
+ typeof o == "object" && !Array.isArray(o) &&
+ !(o == null) &&
+ !(o instanceof Atom)
+
+
+# Atoms
+class Atom
+ constructor: (@val) ->
+E._atom = (val) -> new Atom val
+E._atom_Q = _atom_Q = (o) -> o instanceof Atom
+
+# vim: ts=2:sw=2