Base implementation has been done

This commit is contained in:
Sameer Rahmani 2019-12-14 02:42:25 +00:00
parent a5265c353e
commit 5f54615465
16 changed files with 273 additions and 27 deletions

View File

@ -1,6 +1,7 @@
plugins { plugins {
id 'java' id 'java'
id 'application' id 'application'
id "net.java.openjdk.shinyafox.jshell.gradle.plugin" version "1.0.4"
} }
repositories { repositories {
@ -21,3 +22,16 @@ jar {
attributes 'Main-Class': 'serene.simple.Main' attributes 'Main-Class': 'serene.simple.Main'
} }
} }
// run {
// standardInput = System.in
// }
task repl(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = 'serene.simple.Main'
standardInput = System.in
}

View File

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

View File

@ -0,0 +1,10 @@
package serene.simple;
public class FalseNode extends Node {
public boolean isTruthy = false;
@Override
public Object eval(Scope scope) {
return false;
}
}

View File

@ -9,22 +9,28 @@ public class FnSpecialForm extends SpecialForm {
@Override @Override
public Object eval(final Scope parentScope) { public Object eval(final Scope parentScope) {
final ListNode formalParams = (ListNode) this.node.rest.far; final ListNode<Node> formalParams = (ListNode<Node>) this.node.rest().first();
final ListNode body = this.node.rest.rest; final ListNode<Node> body = this.node.rest().rest();
return new Function() {
return new Function<Object, Object>() {
@Override @Override
public Object apply(Object arg) {
Object args[] = {arg};
return this.apply(args);
}
public Object apply(Object... args) { public Object apply(Object... args) {
Scope scope = new Scope(parentScope); Scope scope = new Scope(parentScope);
if (args.length != formalParams.length()) { if (args.length != formalParams.length) {
throw new RuntimeException(String.format("Wrong number of arguments. Expected: %s, Got: %s.", throw new RuntimeException(String.format("Wrong number of arguments. Expected: %s, Got: %s.",
formalParams.length(), formalParams.length,
args.length)); args.length));
} }
// Map parameter values to formal parameter names // Map parameter values to formal parameter names
int i = 0; int i = 0;
for (Node param : formalParams) { for (Node param : formalParams) {
SymbolNode paramSymbol = (SymbolNode) param; SymbolNode paramSymbol = (SymbolNode) param;
scope.putValue(paramSymbol.name, args[i]); scope.insertSymbol(paramSymbol.name, args[i]);
i++; i++;
} }

View File

@ -0,0 +1,25 @@
package serene.simple;
public class IfSpecialForm extends SpecialForm {
private Node pred;
private Node ifNode;
private Node elseNode;
public IfSpecialForm(ListNode<Node> l) {
super(l);
this.pred = l.rest().first();
this.ifNode = l.rest().rest().first();
this.elseNode = l.rest().rest().rest().first();
}
@Override
public Object eval(final Scope scope) {
Object result = this.pred.eval(scope);
if (result == null) {
return this.elseNode.eval(scope);
}
return this.ifNode.eval(scope);
}
}

View File

@ -1,18 +1,97 @@
package serene.simple; package serene.simple;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import static java.util.Arrays.asList;
public class ListNode<T extends Node> extends Node implements Iterable<T> {
public static final ListNode<?> EMPTY = new ListNode<>();
public final T first;
public final ListNode<T> rest;
public final int length;
public ListNode() {
this.first = null;
this.rest = null;
this.length = 0;
}
public ListNode(T f, ListNode<T> r) {
this.first = f;
this.rest = r;
this.length = r.length + 1;
}
@SafeVarargs
public static <T extends Node> ListNode<T> list(T... objs) {
return list(asList(objs));
}
public static <T extends Node> ListNode<T> list(List<T> objs) {
ListNode<T> l = (ListNode<T>) EMPTY;
for (int i = objs.size() - 1; i >= 0; i--) {
l = l.cons(objs.get(i));
}
return l;
}
public ListNode<T> cons(T node) {
return new ListNode<T>(node, this);
}
public class ListNode extends Node implements Iterable<Node> {
@Override @Override
public Object eval(Scope scope) { public Object eval(Scope scope) {
Function f = (Function) this.first.eval(scope); Function f = (Function) this.first.eval(scope);
List<Object> args = new ArrayList<Object>(); List<Object> args = new ArrayList<Object>();
for (Node node : this.first) { for (T node : this.rest) {
args.add(node.eval(scope)); args.add(node.eval(scope));
} }
return f.apply(args.toArray()); return f.apply(args.toArray());
} }
public T first() {
if (this != EMPTY) {
return this.first;
}
return null;
}
public ListNode<T> rest() {
if (this != EMPTY) {
return this.rest;
}
return (ListNode<T>) EMPTY;
}
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
private ListNode<T> l = ListNode.this;
@Override
public boolean hasNext() {
return this.l != EMPTY;
}
@Override
public T next() {
if (this.l == EMPTY) {
return null;
}
T first = this.l.first;
this.l = this.l.rest;
return first;
}
@Override
public void remove() {
throw new SereneException("Iterator is immutable");
}
};
}
} }

View File

@ -1,6 +1,9 @@
package serene.simple; package serene.simple;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.Console; import java.io.Console;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -10,19 +13,25 @@ public class Main {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
if (args.length == 0) { if (args.length == 0) {
startRepl(); startRepl();
return;
} }
runSerene(args[0]); runSerene(args[0]);
} }
private static void startRepl() { private static void startRepl() throws IOException {
Scope rootScope = Scope.getRootScope(); Scope rootScope = Scope.getRootScope();
Console console = System.console(); //Console console = System.console();
//BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Scanner in = new Scanner(System.in);
System.out.println("Serene 'simple' v0.1.0");
while(true) { while(true) {
String inputData = console.readLine("serene-> "); System.out.print("serene-> ");
//String inputData = reader.readLine();
String inputData = in.nextLine();
if (expr == null) break; if (inputData == null) break;
ByteArrayInputStream inputStream = new ByteArrayInputStream(inputData.getBytes()); ByteArrayInputStream inputStream = new ByteArrayInputStream(inputData.getBytes());
ListNode<Node> nodes = Reader.read(inputStream); ListNode<Node> nodes = Reader.read(inputStream);
@ -37,6 +46,7 @@ public class Main {
System.out.println(result); System.out.println(result);
} }
} }
in.close();
} }

View File

@ -0,0 +1,10 @@
package serene.simple;
public class NilNode extends Node {
public boolean isTruthy = false;
@Override
public Object eval(Scope scope) {
return this;
}
}

View File

@ -1,5 +1,7 @@
package serene.simple; package serene.simple;
public abstract class Node { public abstract class Node {
public boolean isTruthy = true;
public abstract Object eval(Scope scope); public abstract Object eval(Scope scope);
} }

View File

@ -0,0 +1,13 @@
package serene.simple;
public class QuoteSpecialForm extends SpecialForm {
public QuoteSpecialForm(ListNode node) {
super(node);
}
@Override
public Object eval(final Scope scope) {
return this.node;
}
}

View File

@ -2,8 +2,10 @@ package serene.simple;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.PushbackReader; import java.io.PushbackReader;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -19,29 +21,31 @@ public class Reader {
return readNumber(inputStream); return readNumber(inputStream);
} }
else if (c == ')') { else if (c == ')') {
throw new IllegalArgumentException("Unmatch paranthesis.") throw new IllegalArgumentException("Unmatch paranthesis.");
} }
else { else {
return readSymbol(inputStream); return readSymbol(inputStream);
} }
} }
public static ListNode read(InputStream inputStream) throws IOException { public static ListNode<Node> read(InputStream inputStream) throws IOException {
return read(new PushbackReader(new InputStreamReader(inputStream))); return read(new PushbackReader(new InputStreamReader(inputStream)));
} }
public static ListNode read(PushbackReader inputStream) throws IOException { public static ListNode<Node> read(PushbackReader inputStream) throws IOException {
List<Node> nodes = new ArrayList<Node>(); List<Node> nodes = new ArrayList<Node>();
skipWhitespaces(inputStream); skipWhiteSpaces(inputStream);
char c = inputStream.read(); char c = (char) inputStream.read();
while ((byte) c != -1) { while ((byte) c != -1) {
inputStream.unread(c); inputStream.unread(c);
nodes.add(readNode(inputStream)); nodes.add(readNode(inputStream));
skipWhitespaces(inputStream); skipWhiteSpaces(inputStream);
c = (char) inputStream.read(); c = (char) inputStream.read();
} }
return ListNode.list(nodes);
} }
private static Node readList(PushbackReader inputStream) throws IOException { private static Node readList(PushbackReader inputStream) throws IOException {
@ -51,7 +55,7 @@ public class Reader {
List<Node> nodes = new ArrayList<Node>(); List<Node> nodes = new ArrayList<Node>();
do { do {
skipWhitespaces(inputStream); skipWhiteSpaces(inputStream);
char c = (char) inputStream.read(); char c = (char) inputStream.read();
if (c == ')') { if (c == ')') {
@ -63,6 +67,51 @@ public class Reader {
nodes.add(readNode(inputStream)); nodes.add(readNode(inputStream));
} }
} while(true); } while(true);
return SpecialForm(ListNode.list(nodes));
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)) {
inputStream.unread(ch);
break;
};
str = str + (char) ch;
}
return new SymbolNode(str);
}
private static Node readNumber(PushbackReader inputStream) throws IOException {
String number = "";
while (true) {
int ch = inputStream.read();
if(isWhiteSpace(ch)) {
inputStream.unread(ch);
break;
};
number = number + (char) ch;
}
return new NumberNode(Long.parseLong(number, 10));
}
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');
} }
} }

