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 {
id 'java'
id 'application'
id "net.java.openjdk.shinyafox.jshell.gradle.plugin" version "1.0.4"
}
repositories {
@ -21,3 +22,16 @@ jar {
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
public Object eval(Scope scope) {
SymbolNode sym = (SymbolNode) this.node.rest.first;
scope.putValue(sym.name,
this.node.rest.rest.first.eval(scope));
SymbolNode sym = (SymbolNode) this.node.rest().first();
scope.insertSymbol(sym.name,
this.node.rest().rest().first().eval(scope));
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
public Object eval(final Scope parentScope) {
final ListNode formalParams = (ListNode) this.node.rest.far;
final ListNode body = this.node.rest.rest;
return new Function() {
final ListNode<Node> formalParams = (ListNode<Node>) this.node.rest().first();
final ListNode<Node> body = this.node.rest().rest();
return new Function<Object, Object>() {
@Override
public Object apply(Object arg) {
Object args[] = {arg};
return this.apply(args);
}
public Object apply(Object... args) {
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.",
formalParams.length(),
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]);
scope.insertSymbol(paramSymbol.name, args[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;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
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
public Object eval(Scope scope) {
Function f = (Function) this.first.eval(scope);
List<Object> args = new ArrayList<Object>();
for (Node node : this.first) {
for (T node : this.rest) {
args.add(node.eval(scope));
}
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;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.Console;
import java.io.FileInputStream;
@ -10,19 +13,25 @@ public class Main {
public static void main(String[] args) throws IOException {
if (args.length == 0) {
startRepl();
return;
}
runSerene(args[0]);
}
private static void startRepl() {
private static void startRepl() throws IOException {
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) {
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());
ListNode<Node> nodes = Reader.read(inputStream);
@ -37,6 +46,7 @@ public class Main {
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;
public abstract class Node {
public boolean isTruthy = true;
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.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PushbackReader;
import java.util.ArrayList;
import java.util.List;
@ -19,29 +21,31 @@ public class Reader {
return readNumber(inputStream);
}
else if (c == ')') {
throw new IllegalArgumentException("Unmatch paranthesis.")
throw new IllegalArgumentException("Unmatch paranthesis.");
}
else {
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)));
}
public static ListNode read(PushbackReader inputStream) throws IOException {
public static ListNode<Node> read(PushbackReader inputStream) throws IOException {
List<Node> nodes = new ArrayList<Node>();
skipWhitespaces(inputStream);
skipWhiteSpaces(inputStream);
char c = inputStream.read();
char c = (char) inputStream.read();
while ((byte) c != -1) {
inputStream.unread(c);
nodes.add(readNode(inputStream));
skipWhitespaces(inputStream);
skipWhiteSpaces(inputStream);
c = (char) inputStream.read();
}
return ListNode.list(nodes);
}
private static Node readList(PushbackReader inputStream) throws IOException {
@ -51,7 +55,7 @@ public class Reader {
List<Node> nodes = new ArrayList<Node>();
do {
skipWhitespaces(inputStream);
skipWhiteSpaces(inputStream);
char c = (char) inputStream.read();
if (c == ')') {
@ -63,6 +67,51 @@ public class Reader {
nodes.add(readNode(inputStream));
}
} 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 {
private final HashMap<String, Object> symbolsMapping = new HashMap<String, Object>();
private final Scope parent;
private static final Scope root = new Scope(null);
public Scope() {
this(null);
@ -30,4 +31,8 @@ public class Scope {
public void insertSymbol(String symbolName, Object 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 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;
}
public static Node check(ListNode l) {
public static Node check(ListNode<Node> l) {
if (l == ListNode.EMPTY) {
return l;
} else if (l.first.equals(DEF)) {
@ -27,4 +27,9 @@ public class SpecialForm extends Node {
}
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;
public class SymbolNode extends Node {
private final String name;
public final String name;
public SymbolNode(String 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;
}
}