Merge pull request #281 from sebras/master
[jackhill/mal.git] / es6 / core.js
1 import { _equal_Q, _clone, _keyword, _keyword_Q,
2 _list_Q, Vector, _assoc_BANG, _dissoc_BANG, Atom } from './types'
3 import { pr_str } from './printer'
4 import { readline } from './node_readline'
5 import { read_str } from './reader'
6
7 function _error(e) { throw new Error(e) }
8
9 // String functions
10 function slurp(f) {
11 if (typeof require !== 'undefined') {
12 return require('fs').readFileSync(f, 'utf-8')
13 } else {
14 var req = new XMLHttpRequest()
15 req.open('GET', f, false)
16 req.send()
17 if (req.status !== 200) {
18 _error(`Failed to slurp file: ${f}`)
19 }
20 return req.responseText
21 }
22 }
23
24 // Sequence functions
25 function conj(o, ...a) {
26 return _list_Q(o) ? a.reverse().concat(o) : Vector.from(o.concat(a))
27 }
28
29 function seq(obj) {
30 if (_list_Q(obj)) {
31 return obj.length > 0 ? obj : null
32 } else if (obj instanceof Vector) {
33 return obj.length > 0 ? Array.from(obj.slice(0)) : null
34 } else if (typeof obj === "string" && obj[0] !== '\u029e') {
35 return obj.length > 0 ? obj.split('') : null
36 } else if (obj === null) {
37 return null
38 } else {
39 _error('seq: called on non-sequence')
40 }
41 }
42
43 // core_ns is namespace of type functions
44 export const core_ns = new Map([
45 ['=', _equal_Q],
46 ['throw', a => { throw a }],
47
48 ['nil?', a => a === null],
49 ['true?', a => a === true],
50 ['false?', a => a === false],
51 ['string?', a => typeof a === "string" && a[0] !== '\u029e'],
52 ['symbol', a => Symbol.for(a)],
53 ['symbol?', a => typeof a === 'symbol'],
54 ['keyword', _keyword],
55 ['keyword?', _keyword_Q],
56
57 ['pr-str', (...a) => a.map(e => pr_str(e,1)).join(' ')],
58 ['str', (...a) => a.map(e => pr_str(e,0)).join('')],
59 ['prn', (...a) => console.log(...a.map(e => pr_str(e,1))) || null],
60 ['println', (...a) => console.log(...a.map(e => pr_str(e,0))) || null],
61 ['read-string', read_str],
62 ['readline', readline],
63 ['slurp', slurp],
64
65 ['<' , (a,b) => a<b],
66 ['<=', (a,b) => a<=b],
67 ['>' , (a,b) => a>b],
68 ['>=', (a,b) => a>=b],
69 ['+' , (a,b) => a+b],
70 ['-' , (a,b) => a-b],
71 ['*' , (a,b) => a*b],
72 ['/' , (a,b) => a/b],
73 ["time-ms", () => new Date().getTime()],
74
75 ['list', (...a) => a],
76 ['list?', _list_Q],
77 ['vector', (...a) => Vector.from(a)],
78 ['vector?', a => a instanceof Vector],
79 ['hash-map', (...a) => _assoc_BANG(new Map(), ...a)],
80 ['map?', a => a instanceof Map],
81 ['assoc', (m,...a) => _assoc_BANG(_clone(m), ...a)],
82 ['dissoc', (m,...a) => _dissoc_BANG(_clone(m), ...a)],
83 ['get', (m,a) => m === null ? null : m.has(a) ? m.get(a) : null],
84 ['contains?', (m,a) => m.has(a)],
85 ['keys', a => Array.from(a.keys())],
86 ['vals', a => Array.from(a.values())],
87
88 ['sequential?', a => Array.isArray(a)],
89 ['cons', (a,b) => [a].concat(b)],
90 ['concat', (...a) => a.reduce((x,y) => x.concat(y), [])],
91 ['nth', (a,b) => b < a.length ? a[b] : _error('nth: index out of range')],
92 ['first', a => a !== null && a.length > 0 ? a[0] : null],
93 ['rest', a => a === null ? [] : Array.from(a.slice(1))],
94 ['empty?', a => a.length === 0],
95 ['count', a => a === null ? 0 : a.length],
96 ['apply', (f,...a) => f(...a.slice(0, -1).concat(a[a.length-1]))],
97 ['map', (f,a) => Array.from(a.map(x => f(x)))],
98
99 ['conj', conj],
100 ['seq', seq],
101
102 ['meta', a => 'meta' in a ? a['meta'] : null],
103 ['with-meta', (a,b) => { let c = _clone(a); c.meta = b; return c }],
104 ['atom', a => new Atom(a)],
105 ['atom?', a => a instanceof Atom],
106 ['deref', atm => atm.val],
107 ['reset!', (atm,a) => atm.val = a],
108 ['swap!', (atm,f,...args) => atm.val = f(...[atm.val].concat(args))]
109 ])