View File

@ -5,6 +5,7 @@ import java.util.HashMap;
public class Scope { public class Scope {
private final HashMap<String, Object> symbolsMapping = new HashMap<String, Object>(); private final HashMap<String, Object> symbolsMapping = new HashMap<String, Object>();
private final Scope parent; private final Scope parent;
private static final Scope root = new Scope(null);
public Scope() { public Scope() {
this(null); this(null);
@ -30,4 +31,8 @@ public class Scope {
public void insertSymbol(String symbolName, Object symbolValue) { public void insertSymbol(String symbolName, Object symbolValue) {
this.symbolsMapping.put(symbolName, symbolValue); this.symbolsMapping.put(symbolName, symbolValue);
} }
public static Scope getRootScope() {
return Scope.root;
}
} }

View File

@ -0,0 +1,10 @@
package serene.simple;
class SereneException extends RuntimeException {
private static final long serialVersionUID = 1L;
public SereneException(String message) {
super(message);
}
}

View File

@ -7,13 +7,13 @@ public class SpecialForm extends Node {
private static final SymbolNode IF = new SymbolNode("if"); private static final SymbolNode IF = new SymbolNode("if");
private static final SymbolNode QUOTE = new SymbolNode("quote"); private static final SymbolNode QUOTE = new SymbolNode("quote");
private final ListNode node; public final ListNode<Node> node;
public SpecialForm(ListNode node) { public SpecialForm(ListNode<Node> node) {
this.node = node; this.node = node;
} }
public static Node check(ListNode l) { public static Node check(ListNode<Node> l) {
if (l == ListNode.EMPTY) { if (l == ListNode.EMPTY) {
return l; return l;
} else if (l.first.equals(DEF)) { } else if (l.first.equals(DEF)) {
@ -27,4 +27,9 @@ public class SpecialForm extends Node {
} }
return l; return l;
} }
@Override
public Object eval(Scope scope) {
throw new SereneException("Can't use SpecialForm directly");
}
} }

View File

@ -1,7 +1,7 @@
package serene.simple; package serene.simple;
public class SymbolNode extends Node { public class SymbolNode extends Node {
private final String name; public final String name;
public SymbolNode(String name) { public SymbolNode(String name) {
this.name = name; this.name = name;

View File

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