/**
 * Copyright (c) 2012-2013 André Bargull
 * Alle Rechte vorbehalten / All Rights Reserved.  Use is subject to license terms.
 *
 * <https://github.com/anba/es6draft>
 */
package com.github.anba.es6draft.runtime.types.builtins;

import static com.github.anba.es6draft.runtime.types.Null.NULL;
import static com.github.anba.es6draft.runtime.types.builtins.FunctionObject.isStrictFunction;

import com.github.anba.es6draft.runtime.ExecutionContext;
import com.github.anba.es6draft.runtime.Realm;
import com.github.anba.es6draft.runtime.types.Callable;
import com.github.anba.es6draft.runtime.types.Property;
import com.github.anba.es6draft.runtime.types.PropertyDescriptor;
import com.github.anba.es6draft.runtime.types.Type;

/**
 * <h1>8 Types</h1><br>
 * <h2>8.4 Built-in Exotic Object Internal Methods and Data Fields</h2>
 * <ul>
 * <li>8.4.7 Built-in Function Objects
 * </ul>
 */
public abstract class BuiltinFunction extends OrdinaryObject implements Callable {
    /** [[Realm]] */
    private final Realm realm;

    public BuiltinFunction(Realm realm) {
        super(realm);
        this.realm = realm;
    }

    /**
     * [[Realm]]
     */
    protected final Realm realm() {
        return realm;
    }

    /**
     * Returns the callee execution context
     */
    protected final ExecutionContext calleeContext() {
        return realm.defaultContext();
    }

    @Override
    public String toSource() {
        Property desc = ordinaryGetOwnProperty("name");
        assert desc != null && desc.isDataDescriptor() : "built-in functions have an own 'name' data property";
        Object name = desc.getValue();
        assert Type.isString(name) : "'name' is a string valued data property";
        return String.format("function %s() { /* native code */ }", Type.stringValue(name));
    }

    /**
     * 8.3.19.3 [[Get]] (P, Receiver)
     */
    @Override
    public Object get(ExecutionContext cx, String propertyKey, Object receiver) {
        /* step 1-2 */
        Object v = super.get(cx, propertyKey, receiver);
        /* step 3 */
        if ("caller".equals(propertyKey) && isStrictFunction(v)) {
            // TODO: spec bug? [[Get]] override necessary, cf. AddRestrictedFunctionProperties
            // (Bug 1223)
            return NULL;
        }
        /* step 4 */
        return v;
    }

    /**
     * 8.3.19.4 [[GetOwnProperty]] (P)
     */
    @Override
    public Property getOwnProperty(ExecutionContext cx, String propertyKey) {
        /* step 1-2 */
        Property v = super.getOwnProperty(cx, propertyKey);
        if (v != null && v.isDataDescriptor()) {
            // TODO: spec bug? [[GetOwnProperty]] override necessary, cf.
            // AddRestrictedFunctionProperties (Bug 1223)
            if ("caller".equals(propertyKey) && isStrictFunction(v.getValue())) {
                PropertyDescriptor desc = v.toPropertyDescriptor();
                desc.setValue(NULL);
                v = desc.toProperty();
            }
        }
        return v;
    }
}

@@ -383,16 +383,128 @@
 unction;
+%0Aimport static com.github.anba.es6draft.runtime.types.builtins.OrdinaryFunction.AddRestrictedFunctionProperties;
 %0A%0Aimport
@@ -658,16 +658,74 @@
 llable;%0A
+import com.github.anba.es6draft.runtime.types.Intrinsics;%0A
 import c
@@ -1541,24 +1541,792 @@
 t();%0A    %7D%0A%0A
+    /**%0A     * Creates the default function properties, i.e. 'name' and 'length', initialises the%0A     * %5B%5BPrototype%5D%5D to the %3Ccode%3E%25FunctionPrototype%25%3C/code%3E object and calls%0A     * %7B@link OrdinaryFunction#AddRestrictedFunctionProperties(ExecutionContext, com.github.anba.es6draft.runtime.types.ScriptObject)%7D%0A     */%0A    protected final void setupDefaultFunctionProperties(String name, int arity) %7B%0A        ExecutionContext cx = realm.defaultContext();%0A        setPrototype(realm.getIntrinsic(Intrinsics.FunctionPrototype));%0A        defineOwnProperty(cx, %22name%22, new PropertyDescriptor(name, false, false, false));%0A        defineOwnProperty(cx, %22length%22, new PropertyDescriptor(arity, false, false, false));%0A        AddRestrictedFunctionProperties(cx, this);%0A    %7D%0A%0A
     @Overrid
@@ -2765,17 +2765,17 @@
  * 8.3.1
-9
+6
 .3 %5B%5BGet
@@ -3289,9 +3289,9 @@
 .3.1
-9
+6
 .4 %5B

Add helper method to BuiltinFunction, update section numbers