serene-simple/src/main/java/serene/simple/Reader.java

120 lines
3.5 KiB
Java
Raw Normal View History

2019-12-10 17:28:58 +00:00
package serene.simple;
import java.io.EOFException;
2019-12-10 17:28:58 +00:00
import java.io.IOException;
2019-12-14 02:42:25 +00:00
import java.io.InputStream;
2019-12-10 22:25:01 +00:00
import java.io.InputStreamReader;
2019-12-10 17:28:58 +00:00
import java.io.PushbackReader;
2019-12-14 02:42:25 +00:00
import java.util.ArrayList;
2019-12-10 22:25:01 +00:00
import java.util.List;
2019-12-10 17:28:58 +00:00
public class Reader {
public static Node readNode(PushbackReader inputStream) throws IOException, IllegalArgumentException, SereneException {
2019-12-10 17:28:58 +00:00
char c = (char) inputStream.read();
inputStream.unread(c);
if (c == '(') {
2019-12-10 17:28:58 +00:00
return readList(inputStream);
}
else if (Character.isDigit(c)) {
return readNumber(inputStream);
}
else if (c == ')') {
2019-12-14 02:42:25 +00:00
throw new IllegalArgumentException("Unmatch paranthesis.");
2019-12-10 17:28:58 +00:00
}
else {
return readSymbol(inputStream);
}
}
2019-12-10 22:25:01 +00:00
public static ListNode<Node> read(InputStream inputStream) throws IOException, IllegalArgumentException, SereneException {
2019-12-10 22:25:01 +00:00
return read(new PushbackReader(new InputStreamReader(inputStream)));
}
public static ListNode<Node> read(PushbackReader inputStream) throws IOException, IllegalArgumentException, SereneException {
2019-12-10 22:25:01 +00:00
List<Node> nodes = new ArrayList<Node>();
2019-12-14 02:42:25 +00:00
skipWhiteSpaces(inputStream);
2019-12-10 22:25:01 +00:00
2019-12-14 02:42:25 +00:00
char c = (char) inputStream.read();
2019-12-10 22:25:01 +00:00
while ((byte) c != -1) {
inputStream.unread(c);
nodes.add(readNode(inputStream));
2019-12-14 02:42:25 +00:00
skipWhiteSpaces(inputStream);
2019-12-10 22:25:01 +00:00
c = (char) inputStream.read();
}
2019-12-14 02:42:25 +00:00
return ListNode.list(nodes);
}
private static Node readList(PushbackReader inputStream) throws IOException, SereneException {
char opening = (char) inputStream.read();
assert opening == '(' : "Lists must start with a '('";
List<Node> nodes = new ArrayList<Node>();
do {
2019-12-14 02:42:25 +00:00
skipWhiteSpaces(inputStream);
char c = (char) inputStream.read();
if (c == ')') {
break;
} else if ((byte) c == -1) {
throw new EOFException("EOF reached before closing of list");
} else {
inputStream.unread(c);
nodes.add(readNode(inputStream));
}
} while(true);
2019-12-14 02:42:25 +00:00
return SpecialForm.check(ListNode.list(nodes));
}
private static Node readSymbol(PushbackReader inputStream) throws IOException {
String str = "";
2019-12-14 02:42:25 +00:00
while (true) {
int ch = inputStream.read();
2019-12-14 02:42:25 +00:00
2019-12-18 14:02:04 +00:00
if(isWhiteSpace(ch) || isClosingChar(ch) || ch == -1) {
inputStream.unread(ch);
break;
};
str = str + (char) ch;
}
2019-12-14 02:42:25 +00:00
return new SymbolNode(str);
2019-12-14 02:42:25 +00:00
}
private static Node readNumber(PushbackReader inputStream) throws IOException {
2019-12-14 22:05:53 +00:00
int ch = inputStream.read();
String number = "";
2019-12-14 02:42:25 +00:00
2019-12-14 22:05:53 +00:00
while (Character.isDigit((char) ch)) {
number = number + (char) ch;
ch = inputStream.read();
}
2019-12-14 02:42:25 +00:00
2019-12-14 22:05:53 +00:00
inputStream.unread(ch);
return new NumberNode(Long.parseLong(number, 10));
2019-12-14 02:42:25 +00:00
}
private static void skipWhiteSpaces(PushbackReader inputStream) throws IOException {
2019-12-18 14:02:04 +00:00
int ch = inputStream.read();
while (isWhiteSpace(ch)) {
ch = inputStream.read();
}
inputStream.unread(ch);
2019-12-14 02:42:25 +00:00
}
private static boolean isWhiteSpace(int ch) {
2019-12-18 14:02:04 +00:00
return (ch == ' ' || ch == '\t' || ch == '\f' || ch == '\r' || ch == '\n');
}
private static boolean isClosingChar(int ch) {
return (ch == ')' || ch == ']' ||
ch == '}');
2019-12-10 22:25:01 +00:00
}
2019-12-10 17:28:58 +00:00
}