Package org.jruby.truffle.runtime.backtrace

Source Code of org.jruby.truffle.runtime.backtrace.MRIBacktraceFormatter

/*
* Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.runtime.backtrace;

import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.source.NullSourceSection;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.CoreSourceSection;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.TruffleFatalException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyException;

import java.util.ArrayList;
import java.util.List;

public class MRIBacktraceFormatter implements BacktraceFormatter {

    @Override
    public String[] format(RubyContext context, RubyException exception, Backtrace backtrace) {
        try {
            final List<Activation> activations = backtrace.getActivations();

            final ArrayList<String> lines = new ArrayList<>();

            if (activations.isEmpty()) {
                lines.add(String.format("%s (%s)", exception.getMessage(), exception.getLogicalClass().getName()));
            } else {
                lines.add(formatInLine(activations, exception));

                for (int n = 1; n < activations.size(); n++) {
                    lines.add(formatFromLine(activations, n));
                }
            }

            return lines.toArray(new String[lines.size()]);
        } catch (Exception e) {
            throw new TruffleFatalException("Exception while trying to format a Ruby call stack", e);
        }
    }

    private static String formatInLine(List<Activation> activations, RubyException exception) {
        final StringBuilder builder = new StringBuilder();

        final SourceSection sourceSection = activations.get(0).getCallNode().getEncapsulatingSourceSection();
        final SourceSection reportedSourceSection;
        final String reportedName;

        if (sourceSection instanceof CoreSourceSection) {
            reportedSourceSection = nextUserSourceSection(activations, 1);
            reportedName = ((CoreSourceSection) sourceSection).getMethodName();
        } else {
            reportedSourceSection = sourceSection;
            reportedName = reportedSourceSection.getIdentifier();
        }

        if (reportedSourceSection == null) {
            throw new IllegalStateException("Call node has no encapsulating source section");
        }

        if (reportedSourceSection.getSource() == null) {
            throw new IllegalStateException("Call node source section " + reportedSourceSection + " has no source");
        }

        builder.append(reportedSourceSection.getSource().getName());
        builder.append(":");
        builder.append(reportedSourceSection.getStartLine());
        builder.append(":in `");
        builder.append(reportedName);
        builder.append("'");

        if (exception != null) {
            builder.append(": ");
            builder.append(exception.getMessage());
            builder.append(" (");
            builder.append(exception.getLogicalClass().getName());
            builder.append(")");
        }

        return builder.toString();
    }

    private static String formatFromLine(List<Activation> activations, int n) {
        return "\tfrom " + formatCallerLine(activations, n);
    }

    public static String formatCallerLine(List<Activation> activations, int n) {
        final SourceSection sourceSection = activations.get(n).getCallNode().getEncapsulatingSourceSection();
        final SourceSection reportedSourceSection;
        final String reportedName;

        if (sourceSection instanceof CoreSourceSection) {
            reportedSourceSection = activations.get(n + 1).getCallNode().getEncapsulatingSourceSection();
            reportedName = ((CoreSourceSection) sourceSection).getMethodName();
        } else {
            reportedSourceSection = sourceSection;
            reportedName = sourceSection.getIdentifier();
        }

        final StringBuilder builder = new StringBuilder();
        if (reportedSourceSection instanceof NullSourceSection) {
            builder.append("NullSourceSection");
        } else {
            builder.append(reportedSourceSection.getSource().getName());
            builder.append(":");
            builder.append(reportedSourceSection.getStartLine());
        }
        builder.append(":in `");
        builder.append(reportedName);
        builder.append("'");

        return builder.toString();
    }

    private static SourceSection nextUserSourceSection(List<Activation> activations, int n) {
        while (true) {
            SourceSection sourceSection = activations.get(n).getCallNode().getEncapsulatingSourceSection();

            if (!(sourceSection instanceof CoreSourceSection)) {
                return sourceSection;
            }

            n++;
        }
    }

}
TOP

Related Classes of org.jruby.truffle.runtime.backtrace.MRIBacktraceFormatter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.