more tests and cases and documentation
This commit is contained in:
@@ -589,6 +589,64 @@ break;" (compile-expr d)))]))
|
||||
(format "[~a]: ~a" (compile-expr k) (compile-expr v)))))
|
||||
(format "{~a}" (string-join pairs ", ")))
|
||||
|
||||
(define (compile-make-hash args)
|
||||
(match args
|
||||
['() "{}"]
|
||||
[(list entries) (format "Object.fromEntries(~a)" (compile-expr entries))]
|
||||
[_ (fail "make-hash arity" args)]))
|
||||
|
||||
(define (compile-hash-ref args)
|
||||
(match args
|
||||
[(list h k)
|
||||
(format "~a[~a]" (parens (compile-expr h)) (compile-expr k))]
|
||||
[(list h k default)
|
||||
(format "((__h, __k, __default) => Object.prototype.hasOwnProperty.call(__h, __k) ? __h[__k] : (typeof __default === 'function' ? __default() : __default))(~a, ~a, ~a)"
|
||||
(compile-expr h) (compile-expr k) (compile-expr default))]
|
||||
[_ (fail "hash-ref" args)]))
|
||||
|
||||
(define (compile-hash-set args #:mutate? [mutate? #f])
|
||||
(match args
|
||||
[(list h k v)
|
||||
(if mutate?
|
||||
(format "((__h, __k, __v) => { __h[__k] = __v; return undefined; })(~a, ~a, ~a)"
|
||||
(compile-expr h) (compile-expr k) (compile-expr v))
|
||||
(format "Object.assign({}, ~a, { [~a]: ~a })"
|
||||
(compile-expr h) (compile-expr k) (compile-expr v)))]
|
||||
[_ (fail (if mutate? "hash-set!" "hash-set") args)]))
|
||||
|
||||
(define (compile-hash-remove args #:mutate? [mutate? #f])
|
||||
(match args
|
||||
[(list h k)
|
||||
(if mutate?
|
||||
(format "((__h, __k) => { delete __h[__k]; return undefined; })(~a, ~a)"
|
||||
(compile-expr h) (compile-expr k))
|
||||
(format "((__h, __k) => { const __out = Object.assign({}, __h); delete __out[__k]; return __out; })(~a, ~a)"
|
||||
(compile-expr h) (compile-expr k)))]
|
||||
[_ (fail (if mutate? "hash-remove!" "hash-remove") args)]))
|
||||
|
||||
(define (compile-hash-update args #:mutate? [mutate? #f])
|
||||
(match args
|
||||
[(list h k f)
|
||||
(format "((__h, __k, __f) => { if (!Object.prototype.hasOwnProperty.call(__h, __k)) throw new Error('hash-update: no value found for key'); ~a; return ~a; })(~a, ~a, ~a)"
|
||||
(if mutate? "__h[__k] = __f(__h[__k])" "const __out = Object.assign({}, __h); __out[__k] = __f(__h[__k])")
|
||||
(if mutate? "undefined" "__out")
|
||||
(compile-expr h) (compile-expr k) (compile-expr f))]
|
||||
[(list h k f default)
|
||||
(format "((__h, __k, __f, __default) => { const __old = Object.prototype.hasOwnProperty.call(__h, __k) ? __h[__k] : (typeof __default === 'function' ? __default() : __default); ~a; return ~a; })(~a, ~a, ~a, ~a)"
|
||||
(if mutate? "__h[__k] = __f(__old)" "const __out = Object.assign({}, __h); __out[__k] = __f(__old)")
|
||||
(if mutate? "undefined" "__out")
|
||||
(compile-expr h) (compile-expr k) (compile-expr f) (compile-expr default))]
|
||||
[_ (fail (if mutate? "hash-update!" "hash-update") args)]))
|
||||
|
||||
(define (compile-hash-clear args #:mutate? [mutate? #f])
|
||||
(match args
|
||||
[(list h)
|
||||
(if mutate?
|
||||
(format "((__h) => { for (const __k of Object.keys(__h)) delete __h[__k]; return undefined; })(~a)"
|
||||
(compile-expr h))
|
||||
"{}")]
|
||||
[_ (fail (if mutate? "hash-clear!" "hash-clear") args)]))
|
||||
|
||||
(define (atomic-expr? x)
|
||||
(or (boolean? x)
|
||||
(number? x)
|
||||
@@ -608,7 +666,7 @@ break;" (compile-expr d)))]))
|
||||
null? empty? pair? list? vector? number? real? integer?
|
||||
string? boolean? symbol? regexp? pregexp? regexp-match?
|
||||
string=? string-ci=? string<? string>? string<=? string>=?
|
||||
hash-has-key? not))
|
||||
hash? hash-has-key? not))
|
||||
(and (eq? op 'and) (andmap boolean-expr? (cdr x)))
|
||||
(and (eq? op 'or) (andmap boolean-expr? (cdr x))))))))
|
||||
|
||||
@@ -996,6 +1054,14 @@ if (~a !== false) return ~a;" tmp (compile-expr arg) tmp tmp)))
|
||||
[(or) (compile-or args)]
|
||||
[(not) (format "(~a === false)" (compile-expr (car args)))]
|
||||
[(list vector) (format "[~a]" (string-join (map compile-expr args) ", "))]
|
||||
[(list*)
|
||||
(cond
|
||||
[(null? args) "[]"]
|
||||
[(null? (cdr args)) (compile-expr (car args))]
|
||||
[else
|
||||
(define fixed (reverse (cdr (reverse args))))
|
||||
(define last-arg (car (reverse args)))
|
||||
(format "[~a].concat(~a)" (string-join (map compile-expr fixed) ", ") (compile-expr last-arg))])]
|
||||
[(cons) (format "[~a].concat(~a)" (compile-expr (car args)) (compile-expr (cadr args)))]
|
||||
[(append) (if (null? args) "[]" (format "[].concat(~a)" (string-join (map compile-expr args) ", ")))]
|
||||
[(car first) (format "~a[0]" (parens (compile-expr (car args))))]
|
||||
@@ -1004,8 +1070,22 @@ if (~a !== false) return ~a;" tmp (compile-expr arg) tmp tmp)))
|
||||
[(caddr third) (format "~a[2]" (parens (compile-expr (car args))))]
|
||||
[(length vector-length string-length) (format "~a.length" (parens (compile-expr (car args))))]
|
||||
[(list-ref vector-ref string-ref) (format "~a[~a]" (parens (compile-expr (car args))) (compile-expr (cadr args)))]
|
||||
[(null? empty?) (format "Array.isArray(~a) && ~a.length === 0" (compile-expr (car args)) (parens (compile-expr (car args))))]
|
||||
[(pair?) (format "Array.isArray(~a) && ~a.length > 0" (compile-expr (car args)) (parens (compile-expr (car args))))]
|
||||
[(list-tail) (format "~a.slice(~a)" (parens (compile-expr (car args))) (compile-expr (cadr args)))]
|
||||
[(last) (format "((__xs) => __xs[__xs.length - 1])(~a)" (compile-expr (car args)))]
|
||||
[(list-set)
|
||||
(match args
|
||||
[(list xs i v)
|
||||
(format "((__xs, __i, __v) => { const __out = __xs.slice(); __out[__i] = __v; return __out; })(~a, ~a, ~a)"
|
||||
(compile-expr xs) (compile-expr i) (compile-expr v))]
|
||||
[_ (fail "list-set" args)])]
|
||||
[(list-update)
|
||||
(match args
|
||||
[(list xs i f)
|
||||
(format "((__xs, __i, __f) => { const __out = __xs.slice(); __out[__i] = __f(__out[__i]); return __out; })(~a, ~a, ~a)"
|
||||
(compile-expr xs) (compile-expr i) (compile-expr f))]
|
||||
[_ (fail "list-update" args)])]
|
||||
[(null? empty?) (format "((__xs) => Array.isArray(__xs) && __xs.length === 0)(~a)" (compile-expr (car args)))]
|
||||
[(pair?) (format "((__xs) => Array.isArray(__xs) && __xs.length > 0)(~a)" (compile-expr (car args)))]
|
||||
[(list? vector?) (format "Array.isArray(~a)" (compile-expr (car args)))]
|
||||
[(number? real? integer?) (format "typeof ~a === \"number\"" (compile-expr (car args)))]
|
||||
[(string?) (format "typeof ~a === \"string\"" (compile-expr (car args)))]
|
||||
@@ -1039,20 +1119,52 @@ if (~a !== false) return ~a;" tmp (compile-expr arg) tmp tmp)))
|
||||
[(string->number) (format "Number(~a)" (compile-expr (car args)))]
|
||||
[(displayln) (format "console.log(~a)" (string-join (map compile-expr args) ", "))]
|
||||
[(display) (format "console.log(~a)" (string-join (map compile-expr args) ", "))]
|
||||
[(hash) (compile-hash args)]
|
||||
[(hash-ref)
|
||||
(match args
|
||||
[(list h k) (format "~a[~a]" (parens (compile-expr h)) (compile-expr k))]
|
||||
[(list h k default) (format "((__h, __k) => Object.prototype.hasOwnProperty.call(__h, __k) ? __h[__k] : ~a)(~a, ~a)" (compile-expr default) (compile-expr h) (compile-expr k))]
|
||||
[_ (fail "hash-ref" args)])]
|
||||
[(hash-set) (format "Object.assign({}, ~a, { [~a]: ~a })" (compile-expr (car args)) (compile-expr (cadr args)) (compile-expr (caddr args)))]
|
||||
[(hash hasheq hasheqv) (compile-hash args)]
|
||||
[(make-hash make-immutable-hash make-hasheq make-immutable-hasheq make-hasheqv make-immutable-hasheqv)
|
||||
(compile-make-hash args)]
|
||||
[(hash?) (format "((__h) => __h !== null && typeof __h === 'object' && !Array.isArray(__h))(~a)" (compile-expr (car args)))]
|
||||
[(hash-ref) (compile-hash-ref args)]
|
||||
[(hash-set) (compile-hash-set args)]
|
||||
[(hash-set!) (compile-hash-set args #:mutate? #t)]
|
||||
[(hash-remove) (compile-hash-remove args)]
|
||||
[(hash-remove!) (compile-hash-remove args #:mutate? #t)]
|
||||
[(hash-update) (compile-hash-update args)]
|
||||
[(hash-update!) (compile-hash-update args #:mutate? #t)]
|
||||
[(hash-clear) (compile-hash-clear args)]
|
||||
[(hash-clear!) (compile-hash-clear args #:mutate? #t)]
|
||||
[(hash-copy) (format "Object.assign({}, ~a)" (compile-expr (car args)))]
|
||||
[(hash-copy-clear) "{}"]
|
||||
[(hash-has-key?) (format "Object.prototype.hasOwnProperty.call(~a, ~a)" (compile-expr (car args)) (compile-expr (cadr args)))]
|
||||
[(hash-count) (format "Object.keys(~a).length" (compile-expr (car args)))]
|
||||
[(hash-empty?) (format "Object.keys(~a).length === 0" (compile-expr (car args)))]
|
||||
[(hash-keys) (format "Object.keys(~a)" (compile-expr (car args)))]
|
||||
[(hash-values) (format "Object.values(~a)" (compile-expr (car args)))]
|
||||
[(hash->list) (format "Object.entries(~a)" (compile-expr (car args)))]
|
||||
[(hash-map) (format "Object.entries(~a).map(([__k, __v]) => ~a(__k, __v))" (compile-expr (car args)) (compile-expr (cadr args)))]
|
||||
[(hash-for-each) (format "((__h, __f) => { Object.entries(__h).forEach(([__k, __v]) => __f(__k, __v)); return undefined; })(~a, ~a)" (compile-expr (car args)) (compile-expr (cadr args)))]
|
||||
[(reverse) (format "[...~a].reverse()" (parens (compile-expr (car args))))]
|
||||
[(take) (format "~a.slice(0, ~a)" (parens (compile-expr (car args))) (compile-expr (cadr args)))]
|
||||
[(drop) (format "~a.slice(~a)" (parens (compile-expr (car args))) (compile-expr (cadr args)))]
|
||||
[(member memq memv) (format "~a.includes(~a)" (parens (compile-expr (cadr args))) (compile-expr (car args)))]
|
||||
[(take-right) (format "((__xs, __n) => __xs.slice(Math.max(0, __xs.length - __n)))(~a, ~a)" (compile-expr (car args)) (compile-expr (cadr args)))]
|
||||
[(drop-right) (format "((__xs, __n) => __xs.slice(0, Math.max(0, __xs.length - __n)))(~a, ~a)" (compile-expr (car args)) (compile-expr (cadr args)))]
|
||||
[(member)
|
||||
(format "((__v, __xs) => { const __i = __xs.findIndex((__x) => Object.is(__x, __v) || JSON.stringify(__x) === JSON.stringify(__v)); return __i < 0 ? false : __xs.slice(__i); })(~a, ~a)"
|
||||
(compile-expr (car args)) (compile-expr (cadr args)))]
|
||||
[(memq memv)
|
||||
(format "((__v, __xs) => { const __i = __xs.findIndex((__x) => Object.is(__x, __v)); return __i < 0 ? false : __xs.slice(__i); })(~a, ~a)"
|
||||
(compile-expr (car args)) (compile-expr (cadr args)))]
|
||||
[(remove)
|
||||
(format "((__v, __xs) => { let __done = false; return __xs.filter((__x) => { const __same = Object.is(__x, __v) || JSON.stringify(__x) === JSON.stringify(__v); if (!__done && __same) { __done = true; return false; } return true; }); })(~a, ~a)"
|
||||
(compile-expr (car args)) (compile-expr (cadr args)))]
|
||||
[(remove*)
|
||||
(format "((__vs, __xs) => __xs.filter((__x) => !__vs.some((__v) => Object.is(__x, __v) || JSON.stringify(__x) === JSON.stringify(__v))))(~a, ~a)"
|
||||
(compile-expr (car args)) (compile-expr (cadr args)))]
|
||||
[(sort)
|
||||
(match args
|
||||
[(list xs less?)
|
||||
(format "((__xs, __less) => __xs.slice().sort((__a, __b) => __less(__a, __b) !== false ? -1 : (__less(__b, __a) !== false ? 1 : 0)))(~a, ~a)"
|
||||
(compile-expr xs) (compile-expr less?))]
|
||||
[_ (fail "sort" args)])]
|
||||
[(map)
|
||||
(match args
|
||||
[(list f xs) (format "~a.map((__x) => ~a(__x))" (parens (compile-expr xs)) (compile-expr f))]
|
||||
|
||||
Reference in New Issue
Block a user