#lang scheme/base
(require srfi/13/string
"../syntax/ast-core.ss"
"../syntax/ast-utils.ss"
"exceptions.ss"
"value.ss")
(provide (except-out (all-defined-out) less-than? same-type? == ===))
(define (js:void v)
(void))
(define (js:delete ref)
(if (ref? ref)
(delete-ref! ref)
#t))
(define (js:typeof v)
(cond
[(void? v) "undefined"]
[(null? v) "object"]
[(boolean? v) "boolean"]
[(string? v) "string"]
[(function? v) "function"]
[(object? v) "object"]))
(define (js:instanceof x y)
(descendant-of? x y))
(define (js:* x y)
(* (any->number x)
(any->number y)))
(define (js:/ x y)
(let ([result (exact->inexact (/ (any->number x)
(any->number y)))])
(if (integer? result)
(inexact->exact result)
result)))
(define js:+
(case-lambda
[(x) (any->number x)]
[(x y)
(let ([x (any->primitive x object->number)]
[y (any->primitive y object->number)])
(if (or (string? x) (string? y))
(string-append (any->string x)
(any->string y))
(+ (any->number x)
(any->number y))))]))
(define js:-
(case-lambda
[(x) (- (any->number x))]
[(x y) (- (any->number x)
(any->number y))]))
(define (js:% x y)
(let ([dividend (any->number x)]
[divisor (any->number y)])
(cond
[(or (NaN? dividend) (NaN? divisor) (infinite? dividend) (zero? divisor))
NaN]
[(and (not (infinite? dividend)) (infinite? divisor))
x]
[else
(let* ([quotient (exact->inexact (/ dividend divisor))]
[sign (if (negative? quotient) - +)]
[magnitude (inexact->exact (floor (abs quotient)))])
(- dividend (* divisor (sign magnitude))))])))
(define (js:<< x y)
(arithmetic-shift (any->int32 x)
(bitwise-and (any->uint32 y) #x1F)))
(define (js:>> x y)
(arithmetic-shift (any->int32 x)
(- (bitwise-and (any->uint32 y) #x1F))))
(define (js:>>> x y)
(arithmetic-shift (any->uint32 x)
(- (bitwise-and (any->uint32 y) #x1F))))
(define (js:& x y)
(bitwise-and (any->int32 x)
(any->int32 y)))
(define (js:^ x y)
(bitwise-xor (any->int32 x)
(any->int32 y)))
(define (js:\| x y)
(bitwise-ior (any->int32 x)
(any->int32 y)))
(define (js:~ x)
(bitwise-not (any->int32 x)))
(define (js:! x)
(not (any->boolean x)))
(define (less-than? x y)
(let ([x (any->primitive x object->number)]
[y (any->primitive y object->number)])
(if (and (string? x) (string? y))
(and (not (string-prefix? y x))
(string-prefix? x y))
(< (any->number x)
(any->number y)))))
(define (js:< x y)
(less-than? x y))
(define (js:> x y)
(less-than? y x))
(define (js:<= x y)
(not (less-than? y x)))
(define (js:>= x y)
(not (less-than? x y)))
(define (js:in x y)
(unless (object? y)
(raise-runtime-type-error here "object" (any->string y)))
(has-property? y (any->string x)))
(define (same-type? x y)
(or (and (void? x) (void? y))
(and (null? x) (null? y))
(and (boolean? x) (boolean? y))
(and (number? x) (number? y))
(and (string? x) (string? y))
(and (object? x) (object? y))))
(define (== x y)
(cond
[(not (same-type? x y))
(or (and (null? x) (void? y))
(and (void? x) (null? y))
(and (number? x) (string? y) (== x (any->number y)))
(and (string? x) (number? y) (== (any->number x) y))
(and (boolean? x) (== (any->number x) y))
(and (boolean? y) (== x (any->number y)))
(and (string? x) (object? y) (== x (any->string y)))
(and (number? x) (object? y) (== x (any->number y)))
(and (object? x) (string? y) (== (any->string x) y))
(and (object? x) (number? y) (== (any->number x) y))
)]
[(void? x) #t]
[(null? x) #t]
[(number? x) (= x y)]
[(string? x) (string=? x y)]
[(boolean? x) (eq? x y)]
[(object? x) (eq? x y)]
[else (raise-runtime-type-error here "native values" (format "~a and ~a" (any->string x) (any->string y)))]))
(define (js:== x y)
(== x y))
(define (js:!= x y)
(not (== x y)))
(define (=== x y)
(and (same-type? x y)
(or (void? x)
(null? x)
(and (number? x) (= x y))
(and (string? x) (string=? x y))
(and (boolean? x) (eq? x y))
(and (object? x) (eq? x y))
(eq? x y))))
(define (js:=== x y)
(=== x y))
(define (js:!== x y)
(not (=== x y)))