mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 11:41:56 +03:00
Implement print_err
and readln
(#754)
This commit is contained in:
parent
81bde28589
commit
ad9eb285fa
@ -0,0 +1,61 @@
|
||||
package org.enso.interpreter.node.expression.builtin.io;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import java.io.PrintStream;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition.ExecutionMode;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
|
||||
import org.enso.interpreter.runtime.state.Stateful;
|
||||
|
||||
@NodeInfo(shortName = "IO.print_err", description = "Prints its argument to standard error.")
|
||||
public abstract class PrintErrNode extends BuiltinRootNode {
|
||||
PrintErrNode(Language language) {
|
||||
super(language);
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Stateful doPrint(VirtualFrame frame, @CachedContext(Language.class) Context ctx) {
|
||||
print(ctx.getErr(), Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1]);
|
||||
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
|
||||
|
||||
return new Stateful(state, ctx.getUnit().newInstance());
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
private void print(PrintStream err, Object object) {
|
||||
err.println(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Function} object ignoring its first argument and printing the second to the
|
||||
* standard error stream.
|
||||
*
|
||||
* @param language the current {@link Language} instance
|
||||
* @return a {@link Function} object wrapping the behavior of this node
|
||||
*/
|
||||
public static Function makeFunction(Language language) {
|
||||
return Function.fromBuiltinRootNode(
|
||||
PrintErrNodeGen.create(language),
|
||||
CallStrategy.ALWAYS_DIRECT,
|
||||
new ArgumentDefinition(0, "this", ExecutionMode.EXECUTE),
|
||||
new ArgumentDefinition(1, "value", ExecutionMode.EXECUTE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source-level name of this node.
|
||||
*
|
||||
* @return the source-level name of this node
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "IO.print_err";
|
||||
}
|
||||
}
|
@ -15,22 +15,22 @@ import org.enso.interpreter.runtime.callable.function.FunctionSchema;
|
||||
import org.enso.interpreter.runtime.state.Stateful;
|
||||
|
||||
/** Allows for printing arbitrary values to the standard output. */
|
||||
@NodeInfo(shortName = "IO.println", description = "Root of the IO.println method.")
|
||||
public abstract class PrintNode extends BuiltinRootNode {
|
||||
PrintNode(Language language) {
|
||||
@NodeInfo(shortName = "IO.println", description = "Prints its argument to standard out.")
|
||||
public abstract class PrintlnNode extends BuiltinRootNode {
|
||||
PrintlnNode(Language language) {
|
||||
super(language);
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Stateful doPrint(VirtualFrame frame, @CachedContext(Language.class) Context ctx) {
|
||||
doPrint(ctx.getOut(), Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1]);
|
||||
print(ctx.getOut(), Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1]);
|
||||
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
|
||||
|
||||
return new Stateful(state, ctx.getUnit().newInstance());
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
private void doPrint(PrintStream out, Object object) {
|
||||
private void print(PrintStream out, Object object) {
|
||||
out.println(object);
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ public abstract class PrintNode extends BuiltinRootNode {
|
||||
*/
|
||||
public static Function makeFunction(Language language) {
|
||||
return Function.fromBuiltinRootNode(
|
||||
PrintNodeGen.create(language),
|
||||
PrintlnNodeGen.create(language),
|
||||
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
|
||||
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
|
||||
new ArgumentDefinition(1, "value", ArgumentDefinition.ExecutionMode.EXECUTE));
|
@ -0,0 +1,65 @@
|
||||
package org.enso.interpreter.node.expression.builtin.io;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition.ExecutionMode;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
|
||||
import org.enso.interpreter.runtime.error.RuntimeError;
|
||||
import org.enso.interpreter.runtime.state.Stateful;
|
||||
|
||||
@NodeInfo(shortName = "IO.readln", description = "Reads a line from standard in.")
|
||||
public abstract class ReadlnNode extends BuiltinRootNode {
|
||||
public ReadlnNode(Language language) {
|
||||
super(language);
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Stateful doRead(VirtualFrame frame, @CachedContext(Language.class) Context ctx) {
|
||||
return read(ctx.getIn(), Function.ArgumentsHelper.getState(frame.getArguments()));
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
private Stateful read(BufferedReader in, Object state) {
|
||||
try {
|
||||
String str = in.readLine();
|
||||
|
||||
return new Stateful(state, str);
|
||||
} catch (IOException e) {
|
||||
return new Stateful(state, new RuntimeError("Empty input stream."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Function} object ignoring its first argument and reading from the standard
|
||||
* input stream.
|
||||
*
|
||||
* @param language the current {@link Language} instance
|
||||
* @return a {@link Function} object wrapping the behavior of this node
|
||||
*/
|
||||
public static Function makeFunction(Language language) {
|
||||
return Function.fromBuiltinRootNode(
|
||||
ReadlnNodeGen.create(language),
|
||||
CallStrategy.ALWAYS_DIRECT,
|
||||
new ArgumentDefinition(0, "this", ExecutionMode.EXECUTE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source-level name of this node.
|
||||
*
|
||||
* @return the source-level name of the node
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "IO.readln";
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.enso.interpreter.node.expression.builtin.io;
|
||||
package org.enso.interpreter.node.expression.builtin.system;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
@ -10,7 +10,7 @@ import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
|
||||
import org.enso.interpreter.runtime.state.Stateful;
|
||||
|
||||
@NodeInfo(shortName = "IO.nano_time", description = "Gets the nanosecond resolution system time.")
|
||||
@NodeInfo(shortName = "System.nano_time", description = "Gets the nanosecond resolution system time.")
|
||||
public final class NanoTimeNode extends BuiltinRootNode {
|
||||
private NanoTimeNode(Language language) {
|
||||
super(language);
|
||||
@ -47,6 +47,6 @@ public final class NanoTimeNode extends BuiltinRootNode {
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "IO.nano_time";
|
||||
return "System.nano_time";
|
||||
}
|
||||
}
|
@ -14,8 +14,10 @@ import org.enso.interpreter.node.expression.builtin.function.ExplicitCallFunctio
|
||||
import org.enso.interpreter.node.expression.builtin.interop.generic.*;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.syntax.MethodDispatchNode;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.syntax.ConstructorDispatchNode;
|
||||
import org.enso.interpreter.node.expression.builtin.io.NanoTimeNode;
|
||||
import org.enso.interpreter.node.expression.builtin.io.PrintNode;
|
||||
import org.enso.interpreter.node.expression.builtin.io.PrintErrNode;
|
||||
import org.enso.interpreter.node.expression.builtin.io.PrintlnNode;
|
||||
import org.enso.interpreter.node.expression.builtin.io.ReadlnNode;
|
||||
import org.enso.interpreter.node.expression.builtin.system.NanoTimeNode;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.java.*;
|
||||
import org.enso.interpreter.node.expression.builtin.number.AddNode;
|
||||
import org.enso.interpreter.node.expression.builtin.number.DivideNode;
|
||||
@ -94,6 +96,7 @@ public class Builtins {
|
||||
new ArgumentDefinition(0, "head", ArgumentDefinition.ExecutionMode.EXECUTE),
|
||||
new ArgumentDefinition(1, "rest", ArgumentDefinition.ExecutionMode.EXECUTE));
|
||||
AtomConstructor io = new AtomConstructor("IO", scope).initializeFields();
|
||||
AtomConstructor system = new AtomConstructor("System", scope).initializeFields();
|
||||
AtomConstructor panic = new AtomConstructor("Panic", scope).initializeFields();
|
||||
AtomConstructor error = new AtomConstructor("Error", scope).initializeFields();
|
||||
AtomConstructor state = new AtomConstructor("State", scope).initializeFields();
|
||||
@ -120,8 +123,11 @@ public class Builtins {
|
||||
scope.registerConstructor(java);
|
||||
scope.registerConstructor(createPolyglot(language));
|
||||
|
||||
scope.registerMethod(io, "println", PrintNode.makeFunction(language));
|
||||
scope.registerMethod(io, "nano_time", NanoTimeNode.makeFunction(language));
|
||||
scope.registerMethod(io, "println", PrintlnNode.makeFunction(language));
|
||||
scope.registerMethod(io, "print_err", PrintErrNode.makeFunction(language));
|
||||
scope.registerMethod(io, "readln", ReadlnNode.makeFunction(language));
|
||||
|
||||
scope.registerMethod(system, "nano_time", NanoTimeNode.makeFunction(language));
|
||||
|
||||
scope.registerMethod(panic, "throw", PanicNode.makeFunction(language));
|
||||
scope.registerMethod(panic, "recover", CatchPanicNode.makeFunction(language));
|
||||
|
@ -3,7 +3,11 @@ package org.enso.interpreter.runtime;
|
||||
import com.oracle.truffle.api.TruffleFile;
|
||||
import com.oracle.truffle.api.TruffleLanguage;
|
||||
import com.oracle.truffle.api.TruffleLanguage.Env;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -30,6 +34,8 @@ public class Context {
|
||||
private final Env environment;
|
||||
private final Compiler compiler;
|
||||
private final PrintStream out;
|
||||
private final PrintStream err;
|
||||
private final BufferedReader in;
|
||||
private final List<Package> packages;
|
||||
|
||||
/**
|
||||
@ -42,6 +48,8 @@ public class Context {
|
||||
this.language = language;
|
||||
this.environment = environment;
|
||||
this.out = new PrintStream(environment.out());
|
||||
this.err = new PrintStream(environment.err());
|
||||
this.in = new BufferedReader(new InputStreamReader(environment.in()));
|
||||
|
||||
List<File> packagePaths = OptionsHelper.getPackagesPaths(environment);
|
||||
|
||||
@ -125,6 +133,24 @@ public class Context {
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the standard error stream for this context.
|
||||
*
|
||||
* @return the standard error stream for this context
|
||||
*/
|
||||
public PrintStream getErr() {
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the standard input stream for this context.
|
||||
*
|
||||
* @return the standard input stream for this context
|
||||
*/
|
||||
public BufferedReader getIn() {
|
||||
return in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new module scope that automatically imports all the builtin types and methods.
|
||||
*
|
||||
|
@ -1,6 +1,11 @@
|
||||
package org.enso.interpreter.test
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.{
|
||||
ByteArrayOutputStream,
|
||||
PipedInputStream,
|
||||
PipedOutputStream,
|
||||
PrintStream
|
||||
}
|
||||
import java.util.UUID
|
||||
|
||||
import com.oracle.truffle.api.instrumentation.EventBinding
|
||||
@ -72,12 +77,19 @@ trait InterpreterRunner {
|
||||
value.execute(l.map(_.asInstanceOf[AnyRef]): _*)
|
||||
)
|
||||
}
|
||||
val output = new ByteArrayOutputStream()
|
||||
val output = new ByteArrayOutputStream()
|
||||
val err = new ByteArrayOutputStream()
|
||||
val inOut = new PipedOutputStream()
|
||||
val inOutPrinter = new PrintStream(inOut, true)
|
||||
val in = new PipedInputStream(inOut)
|
||||
|
||||
val ctx = Context
|
||||
.newBuilder(LanguageInfo.ID)
|
||||
.allowExperimentalOptions(true)
|
||||
.allowAllAccess(true)
|
||||
.out(output)
|
||||
.err(err)
|
||||
.in(in)
|
||||
.build()
|
||||
lazy val executionContext = new PolyglotContext(ctx)
|
||||
|
||||
@ -127,12 +139,22 @@ trait InterpreterRunner {
|
||||
}
|
||||
}
|
||||
|
||||
def consumeErr: List[String] = {
|
||||
val result = err.toString
|
||||
err.reset()
|
||||
result.linesIterator.toList
|
||||
}
|
||||
|
||||
def consumeOut: List[String] = {
|
||||
val result = output.toString
|
||||
output.reset()
|
||||
result.linesIterator.toList
|
||||
}
|
||||
|
||||
def feedInput(string: String): Unit = {
|
||||
inOutPrinter.println(string)
|
||||
}
|
||||
|
||||
def getReplInstrument: ReplDebuggerInstrument = {
|
||||
ctx.getEngine.getInstruments
|
||||
.get(ReplDebuggerInstrument.INSTRUMENT_ID)
|
||||
|
@ -64,4 +64,31 @@ class TextTest extends InterpreterTest {
|
||||
eval(code)
|
||||
consumeOut shouldEqual List("\"Grzegorz Brzeczyszczykiewicz\"")
|
||||
}
|
||||
|
||||
"Text literals" should "be able to be printed to standard error" in {
|
||||
val errString = "\"My error string\""
|
||||
val resultStr = errString.drop(1).dropRight(1)
|
||||
|
||||
val code =
|
||||
s"""
|
||||
|main = IO.print_err $errString
|
||||
|""".stripMargin
|
||||
|
||||
eval(code)
|
||||
consumeErr shouldEqual List(resultStr)
|
||||
}
|
||||
|
||||
"Text literals" should "be able to be read from standard in" in {
|
||||
val inputString = "foobarbaz"
|
||||
|
||||
val code =
|
||||
"""
|
||||
|main =
|
||||
| IO.readln + " yay!"
|
||||
|""".stripMargin
|
||||
|
||||
feedInput(inputString)
|
||||
|
||||
eval(code) shouldEqual "foobarbaz yay!"
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,6 @@ class ParserTest extends AnyFlatSpec with Matchers {
|
||||
val module = Parser().run(input)
|
||||
val idmap1 = module.idMap
|
||||
val idmap2 = Parser().run(new Reader(input), idmap1).idMap
|
||||
println(module.zipWithOffset)
|
||||
assertSpan(input, module)
|
||||
assert(module.show() == new Reader(input).toString())
|
||||
assert(idmap1 == idmap2)
|
||||
|
Loading…
Reference in New Issue
Block a user