Skip to content

Commit cb7bc0d

Browse files
committed
implement a readline stub
1 parent 03c2b3a commit cb7bc0d

File tree

2 files changed

+238
-1
lines changed

2 files changed

+238
-1
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import com.oracle.graal.python.builtins.modules.MathModuleBuiltins;
6464
import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins;
6565
import com.oracle.graal.python.builtins.modules.RandomModuleBuiltins;
66+
import com.oracle.graal.python.builtins.modules.ReadlineModuleBuiltins;
6667
import com.oracle.graal.python.builtins.modules.SREModuleBuiltins;
6768
import com.oracle.graal.python.builtins.modules.SelectModuleBuiltins;
6869
import com.oracle.graal.python.builtins.modules.SignalModuleBuiltins;
@@ -271,7 +272,8 @@ private static final PythonBuiltins[] initializeBuiltins() {
271272
new SysModuleBuiltins(),
272273
new BufferBuiltins(),
273274
new MemoryviewBuiltins(),
274-
new SuperBuiltins()));
275+
new SuperBuiltins(),
276+
new ReadlineModuleBuiltins()));
275277
if (!TruffleOptions.AOT) {
276278
ServiceLoader<PythonBuiltins> providers = ServiceLoader.load(PythonBuiltins.class);
277279
for (PythonBuiltins builtin : providers) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/*
2+
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.builtins.modules;
42+
43+
import java.io.BufferedReader;
44+
import java.io.BufferedWriter;
45+
import java.io.IOException;
46+
import java.nio.file.StandardOpenOption;
47+
import java.util.ArrayList;
48+
import java.util.HashMap;
49+
import java.util.List;
50+
51+
import com.oracle.graal.python.builtins.Builtin;
52+
import com.oracle.graal.python.builtins.CoreFunctions;
53+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
54+
import com.oracle.graal.python.builtins.PythonBuiltins;
55+
import com.oracle.graal.python.builtins.objects.PNone;
56+
import com.oracle.graal.python.builtins.objects.module.PythonModule;
57+
import com.oracle.graal.python.builtins.objects.str.PString;
58+
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
59+
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
60+
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
61+
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
62+
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
63+
import com.oracle.graal.python.runtime.PythonCore;
64+
import com.oracle.graal.python.runtime.exception.PythonErrorType;
65+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
66+
import com.oracle.truffle.api.dsl.Cached;
67+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
68+
import com.oracle.truffle.api.dsl.NodeFactory;
69+
import com.oracle.truffle.api.dsl.Specialization;
70+
import com.oracle.truffle.api.interop.ForeignAccess;
71+
import com.oracle.truffle.api.interop.TruffleObject;
72+
73+
@CoreFunctions(defineModule = "readline")
74+
public class ReadlineModuleBuiltins extends PythonBuiltins {
75+
private static final String DATA = "__data__";
76+
77+
@Override
78+
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
79+
return ReadlineModuleBuiltinsFactory.getFactories();
80+
}
81+
82+
private static final class LocalData implements TruffleObject {
83+
private final HashMap<String, String> bindings = new HashMap<>();
84+
private final List<String> history = new ArrayList<>();
85+
protected Object completer;
86+
87+
public ForeignAccess getForeignAccess() {
88+
return null;
89+
}
90+
}
91+
92+
@Override
93+
public void initialize(PythonCore core) {
94+
super.initialize(core);
95+
LocalData readlineData = new LocalData();
96+
builtinConstants.put(DATA, readlineData);
97+
}
98+
99+
@Builtin(name = "get_completer", fixedNumOfPositionalArgs = 1, declaresExplicitSelf = true)
100+
@GenerateNodeFactory
101+
abstract static class GetCompleterNode extends PythonUnaryBuiltinNode {
102+
@Specialization
103+
Object getCompleter(PythonModule self,
104+
@Cached("create()") ReadAttributeFromObjectNode readNode) {
105+
LocalData data = (LocalData) readNode.execute(self, DATA);
106+
if (data.completer != null) {
107+
return data.completer;
108+
} else {
109+
return PNone.NONE;
110+
}
111+
}
112+
}
113+
114+
@Builtin(name = "set_completer", fixedNumOfPositionalArgs = 2, declaresExplicitSelf = true)
115+
@GenerateNodeFactory
116+
abstract static class SetCompleterNode extends PythonBinaryBuiltinNode {
117+
@Specialization
118+
PNone setCompleter(PythonModule self, Object callable,
119+
@Cached("create()") ReadAttributeFromObjectNode readNode) {
120+
LocalData data = (LocalData) readNode.execute(self, DATA);
121+
data.completer = callable;
122+
return PNone.NONE;
123+
}
124+
}
125+
126+
@Builtin(name = "parse_and_bind", fixedNumOfPositionalArgs = 2, declaresExplicitSelf = true)
127+
@GenerateNodeFactory
128+
abstract static class ParseAndBindNode extends PythonBinaryBuiltinNode {
129+
@Specialization
130+
@TruffleBoundary
131+
PNone setCompleter(PythonModule self, String spec,
132+
@Cached("create()") ReadAttributeFromObjectNode readNode) {
133+
if (spec.startsWith("tab:")) {
134+
LocalData data = (LocalData) readNode.execute(self, DATA);
135+
data.bindings.put("tab", spec.split(":")[1].trim());
136+
return PNone.NONE;
137+
} else {
138+
throw raise(PythonBuiltinClassType.NotImplementedError, "any other binding than 'tab'");
139+
}
140+
}
141+
}
142+
143+
@Builtin(name = "read_init_file", fixedNumOfPositionalArgs = 1, declaresExplicitSelf = true)
144+
@GenerateNodeFactory
145+
abstract static class ReadInitNode extends PythonUnaryBuiltinNode {
146+
@Specialization
147+
PNone setCompleter(@SuppressWarnings("unused") PythonModule self) {
148+
throw raise(PythonErrorType.OSError, "not implemented");
149+
}
150+
}
151+
152+
@Builtin(name = "get_current_history_length", fixedNumOfPositionalArgs = 1, declaresExplicitSelf = true)
153+
@GenerateNodeFactory
154+
abstract static class GetHistoryLengthNode extends PythonUnaryBuiltinNode {
155+
@Specialization
156+
@TruffleBoundary
157+
int setCompleter(PythonModule self,
158+
@Cached("create()") ReadAttributeFromObjectNode readNode) {
159+
LocalData data = (LocalData) readNode.execute(self, DATA);
160+
return data.history.size();
161+
}
162+
}
163+
164+
@Builtin(name = "read_history_file", fixedNumOfPositionalArgs = 2, declaresExplicitSelf = true)
165+
@GenerateNodeFactory
166+
abstract static class ReadHistoryFileNode extends PythonBinaryBuiltinNode {
167+
@Specialization
168+
PNone setCompleter(PythonModule self, PString path,
169+
@Cached("create()") ReadAttributeFromObjectNode readNode) {
170+
return setCompleter(self, path.getValue(), readNode);
171+
}
172+
173+
@Specialization
174+
@TruffleBoundary
175+
PNone setCompleter(PythonModule self, String path,
176+
@Cached("create()") ReadAttributeFromObjectNode readNode) {
177+
LocalData data = (LocalData) readNode.execute(self, DATA);
178+
try {
179+
BufferedReader reader = getContext().getEnv().getTruffleFile(path).newBufferedReader();
180+
String line;
181+
while ((line = reader.readLine()) != null) {
182+
data.history.add(line);
183+
}
184+
} catch (IOException e) {
185+
throw raise(PythonErrorType.IOError, e.getMessage());
186+
}
187+
return PNone.NONE;
188+
}
189+
}
190+
191+
@Builtin(name = "write_history_file", fixedNumOfPositionalArgs = 2, declaresExplicitSelf = true)
192+
@GenerateNodeFactory
193+
abstract static class WriteHistoryFileNode extends PythonBinaryBuiltinNode {
194+
@Specialization
195+
PNone setCompleter(PythonModule self, PString path,
196+
@Cached("create()") ReadAttributeFromObjectNode readNode) {
197+
return setCompleter(self, path.getValue(), readNode);
198+
}
199+
200+
@Specialization
201+
@TruffleBoundary
202+
PNone setCompleter(PythonModule self, String path,
203+
@Cached("create()") ReadAttributeFromObjectNode readNode) {
204+
LocalData data = (LocalData) readNode.execute(self, DATA);
205+
try {
206+
BufferedWriter writer = getContext().getEnv().getTruffleFile(path).newBufferedWriter(StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
207+
for (String l : data.history) {
208+
writer.write(l);
209+
writer.newLine();
210+
}
211+
} catch (IOException e) {
212+
throw raise(PythonErrorType.IOError, e.getMessage());
213+
}
214+
return PNone.NONE;
215+
}
216+
}
217+
218+
@Builtin(name = "insert_text", fixedNumOfPositionalArgs = 1)
219+
@GenerateNodeFactory
220+
abstract static class InsertTextNode extends PythonUnaryBuiltinNode {
221+
@Specialization
222+
PNone setCompleter(@SuppressWarnings("unused") Object text) {
223+
return PNone.NONE;
224+
}
225+
}
226+
227+
@Builtin(name = "redisplay", fixedNumOfPositionalArgs = 0)
228+
@GenerateNodeFactory
229+
abstract static class RedisplayNode extends PythonBuiltinNode {
230+
@Specialization
231+
PNone setCompleter() {
232+
return PNone.NONE;
233+
}
234+
}
235+
}

0 commit comments

Comments
 (0)