diff --git a/src/main/java/serene/simple/NumberNode.java b/src/main/java/serene/simple/NumberNode.java index e0757d0..29ec157 100644 --- a/src/main/java/serene/simple/NumberNode.java +++ b/src/main/java/serene/simple/NumberNode.java @@ -1,19 +1,19 @@ package serene.simple; public class NumberNode extends Node { - private final Long value; + private final Long value; - public NumberNode(Long v) { - this.value = v; - } + public NumberNode(Long v) { + this.value = v; + } - @Override - public Object eval(BaseScope scope) { - return this.value; - } + @Override + public Object eval(BaseScope scope) { + return this.value; + } - @Override - public String toString() { - return String.format("%s", this.value); - } - } + @Override + public String toString() { + return String.format("%s", this.value); + } +} diff --git a/src/main/java/serene/simple/Reader.java b/src/main/java/serene/simple/Reader.java index 59bc0eb..c334513 100644 --- a/src/main/java/serene/simple/Reader.java +++ b/src/main/java/serene/simple/Reader.java @@ -10,120 +10,141 @@ import java.util.List; public class Reader { - public static Node readNode(PushbackReader inputStream) throws IOException, IllegalArgumentException, SereneException { - char c = (char) inputStream.read(); + public static Node readNode(PushbackReader inputStream) throws IOException, IllegalArgumentException, SereneException { + char c = (char) inputStream.read(); + inputStream.unread(c); + + if (c == '(') { + return readList(inputStream); + } + else if (Character.isDigit(c)) { + return readNumber(inputStream); + } + else if (c == '"') { + return readString(inputStream); + } + else if (c == ')') { + throw new IllegalArgumentException("Unmatch paranthesis."); + } + else { + return readSymbol(inputStream); + } + } + + public static ListNode read(InputStream inputStream) throws IOException, IllegalArgumentException, SereneException { + return read(new PushbackReader(new InputStreamReader(inputStream))); + } + + public static ListNode read(PushbackReader inputStream) throws IOException, IllegalArgumentException, SereneException { + List nodes = new ArrayList(); + skipWhiteSpaces(inputStream); + + char c = (char) inputStream.read(); + while ((byte) c != -1) { + inputStream.unread(c); + nodes.add(readNode(inputStream)); + skipWhiteSpaces(inputStream); + c = (char) inputStream.read(); + } + + 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 nodes = new ArrayList(); + + do { + 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); - if (c == '(') { - return readList(inputStream); - } - else if (Character.isDigit(c)) { - return readNumber(inputStream); - } - else if (c == ')') { - throw new IllegalArgumentException("Unmatch paranthesis."); - } - else { - return readSymbol(inputStream); - } - } + return SpecialForm.check(ListNode.list(nodes)); + } - public static ListNode read(InputStream inputStream) throws IOException, IllegalArgumentException, SereneException { - return read(new PushbackReader(new InputStreamReader(inputStream))); - } + private static Node readSymbol(PushbackReader inputStream) throws IOException { + String str = ""; - public static ListNode read(PushbackReader inputStream) throws IOException, IllegalArgumentException, SereneException { - List nodes = new ArrayList(); - skipWhiteSpaces(inputStream); - - char c = (char) inputStream.read(); - while ((byte) c != -1) { - inputStream.unread(c); - nodes.add(readNode(inputStream)); - skipWhiteSpaces(inputStream); - c = (char) inputStream.read(); - } - - 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 nodes = new ArrayList(); - - do { - 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); - - return SpecialForm.check(ListNode.list(nodes)); - } - - private static Node readSymbol(PushbackReader inputStream) throws IOException { - String str = ""; - - while (true) { - int ch = inputStream.read(); - - if(isWhiteSpace(ch) || isClosingChar(ch) || ch == -1) { - inputStream.unread(ch); - break; - }; - str = str + (char) ch; - } - - switch(str) { - case "true": - return new TrueNode(); - case "false": - return new FalseNode(); - case "nil": - return new NilNode(); - default: - return new SymbolNode(str); - } - - } - - private static Node readNumber(PushbackReader inputStream) throws IOException { - int ch = inputStream.read(); - String number = ""; - - while (Character.isDigit((char) ch)) { - number = number + (char) ch; - ch = inputStream.read(); - } + while (true) { + int ch = inputStream.read(); + if(isWhiteSpace(ch) || isClosingChar(ch) || ch == -1) { inputStream.unread(ch); - return new NumberNode(Long.parseLong(number, 10)); + break; + }; + str = str + (char) ch; } - private static void skipWhiteSpaces(PushbackReader inputStream) throws IOException { - int ch = inputStream.read(); - - while (isWhiteSpace(ch)) { - ch = inputStream.read(); - } - inputStream.unread(ch); + switch(str) { + case "true": + return new TrueNode(); + case "false": + return new FalseNode(); + case "nil": + return new NilNode(); + default: + return new SymbolNode(str); } - private static boolean isWhiteSpace(int ch) { - return (ch == ' ' || ch == '\t' || ch == '\f' || ch == '\r' || ch == '\n'); + } + + private static Node readNumber(PushbackReader inputStream) throws IOException { + int ch = inputStream.read(); + String number = ""; + + while (Character.isDigit((char) ch)) { + number = number + (char) ch; + ch = inputStream.read(); } - private static boolean isClosingChar(int ch) { - return (ch == ')' || ch == ']' || - ch == '}'); + inputStream.unread(ch); + return new NumberNode(Long.parseLong(number, 10)); + } + + private static Node readString(PushbackReader inputStream) throws IOException { + char opening = (char) inputStream.read(); + assert opening == '"' : "Strings should start with \""; + String str = ""; + + while (true) { + char ch = (char) inputStream.read(); + + if(ch == '"') { + break; + } + str = str + ch; + }; + + return new StringNode(str); + + } + + private static void skipWhiteSpaces(PushbackReader inputStream) throws IOException { + int ch = inputStream.read(); + + while (isWhiteSpace(ch)) { + ch = inputStream.read(); } + inputStream.unread(ch); + } + + private static boolean isWhiteSpace(int ch) { + return (ch == ' ' || ch == '\t' || ch == '\f' || ch == '\r' || ch == '\n'); + } + + private static boolean isClosingChar(int ch) { + return (ch == ')' || ch == ']' || + ch == '}'); + } } diff --git a/src/main/java/serene/simple/StringNode.java b/src/main/java/serene/simple/StringNode.java new file mode 100644 index 0000000..c8c3650 --- /dev/null +++ b/src/main/java/serene/simple/StringNode.java @@ -0,0 +1,19 @@ +package serene.simple; + +public class StringNode extends Node { + private final String value; + + public StringNode(String v) { + this.value = v; + } + + @Override + public Object eval(BaseScope scope) { + return this.value; + } + + @Override + public String toString() { + return this.value; + } +}