Bunch of new Node implementations has been added

This commit is contained in:
Sameer Rahmani 2019-12-12 00:17:41 +00:00
parent aa16324991
commit a5265c353e
10 changed files with 203 additions and 2 deletions

View File

@ -0,0 +1,15 @@
package serene.simple;
public class DefSpecialForm extends SpecialForm {
public DefSpecialForm(ListNode listNode) {
super(listNode);
}
@Override
public Object eval(Scope scope) {
SymbolNode sym = (SymbolNode) this.node.rest.first;
scope.putValue(sym.name,
this.node.rest.rest.first.eval(scope));
return ListNode.EMPTY;
}
}

View File

@ -0,0 +1,40 @@
package serene.simple;
import java.util.function.Function;
public class FnSpecialForm extends SpecialForm {
public FnSpecialForm(ListNode paramsAndBody) {
super(paramsAndBody);
}
@Override
public Object eval(final Scope parentScope) {
final ListNode formalParams = (ListNode) this.node.rest.far;
final ListNode body = this.node.rest.rest;
return new Function() {
@Override
public Object apply(Object... args) {
Scope scope = new Scope(parentScope);
if (args.length != formalParams.length()) {
throw new RuntimeException(String.format("Wrong number of arguments. Expected: %s, Got: %s.",
formalParams.length(),
args.length));
}
// Map parameter values to formal parameter names
int i = 0;
for (Node param : formalParams) {
SymbolNode paramSymbol = (SymbolNode) param;
scope.putValue(paramSymbol.name, args[i]);
i++;
}
// Evaluate body
Object output = null;
for (Node node : body) {
output = node.eval(scope);
}
return output;
}
};
}
}

View File

@ -0,0 +1,8 @@
package serene.simple;
public class FunctionNode extends Node {
@Override
public Object eval(Scope scope) {
return this;
}
}

View File

@ -0,0 +1,18 @@
package serene.simple;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public class ListNode extends Node implements Iterable<Node> {
@Override
public Object eval(Scope scope) {
Function f = (Function) this.first.eval(scope);
List<Object> args = new ArrayList<Object>();
for (Node node : this.first) {
args.add(node.eval(scope));
}
return f.apply(args.toArray());
}
}

View File

@ -0,0 +1,5 @@
package serene.simple;
public abstract class Node {
public abstract Object eval(Scope scope);
}

View File

@ -0,0 +1,14 @@
package serene.simple;
public class NumberNode extends Node {
private final Long value;
public NumberNode(Long v) {
this.value = v;
}
@Override
public Object eval(Scope scope) {
return this.value;
}
}

View File

@ -1,5 +1,6 @@
package serene.simple;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PushbackReader;
@ -11,13 +12,13 @@ public class Reader {
char c = (char) inputStream.read();
inputStream.unread(c);
if (c == "(") {
if (c == '(') {
return readList(inputStream);
}
else if (Character.isDigit(c)) {
return readNumber(inputStream);
}
else if (c == ")") {
else if (c == ')') {
throw new IllegalArgumentException("Unmatch paranthesis.")
}
else {
@ -40,5 +41,28 @@ public class Reader {
nodes.add(readNode(inputStream));
skipWhitespaces(inputStream);
c = (char) inputStream.read();
}
}
private static Node readList(PushbackReader inputStream) throws IOException {
char opening = (char) inputStream.read();
assert opening == '(' : "Lists must start with a '('";
List<Node> nodes = new ArrayList<Node>();
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(ListNode.list(nodes));
}
}

View File

@ -0,0 +1,33 @@
package serene.simple;
import java.util.HashMap;
public class Scope {
private final HashMap<String, Object> symbolsMapping = new HashMap<String, Object>();
private final Scope parent;
public Scope() {
this(null);
}
public Scope(Scope parent) {
this.parent = parent;
}
public Object lookupSymbol(String symbolName) {
if (this.symbolsMapping.containsKey(symbolName)) {
return this.symbolsMapping.get(symbolName);
}
else if (this.parent != null) {
return this.parent.lookupSymbol(symbolName);
}
else {
throw new RuntimeException(String.format("Variable '%s' is not defined in this scope.",
symbolName));
}
}
public void insertSymbol(String symbolName, Object symbolValue) {
this.symbolsMapping.put(symbolName, symbolValue);
}
}

View File

@ -0,0 +1,30 @@
package serene.simple;
public class SpecialForm extends Node {
private static final SymbolNode DEF = new SymbolNode("def");
private static final SymbolNode FN = new SymbolNode("fn");
private static final SymbolNode IF = new SymbolNode("if");
private static final SymbolNode QUOTE = new SymbolNode("quote");
private final ListNode node;
public SpecialForm(ListNode node) {
this.node = node;
}
public static Node check(ListNode l) {
if (l == ListNode.EMPTY) {
return l;
} else if (l.first.equals(DEF)) {
return new DefSpecialForm(l);
} else if (l.first.equals(FN)) {
return new FnSpecialForm(l);
} else if (l.first.equals(IF)) {
return new IfSpecialForm(l);
} else if (l.first.equals(QUOTE)) {
return new QuoteSpecialForm(l);
}
return l;
}
}

View File

@ -0,0 +1,14 @@
package serene.simple;
public class SymbolNode extends Node {
private final String name;
public SymbolNode(String name) {
this.name = name;
}
@Override
public Object eval(Scope scope) {
return scope.lookupSymbol(this.name);
}
}