$ cat lookup.js
function(obj, field) {
if (field === "XMLHttpRequest") { return undefined; }
else if (typeof field === "string") { return obj[field]; }
else { return undefined; } }
$ ./dist/build/lambdaJS/lambdaJS --desugar --no-env < lookup.js
(let
(($makeException (lambda (name msg)
(let
(($0
(get-field
(deref $global)
name)))
(let
(($constr $0))
(if (if (if (=== (typeof $constr) "location")
(let
(($isF (deref $constr)))
(if (=== (typeof $isF) "object")
(=== (typeof (get-field
$isF
"$code")) "lambda")
#f))
#f)
#f
#t)
(throw ($makeException "TypeError" ":new not given function"))
(let
(($protoField (get-field
(deref $constr)
"prototype")))
(let
(($protoObj (if (if (=== (typeof $protoField) "location")
(=== (typeof (deref $protoField)) "object")
#f)
$protoField
$Object.prototype)))
(let
(($newObj (alloc (object ("$constructing" #t)
("$class" "Object")
("$proto" $protoField)))))
(let
(($1
((get-field
(deref $constr)
"$code") $newObj (alloc (alloc (object ("length" 1.0)
("callee" $0)
("$class" "Object")
("$proto" $Object.prototype)
("$isArgs" #t)
("0" msg)))))))
(if (if (=== (typeof $1) "location")
(=== (typeof (deref $1)) "object")
#f)
$1
(begin
(set!
$newObj
(delete-field (deref $newObj)
"$constructing"))
$newObj))))))))))))
(begin
(alloc (object ("$code" (lambda (this arguments)
(let
((obj (get-field
(deref (deref arguments))
"0")))
(let
((field (get-field
(deref (deref arguments))
"1")))
(let
()
(label $return
(begin
(begin
(if (=== field "XMLHttpRequest")
(begin
(break $return
(get-field
(deref $global)
"undefined"))
undefined)
(if (=== (typeof field) "string")
(begin
(break $return
;;; The expression below (desugar 'obj[field])
(get-field
;;; The expression below is (deref (desugar 'obj)). If 'obj is
;;; not an object, it is converted to an object. This is perfectly safe, since we just
;;; need it to have type JS.
(deref (let
(($2
obj))
(if (=== (typeof $2) "undefined")
(throw ($makeException "TypeError" ":toObject received undefined"))
(if (=== $2 null)
(throw ($makeException "TypeError" ":toObject received null"))
(if (=== (typeof $2) "boolean")
(alloc (object ("$proto" $Boolean.prototype)
("$class" "Boolean")
("$value" $2)))
(if (=== (typeof $2) "number")
(alloc (object ("$proto" $Number.prototype)
("$class" "Number")
("$value" $2)))
(if (=== (typeof $2) "string")
(alloc (object ("$proto" $String.prototype)
("$class" "String")
("$value" $2)
("length" (str-length $2))))
$2)))))))
;;; The expression below is (toString (desugar 'field)), where toString
;;; is the metafunction defined in ECMA262-3, Section 9.8.1. Of course, here we have toString
;;; written in λJS. In ECMA262-3, toString uses various other metafunctions.
;;; Here, they are all inlined.
(let
(($toStr field))
(if (=== (typeof $toStr) "location")
;;; The true branch below is unreachable.
(if (if (=== (typeof (deref $toStr)) "object")
#f
#t)
(throw "Catastrophe - toStr given a ref of a not-obj")
(prim->string (let
(($x $toStr))
(if (=== (typeof $x) "location")
(if (if (=== (typeof (deref $x)) "object")
#f
#t)
(throw "Catastrophe - toPrim given a ref of a not-obj")
(let
(($vOf (get-field
(deref $x)
"valueOf")))
(if (if (=== (typeof $vOf) "location")
(let
(($isF (deref $vOf)))
(if (=== (typeof $isF) "object")
(=== (typeof (get-field
$isF
"$code")) "lambda")
#f))
#f)
(let
(($vRes (let
(($3
$vOf))
;;; Below, field.valueOf() is called. It may
;;; produce an arbitrary result, so it has type JS (not type NoXHR)
((get-field
(deref $3)
"$code") $x (alloc (alloc (object ("length" 0.0)
("callee" $3)
("$class" "Object")
("$proto" $Object.prototype)
("$isArgs" #t))))))))
(if (prim? $vRes)
$vRes
(let
(($toStr (get-field
(deref $x)
"toString")))
(if (if (=== (typeof $toStr) "location")
(let
(($isF (deref $toStr)))
(if (=== (typeof $isF) "object")
(=== (typeof (get-field
$isF
"$code")) "lambda")
#f))
#f)
(let
(($tRes (let
(($4
$toStr))
;;; Below, field.toString() is called.
;;; A function application has type JS, not type NoXHR.
((get-field
(deref $4)
"$code") $x (alloc (alloc (object ("length" 0.0)
("callee" $4)
("$class" "Object")
("$proto" $Object.prototype)
("$isArgs" #t))))))))
(if (prim? $tRes)
$tRes
(throw ($makeException "TypeError" ":apply expects arguments or array"))))
(throw ($makeException "TypeError" ":apply expects arguments or array"))))))
(let
(($toStr (get-field
(deref $x)
"toString")))
(if (if (=== (typeof $toStr) "location")
(let
(($isF (deref $toStr)))
(if (=== (typeof $isF) "object")
(=== (typeof (get-field
$isF
"$code")) "lambda")
#f))
#f)
(let
(($tRes (let
(($5
$toStr))
((get-field
(deref $5)
"$code") $x (alloc (alloc (object ("length" 0.0)
("callee" $5)
("$class" "Object")
("$proto" $Object.prototype)
("$isArgs" #t))))))))
(if (prim? $tRes)
$tRes
(throw ($makeException "TypeError" ":apply expects arguments or array"))))
(throw ($makeException "TypeError" ":apply expects arguments or array")))))))
(if (=== (typeof $x) "object")
(throw "Catastrophe - toPrim given plain object")
$x)))))
;;; The expression below is the false branch of the conditional. The
;;; type-test is unnecessary; it's inserted naively by desugaring.
(if (=== (typeof $toStr) "object")
(throw "Catastrophe - toStr given plain object")
;;; Here, we know that $toStr (i.e. field) has type NoXHR. The operator
;;; prim->string is the identity on strings, and doesn't convert booleans or numbers to the
;;; string "XMLHttpRequest"!
(prim->string $toStr))))))
undefined)
(begin
(break $return
(get-field
(deref $global)
"undefined"))
undefined)))
undefined)
undefined)))))))
("arguments" null)
("prototype" (alloc (object ("$proto" $Object.prototype))))
("$strRep" "function (obj,field) {\n [cant look here]\n}")
("$proto" $Function.prototype)))
undefined))