All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.truffle.js.builtins.ConsoleBuiltins Maven / Gradle / Ivy

/*
 * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * The Universal Permissive License (UPL), Version 1.0
 *
 * Subject to the condition set forth below, permission is hereby granted to any
 * person obtaining a copy of this software, associated documentation and/or
 * data (collectively the "Software"), free of charge and under any and all
 * copyright rights in the Software, and any and all patent rights owned or
 * freely licensable by each licensor hereunder covering either (i) the
 * unmodified Software as contributed to or provided by such licensor, or (ii)
 * the Larger Works (as defined below), to deal in both
 *
 * (a) the Software, and
 *
 * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
 * one is included with the Software each a "Larger Work" to which the Software
 * is contributed by such licensors),
 *
 * without restriction, including without limitation the rights to copy, create
 * derivative works of, display, perform, and distribute the Software and make,
 * use, sell, offer for sale, import, export, have made, and have sold the
 * Software and the Larger Work(s), and to sublicense the foregoing rights on
 * either these or other terms.
 *
 * This license is subject to the following condition:
 *
 * The above copyright notice and either this complete permission notice or at a
 * minimum a reference to the UPL must be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.oracle.truffle.js.builtins;

import java.io.PrintWriter;
import java.util.Map;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.js.builtins.ConsoleBuiltinsFactory.JSConsoleAssertNodeGen;
import com.oracle.truffle.js.builtins.ConsoleBuiltinsFactory.JSConsoleClearNodeGen;
import com.oracle.truffle.js.builtins.ConsoleBuiltinsFactory.JSConsoleCountNodeGen;
import com.oracle.truffle.js.builtins.ConsoleBuiltinsFactory.JSConsoleCountResetNodeGen;
import com.oracle.truffle.js.builtins.ConsoleBuiltinsFactory.JSConsoleGroupEndNodeGen;
import com.oracle.truffle.js.builtins.ConsoleBuiltinsFactory.JSConsoleGroupNodeGen;
import com.oracle.truffle.js.builtins.ConsoleBuiltinsFactory.JSConsoleTimeEndNodeGen;
import com.oracle.truffle.js.builtins.ConsoleBuiltinsFactory.JSConsoleTimeLogNodeGen;
import com.oracle.truffle.js.builtins.ConsoleBuiltinsFactory.JSConsoleTimeNodeGen;
import com.oracle.truffle.js.builtins.GlobalBuiltins.JSGlobalPrintNode;
import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.JSGlobalPrintNodeGen;
import com.oracle.truffle.js.nodes.cast.JSToBooleanNode;
import com.oracle.truffle.js.nodes.cast.JSToStringNode;
import com.oracle.truffle.js.nodes.function.JSBuiltin;
import com.oracle.truffle.js.nodes.function.JSBuiltinNode;
import com.oracle.truffle.js.runtime.JSConsoleUtil;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.JSRealm;
import com.oracle.truffle.js.runtime.Strings;
import com.oracle.truffle.js.runtime.builtins.BuiltinEnum;
import com.oracle.truffle.js.runtime.objects.JSDynamicObject;
import com.oracle.truffle.js.runtime.objects.Undefined;

/**
 * Contains builtins for `console`.
 */
public final class ConsoleBuiltins extends JSBuiltinsContainer.SwitchEnum {

    public static final JSBuiltinsContainer BUILTINS = new ConsoleBuiltins();

    protected ConsoleBuiltins() {
        super(JSRealm.CONSOLE_CLASS_NAME, Console.class);
    }

    public enum Console implements BuiltinEnum {
        log(0),
        info(0),
        debug(0),
        dir(0),
        error(0),
        warn(0),
        assert_(0),
        clear(0),
        count(0),
        countReset(0),
        group(0),
        groupCollapsed(0),
        groupEnd(0),
        time(0),
        timeEnd(0),
        timeLog(0);

        private final int length;

        Console(int length) {
            this.length = length;
        }

        @Override
        public int getLength() {
            return length;
        }
    }

