
scope { // 'scope' is like 'eval' but pushes a scope level and honors 'return'
    var a 17
    assert "integer" === typename a
    [print 'nameof a ='nameof a]
    assert 'a' === nameof a
    assert 17 === a
    assert unset a
    assert "undefined" === typename a
    assert "exception" === typename catch { $print a }
    var a 0 || 12
    assert 12 === a
    //$print "set/unset in scope done"
}

assert "undefined" === typename a

scope {
    var a scope { if{true} {if{true}{ if{true}{return 3} } } }
    assert 3 === a
}

eval { // 'eval' runs in current scope
    var a {hi}, b = 3
    assert "string" === typename a
    assert 'integer' === typename b
    assert 3 === b
    assert unset b
    set a
    assert undefined === a
    set a "hi"
    $print "set done in eval"
}

assert "string" === typename a
assert catch { unset a } /* throws b/c unset only works on same-scope vars */

eval { unset a }
assert "undefined" === typename a

__sweep


scope {
    var foo "FOO!"
    var bar "foo"
    assert 'FOO!' === get bar
}

assert 37 === eval {
    eval {
        var a 21.12
    }
    assert 'double' === typename a
    assert -21.12 === -a
    assert 21.12 === -a * -1
    37;
}
assert 21.12 === a
__sweep

scope {
    assert 8 === var x = 17, y x / 2
    assert 'integer' === typename x
    assert 'integer' === typename y
    assert 17 === x
    assert 8 === y
}
assert 'undefined' === typename x
assert 'undefined' === typename y

scope {
    $print "Demonstrating overwriting of higher-scoped vars..."
    assert 'function' === typename print
    var np = print
    assert 'function' === typename np
    scope {
        set print null
    }
    assert 'function' === typename np
    $np 'print =' typename print
    assert 'null' === typename print
    assert catch { $print }
    $np "Now showing how to declare locals...."

    set print np /** because 'print' is defined in a higher scope
                     we overwrite it here, instead of using a local
                     reference.
                 */
    scope {
        var print = print // 2nd "print" still evaluates to global print
        $print "Using/abusing local print reference" print
        assert np === print
        set print null
        assert 'null' === typename print
        assert catch { $print 1 }
    }
    assert 'function' === typename print

    scope {
        var myvar
        assert 'undefined' === typename myvar
        scope {
            set myvar 12
        }
        assert 'integer' === typename myvar
        assert 12 === myvar
    }
    assert 'undefined' === typename myvar

    $print "Done overwriting higher-level vars."
}


scope "[print 'hi from string']"

scope {
    set myCode {
        $print "eval via code reference."
        __sweep
    }
    $print 'myCode =' myCode
    eval myCode

    set "myCode" 3
    assert 3 === eval myCode
}

scope {
    const a 7
    assert 7 === a
    assert 306 === catch { set a 3 }.code /* a is const */
}

scope {
    const Obj = object{}.prototype
    const Int = 1.prototype
    const Double = 1.0.prototype
    const String = "".prototype
    // TODO: add a base Number prototype from which Int/Double derive.
    assert (1 inherits Int)
    assert (1.0 inherits Double)
    assert !(1 inherits Double)
    assert array[] inherits Obj
    assert !(array[] inherits object{})
    assert "" inherits String
    // TO FIX: assert !("" inherits Obj)
    // TO FIX: assert !(1 inherits Obj)
    // TO FIX: assert !(1.0 inherits Obj)
    // The problem is that if i remove that prototype,
    // some method lookups suddenly break (not sure why)
}

return {end of test script #4}
throw "NOT REACHED"
