Skip to content

Commit

Permalink
Showing 3 changed files with 81 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2016 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.core.cast;

import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.NotProvided;
import org.jruby.truffle.language.RubyNode;

/**
* Take a Symbol or some object accepting #to_str
* and convert it to a Java String and defaults to
* the given value if not provided.
*/
@NodeChild(value = "value", type = RubyNode.class)
public abstract class NameToJavaStringWithDefaultNode extends RubyNode {

private final String defaultValue;
@Child private NameToJavaStringNode toJavaStringNode;

public NameToJavaStringWithDefaultNode(RubyContext context, SourceSection sourceSection, String defaultValue) {
super(context, sourceSection);
this.defaultValue = defaultValue;
toJavaStringNode = NameToJavaStringNodeGen.create(context, sourceSection, null);
}

public abstract String executeString(VirtualFrame frame, Object value);

@Specialization
public String doDefault(VirtualFrame frame, NotProvided value) {
return toJavaStringNode.executeToJavaString(frame, defaultValue);
}

@Specialization(guards = "wasProvided(value)")
public String doProvided(VirtualFrame frame, Object value) {
return toJavaStringNode.executeToJavaString(frame, value);
}


}
Original file line number Diff line number Diff line change
@@ -41,46 +41,44 @@
package org.jruby.truffle.stdlib.readline;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.CreateCast;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import jline.console.history.History;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.CoreClass;
import org.jruby.truffle.builtins.CoreMethod;
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.builtins.YieldingCoreMethodNode;
import org.jruby.truffle.core.cast.ToStrNode;
import org.jruby.truffle.core.cast.ToStrNodeGen;
import org.jruby.truffle.builtins.*;
import org.jruby.truffle.core.cast.*;
import org.jruby.truffle.core.rope.RopeOperations;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.objects.TaintNode;
import org.jruby.truffle.language.objects.TaintNodeGen;

import java.util.Iterator;

@CoreClass("Truffle::ReadlineHistory")
public abstract class ReadlineHistoryNodes {

@CoreMethod(names = { "push", "<<" }, rest = true)
public abstract static class PushNode extends CoreMethodArrayArgumentsNode {

@Child private ToStrNode toStrNode;
@Child private NameToJavaStringNode toJavaStringNode;

public PushNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
toStrNode = ToStrNodeGen.create(context, sourceSection, null);
toJavaStringNode = NameToJavaStringNodeGen.create(context, sourceSection, null);
}

@Specialization
public DynamicObject push(VirtualFrame frame, DynamicObject history, Object... lines) {
final ConsoleHolder consoleHolder = getContext().getConsoleHolder();

for (Object line : lines) {
final DynamicObject asString = toStrNode.executeToStr(frame, line);
consoleHolder.getHistory().add(RopeOperations.decodeUTF8(StringOperations.rope(asString)));
final String asString = toJavaStringNode.executeToJavaString(frame, line);
consoleHolder.getHistory().add(asString);
}

return history;
@@ -220,25 +218,29 @@ public Object getIndex(int index) {

}

@CoreMethod(names = "[]=", needsSelf = false, required = 2, lowerFixnumParameters = 0)
public abstract static class SetIndexNode extends CoreMethodArrayArgumentsNode {
@CoreMethod(names = "[]=", needsSelf = false, required = 2)
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "index"),
@NodeChild(type = RubyNode.class, value = "line")
})
public abstract static class SetIndexNode extends CoreMethodNode {

@Child private ToStrNode toStrNode;
@CreateCast("index") public RubyNode coerceIndexToInt(RubyNode index) {
return ToIntNodeGen.create(index);
}

public SetIndexNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
toStrNode = ToStrNodeGen.create(context, sourceSection, null);
@CreateCast("line") public RubyNode coerceLineToJavaString(RubyNode line) {
return NameToJavaStringNodeGen.create(null, null, line);
}

@Specialization
public Object setIndex(VirtualFrame frame, int index, Object line) {
public Object setIndex(VirtualFrame frame, int index, String line) {
final ConsoleHolder consoleHolder = getContext().getConsoleHolder();

final int normalizedIndex = index < 0 ? index + consoleHolder.getHistory().size() : index;

try {
final DynamicObject asString = toStrNode.executeToStr(frame, line);
consoleHolder.getHistory().set(normalizedIndex, RopeOperations.decodeUTF8(StringOperations.rope(asString)));
consoleHolder.getHistory().set(normalizedIndex, line);

return nil();
} catch (IndexOutOfBoundsException e) {
Original file line number Diff line number Diff line change
@@ -51,9 +51,7 @@
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.*;
import org.jruby.truffle.core.array.ArrayHelpers;
import org.jruby.truffle.core.cast.BooleanCastWithDefaultNodeGen;
import org.jruby.truffle.core.cast.NameToJavaStringNodeGen;
import org.jruby.truffle.core.cast.ToStrNodeGen;
import org.jruby.truffle.core.cast.*;
import org.jruby.truffle.core.rope.RopeOperations;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.RubyNode;
@@ -122,26 +120,25 @@ public ReadlineNode(RubyContext context, SourceSection sourceSection) {
taintNode = TaintNodeGen.create(context, sourceSection, null);
}

@CreateCast("addToHistory") public RubyNode coerceToBoolean(RubyNode addToHistory) {
return BooleanCastWithDefaultNodeGen.create(null, null, false, addToHistory);
@CreateCast("prompt") public RubyNode coercePromptToJavaString(RubyNode prompt) {
return NameToJavaStringWithDefaultNodeGen.create(null, null, coreStrings().EMPTY_STRING.toString(), prompt);
}

@Specialization(guards = "wasNotProvided(prompt)")
public Object readlineNoPrompt(Object prompt, boolean addToHistory) {
return readline(coreStrings().EMPTY_STRING.createInstance(), addToHistory);
@CreateCast("addToHistory") public RubyNode coerceToBoolean(RubyNode addToHistory) {
return BooleanCastWithDefaultNodeGen.create(null, null, false, addToHistory);
}

@TruffleBoundary
@Specialization(guards = "isRubyString(prompt)")
public Object readline(DynamicObject prompt, boolean addToHistory) {
@Specialization
public Object readline(String prompt, boolean addToHistory) {
getContext().getConsoleHolder().getReadline().setExpandEvents(false);

DynamicObject line = nil();
String value;
while (true) {
try {
getContext().getConsoleHolder().getReadline().getTerminal().setEchoEnabled(false);
value = getContext().getConsoleHolder().getReadline().readLine(RopeOperations.decodeUTF8(StringOperations.rope(prompt)));
value = getContext().getConsoleHolder().getReadline().readLine(prompt);
break;
} catch (IOException e) {
throw new RaiseException(coreExceptions().ioError(e.getMessage(), this));

0 comments on commit d746a27

Please sign in to comment.