    @Override
    protected Object createNode(JSContext context, JSBuiltin builtin, boolean construct, boolean newTarget, Console builtinEnum) {
        switch (builtinEnum) {
            case log:
            case info:
            case debug:
            case dir: // dir is not a strict alias of log, but close enough for our purpose
                return JSGlobalPrintNodeGen.create(context, builtin, false, false, args().varArgs().createArgumentNodes(context));
            case error:
            case warn:
                return JSGlobalPrintNodeGen.create(context, builtin, true, false, args().varArgs().createArgumentNodes(context));
            case assert_:
                return JSConsoleAssertNodeGen.create(context, builtin, args().varArgs().createArgumentNodes(context));
            case clear:
                return JSConsoleClearNodeGen.create(context, builtin, args().varArgs().createArgumentNodes(context));
            case count:
                return JSConsoleCountNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case countReset:
                return JSConsoleCountResetNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case group:
            case groupCollapsed:
                return JSConsoleGroupNodeGen.create(context, builtin, args().varArgs().createArgumentNodes(context));
            case groupEnd:
                return JSConsoleGroupEndNodeGen.create(context, builtin, args().fixedArgs(0).createArgumentNodes(context));
            case time:
                return JSConsoleTimeNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case timeEnd:
                return JSConsoleTimeEndNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case timeLog:
                return JSConsoleTimeLogNodeGen.create(context, builtin, args().varArgs().createArgumentNodes(context));
        }
        return null;
    }

    public abstract static class JSConsoleOperation extends JSBuiltinNode {

        public JSConsoleOperation(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
        }

        public JSConsoleUtil getConsoleUtil() {
            return getRealm().getConsoleUtil();
        }

    }

    public abstract static class JSConsoleAssertNode extends JSConsoleOperation {

        public static final TruffleString ASSERTION_FAILED_COLON = Strings.constant("Assertion failed:");
        public static final TruffleString ASSERTION_FAILED = Strings.constant("Assertion failed");

        @Child private JSGlobalPrintNode printNode;
        @Child private JSToBooleanNode toBooleanNode;

        public JSConsoleAssertNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            printNode = JSGlobalPrintNodeGen.create(context, null, false, false, null);
            toBooleanNode = JSToBooleanNode.create();
        }

