RootScope and support for Built in function has been added

This commit is contained in:
Sameer Rahmani 2019-12-19 22:57:04 +00:00
parent 709346311a
commit 79312f29ff
19 changed files with 401 additions and 283 deletions

View File

@ -0,0 +1,34 @@
package serene.simple;
import java.util.HashMap;
import java.util.Map;
public abstract class BaseScope {
private final Map<String, Object> symbolsMapping = new HashMap<String, Object>();
private final BaseScope parent;
public BaseScope() {
this(null);
}
public BaseScope(BaseScope 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

@ -6,7 +6,7 @@ public class DefSpecialForm extends SpecialForm {
}
@Override
public Object eval(Scope scope) {
public Object eval(BaseScope scope) {
SymbolNode sym = (SymbolNode) this.node.rest().first();
scope.insertSymbol(sym.name,
this.node.rest().rest().first().eval(scope));

View File

@ -4,7 +4,7 @@ public class FalseNode extends Node {
public boolean isTruthy = false;
@Override
public Object eval(Scope scope) {
public Object eval(BaseScope scope) {
return Boolean.FALSE;
}

View File

@ -8,7 +8,7 @@ public class FnSpecialForm extends SpecialForm {
}
@Override
public Object eval(final Scope parentScope) {
public Object eval(final BaseScope parentScope) {
final ListNode<Node> formalParams = (ListNode<Node>) this.node.rest().first();
final ListNode<Node> body = this.node.rest().rest();

View File

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

View File

@ -2,7 +2,6 @@ package serene.simple;
public class IfSpecialForm extends SpecialForm {
private Node pred;
private Node ifNode;
private Node elseNode;
@ -15,7 +14,7 @@ public class IfSpecialForm extends SpecialForm {
}
@Override
public Object eval(final Scope scope) {
public Object eval(final BaseScope scope) {
Object result = this.pred.eval(scope);
if (result == null || (result instanceof Boolean && (Boolean) result == false)) {
return this.elseNode.eval(scope);

View File

@ -4,6 +4,9 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import serene.simple.builtin.AFn;
import static java.util.Arrays.asList;
public class ListNode<T extends Node> extends Node implements Iterable<T> {
@ -43,14 +46,29 @@ public class ListNode<T extends Node> extends Node implements Iterable<T> {
}
@Override
public Object eval(Scope scope) {
Function<Object, Object> f = (Function) this.first().eval(scope);
public Object eval(BaseScope scope) {
Object f = this.first().eval(scope);
List<Object> args = new ArrayList<Object>();
for (T node : this.rest()) {
args.add(node.eval(scope));
}
return f.apply(args.toArray());
if (f instanceof AFn) {
return evalBuiltin(scope, (AFn) f, args);
}
else {
return evalFn(scope, (Function<Object, Object>) f, args);
}
}
public Object evalBuiltin(BaseScope scope, AFn fn, List<Object> args) {
fn.setArguments(args);
return fn.eval(scope);
}
public Object evalFn(BaseScope scope, Function<Object, Object> fn, List<Object> args) {
return fn.apply(args.toArray());
}
public T first() {

View File

@ -19,7 +19,7 @@ public class Main {
}
private static void startRepl() throws IOException {
Scope rootScope = Scope.getRootScope();
BaseScope rootScope = new RootScope();
Console console = System.console();
@ -60,7 +60,7 @@ public class Main {
}
private static void runSerene(String filePath) throws IOException {
Scope rootScope = Scope.getRootScope();
BaseScope rootScope = new RootScope();
ListNode<Node> nodes = Reader.read(new FileInputStream(filePath));

View File

@ -4,7 +4,7 @@ public class NilNode extends Node {
public boolean isTruthy = false;
@Override
public Object eval(Scope scope) {
public Object eval(BaseScope scope) {
return null;
}

View File

@ -3,7 +3,7 @@ package serene.simple;
public abstract class Node {
public boolean isTruthy = true;
public abstract Object eval(Scope scope);
public abstract Object eval(BaseScope scope);
public boolean equals(Node n) {
return this == n;

View File

@ -8,7 +8,7 @@ public class NumberNode extends Node {
}
@Override
public Object eval(Scope scope) {
public Object eval(BaseScope scope) {
return this.value;
}

View File

@ -1,11 +1,6 @@
package serene.simple;
public class QuoteSpecialForm extends SpecialForm {
// public QuoteSpecialForm(Node node) {
// this.x = node;
// }
public QuoteSpecialForm(ListNode<Node> node) throws SereneException {
super(node);
@ -15,7 +10,7 @@ public class QuoteSpecialForm extends SpecialForm {
}
@Override
public Object eval(final Scope scope) {
public Object eval(final BaseScope scope) {
return this.node.rest().first();
}
}

View File

@ -0,0 +1,42 @@
package serene.simple;
import java.util.HashMap;
import java.util.Map;
import serene.simple.builtin.AFn;
import serene.simple.builtin.PrintlnFn;
public class RootScope extends BaseScope {
private final BaseScope parent;
private final HashMap<String, Object> symbolsMapping = new HashMap<String, Object>() {{
put("println", new PrintlnFn());
}};
// "+", PlusFn,
// "-", MinusFn,
// "*", TimesFn,
// "/", ObelusFn,
// "mod", ModFn,
// "now", NowFn,
public RootScope() {
this.parent = null;
System.out.println(this.symbolsMapping.get("println"));
}
@Override
public Object lookupSymbol(String symbolName) {
if (this.symbolsMapping.containsKey(symbolName)) {
return this.symbolsMapping.get(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

@ -1,38 +1,14 @@
package serene.simple;
import java.util.HashMap;
public class Scope {
private final HashMap<String, Object> symbolsMapping = new HashMap<String, Object>();
private final Scope parent;
private static final Scope root = new Scope(null);
public class Scope extends BaseScope{
private final BaseScope parent;
public Scope() {
this(null);
this(new RootScope());
}
public Scope(Scope parent) {
public Scope(BaseScope 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);
}
public static Scope getRootScope() {
return Scope.root;
}
}

View File

@ -32,7 +32,7 @@ public class SpecialForm extends Node {
}
@Override
public Object eval(Scope scope) throws SereneException {
public Object eval(BaseScope scope) throws SereneException {
throw new SereneException("Can't use SpecialForm directly");
}
}

View File

@ -22,7 +22,7 @@ public class SymbolNode extends Node {
}
@Override
public Object eval(Scope scope) {
public Object eval(BaseScope scope) {
return scope.lookupSymbol(this.name);
}

View File

@ -2,7 +2,7 @@ package serene.simple;
public class TrueNode extends Node {
@Override
public Object eval(Scope scope) {
public Object eval(BaseScope scope) {
return true;
}

View File

@ -0,0 +1,31 @@
package serene.simple.builtin;
import java.util.Collections;
import java.util.List;
import serene.simple.Node;
public abstract class AFn extends Node {
private List<Object> args;
public void setArguments() {
this.args = Collections.EMPTY_LIST;
}
public void setArguments(List<Object> args) {
this.args = args;
}
public List<Object> arguments() {
return this.args;
}
public abstract String fnName();
@Override
public String toString() {
return String.format("BuiltinFn<%s>", this.fnName());
}
}

View File

@ -0,0 +1,23 @@
package serene.simple.builtin;
import serene.simple.BaseScope;
public class PrintlnFn extends AFn {
public String fnName() {
return "println";
};
public Object eval(BaseScope scope) {
String output = "";
for(Object x: this.arguments()) {
output = String.format(
"%s %s", output,
(String) x.toString());
}
System.out.println(output);
return null;
}
}