        @Specialization
        protected JSDynamicObject assertImpl(Object... data) {
            boolean result = data.length > 0 ? toBooleanNode.executeBoolean(data[0]) : false;
            if (!result) {
                Object[] arr = new Object[data.length > 0 ? data.length : 1];
                if (data.length > 1) {
                    System.arraycopy(data, 1, arr, 1, data.length - 1);
                }
                arr[0] = data.length > 1 ? ASSERTION_FAILED_COLON : ASSERTION_FAILED;
                printNode.executeObjectArray(arr);
            }
            return Undefined.instance;
        }
    }

    public abstract static class JSConsoleClearNode extends JSConsoleOperation {

        public JSConsoleClearNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
        }

        @Specialization
        @TruffleBoundary
        protected JSDynamicObject clear() {
            PrintWriter writer = getRealm().getOutputWriter();
            writer.append("\033[H\033[2J");
            writer.flush();
            return Undefined.instance;
        }
    }

    public abstract static class JSConsoleCountNode extends JSConsoleOperation {

        @Child private JSToStringNode toStringNode;

        public JSConsoleCountNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            toStringNode = JSToStringNode.create();
        }

        @Specialization
        @TruffleBoundary
        protected JSDynamicObject count(Object label) {
            TruffleString key = label == Undefined.instance ? Strings.DEFAULT : toStringNode.executeString(label);
            int count = 0;
            JSConsoleUtil console = getConsoleUtil();
            Map countMap = console.getCountMap();
            if (countMap.containsKey(key)) {
                count = countMap.get(key);
            }
            countMap.put(key, ++count);

            PrintWriter writer = getRealm().getOutputWriter();
            writer.append(console.getConsoleIndentationString());
            writer.append(Strings.toJavaString(key));
            writer.append(": ");
            writer.append(String.valueOf(count));
            writer.append(Strings.LINE_SEPARATOR_JLS);
            writer.flush();
            return Undefined.instance;
        }
    }

    public abstract static class JSConsoleCountResetNode extends JSConsoleOperation {

        @Child private JSToStringNode toStringNode;

        public JSConsoleCountResetNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            toStringNode = JSToStringNode.create();
        }

        @Specialization
        @TruffleBoundary
        protected JSDynamicObject count(Object label) {
            Object key = label == Undefined.instance ? Strings.DEFAULT : toStringNode.executeString(label);
            getConsoleUtil().getCountMap().remove(key);
            return Undefined.instance;
        }
    }

    public abstract static class JSConsoleGroupNode extends JSConsoleOperation {

        @Child private JSGlobalPrintNode printNode;

        public JSConsoleGroupNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            printNode = JSGlobalPrintNodeGen.create(context, null, false, false, null);
        }

        @Specialization
        @TruffleBoundary
        protected JSDynamicObject group(Object[] label) {
            if (label.length > 0) {
                printNode.executeObjectArray(label);
            }
            getConsoleUtil().incConsoleIndentation();
            return Undefined.instance;
        }
    }

    public abstract static class JSConsoleGroupEndNode extends JSConsoleOperation {

        public JSConsoleGroupEndNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);

        }

        @Specialization
        @TruffleBoundary
        protected JSDynamicObject groupEnd() {
            getConsoleUtil().decConsoleIndentation();
            return Undefined.instance;
        }
    }

    public abstract static class JSConsoleTimeNode extends JSConsoleOperation {
        @Child private JSToStringNode toStringNode;

        public JSConsoleTimeNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            toStringNode = JSToStringNode.create();
        }

        @Specialization
        @TruffleBoundary
        protected JSDynamicObject time(Object label) {
            TruffleString key = label == Undefined.instance ? Strings.DEFAULT : toStringNode.executeString(label);
            getConsoleUtil().getTimeMap().put(key, getRealm().currentTimeMillis());
            return Undefined.instance;
        }
    }

    public abstract static class JSConsoleTimeEndNode extends JSConsoleOperation {
        @Child private JSToStringNode toStringNode;
        @Child private JSGlobalPrintNode printNode;

        public JSConsoleTimeEndNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            toStringNode = JSToStringNode.create();
            printNode = JSGlobalPrintNodeGen.create(context, null, false, false, null);
        }

        @Specialization
        @TruffleBoundary
        protected JSDynamicObject timeEnd(Object label) {
            TruffleString key = label == Undefined.instance ? Strings.DEFAULT : toStringNode.executeString(label);
            Map timeMap = getConsoleUtil().getTimeMap();
            if (timeMap.containsKey(key)) {
                long start = timeMap.remove(key);
                long end = getRealm().currentTimeMillis();
                long delta = end - start;
                printNode.executeObjectArray(new Object[]{Strings.concat(key, Strings.COLON), Strings.concat(Strings.fromLong(delta), Strings.MS)});
            }
            return Undefined.instance;
        }
    }

    public abstract static class JSConsoleTimeLogNode extends JSConsoleOperation {

        @Child private JSGlobalPrintNode printNode;
        @Child private JSToStringNode toStringNode;

        public JSConsoleTimeLogNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            printNode = JSGlobalPrintNodeGen.create(context, null, false, false, null);
            toStringNode = JSToStringNode.create();
        }

        @Specialization
        @TruffleBoundary
        protected JSDynamicObject timeLog(Object... data) {
            TruffleString key = data.length == 0 || data[0] == Undefined.instance ? Strings.DEFAULT : toStringNode.executeString(data[0]);
            Map timeMap = getConsoleUtil().getTimeMap();
            if (timeMap.containsKey(key)) {
                long start = timeMap.get(key);
                long end = getRealm().currentTimeMillis();
                long delta = end - start;

                Object[] arr = new Object[Math.max(2, data.length + 1)]; // add two, ignore first
                if (data.length > 1) {
                    System.arraycopy(data, 1, arr, 2, data.length - 1);
                }
                arr[0] = Strings.concat(key, Strings.COLON);
                arr[1] = Strings.concat(Strings.fromLong(delta), Strings.MS);
                printNode.executeObjectArray(arr);
            }
            return Undefined.instance;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy