Skip to content

Commit

Permalink
Implement REPL and add the main entrance
Browse files Browse the repository at this point in the history
  • Loading branch information
predatorray committed Feb 19, 2016
1 parent 3b2ba61 commit 1122fd3
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.java eol=crlf
*.xml eol=crlf
*.bud eol=crlf
121 changes: 121 additions & 0 deletions src/main/java/me/predatorray/bud/lisp/BudRepl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package me.predatorray.bud.lisp;

import me.predatorray.bud.lisp.buitin.BuiltinsEnvironment;
import me.predatorray.bud.lisp.evaluator.EvaluatingException;
import me.predatorray.bud.lisp.evaluator.Evaluator;
import me.predatorray.bud.lisp.evaluator.NaiveEvaluator;
import me.predatorray.bud.lisp.lang.BudObject;
import me.predatorray.bud.lisp.lang.Environment;
import me.predatorray.bud.lisp.lexer.Lexer;
import me.predatorray.bud.lisp.lexer.LexerException;
import me.predatorray.bud.lisp.lexer.Token;
import me.predatorray.bud.lisp.parser.Expression;
import me.predatorray.bud.lisp.parser.Parser;
import me.predatorray.bud.lisp.parser.ParserException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

public class BudRepl {

private final Evaluator evaluator;
private final Environment initial;

private final boolean interactive;

public BudRepl() {
this.evaluator = new NaiveEvaluator();
this.initial = BuiltinsEnvironment.INSTANCE;
this.interactive = true;
}

private class ReplParserCallback implements Parser.ParserCallback {

private final PrintWriter stdPrintWriter;

private boolean evaluated = true;

ReplParserCallback(PrintWriter stdPrintWriter) {
this.stdPrintWriter = stdPrintWriter;
}

@Override
public void expressionReady(Expression expression) {
evaluated = true;
BudObject evaluated = evaluator.evaluate(expression, initial);
if (evaluated != null) {
stdPrintWriter.println(evaluated.toString());
stdPrintWriter.flush();
}
}

public boolean hasAnyExpressionBeenEvaluated() {
boolean consumed = evaluated;
evaluated = false;
return consumed;
}
}

public void execute(Reader reader, final Writer writer, Writer errorWriter) throws IOException {
BufferedReader lineReader = new BufferedReader(reader);
final PrintWriter stdPrintWriter = toPrintWriter(writer);
final PrintWriter errPrintWriter = toPrintWriter(errorWriter);

ReplParserCallback replParserCallback = new ReplParserCallback(stdPrintWriter);
Parser parser = new Parser(replParserCallback);

boolean exceptionOccurred = false;
while (true) {
try {
if (interactive) {
if (replParserCallback.hasAnyExpressionBeenEvaluated() || exceptionOccurred) {
stdPrintWriter.print("bud> ");
} else {
stdPrintWriter.print(" > ");
}
stdPrintWriter.flush();
}

String line = lineReader.readLine();
if (line == null) {
break;
}

// TODO if ended with backslash
Lexer lexer = new Lexer(line);
Iterator<Token> tokenIterator = lexer.iterator();
parser.feed(tokenIterator);
exceptionOccurred = false;
} catch (LexerException | ParserException | EvaluatingException e) {
PrintWriter target = (interactive ? stdPrintWriter : errPrintWriter);
target.println(e.getLocalizedMessage());
target.flush();
exceptionOccurred = true;
}
}
}

private PrintWriter toPrintWriter(Writer writer) {
return writer instanceof PrintWriter ? ((PrintWriter) writer) : new PrintWriter(writer);
}

public static void main(String... args) throws Exception {
BudRepl repl = new BudRepl();
Charset replEncoding = StandardCharsets.UTF_8;
try {
repl.execute(new InputStreamReader(System.in, replEncoding),
new OutputStreamWriter(System.out, replEncoding),
new OutputStreamWriter(System.err, replEncoding));
} catch (Exception unknownException) {
unknownException.printStackTrace();
}
}
}
5 changes: 5 additions & 0 deletions src/main/java/me/predatorray/bud/lisp/lang/Symbol.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,9 @@ public boolean equals(Object o) {
public int hashCode() {
return name.hashCode();
}

@Override
public String toString() {
return name;
}
}
1 change: 0 additions & 1 deletion src/main/java/me/predatorray/bud/lisp/lexer/Lexer.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ public Token next() {
}
break;
case AFTER_SHARP:
// TODO
if (currChar == 't' || currChar == 'T') {
state = TokenizerState.NORMAL;
return new BooleanToken(true, getBoolOrCharLocation());
Expand Down
33 changes: 32 additions & 1 deletion src/main/java/me/predatorray/bud/lisp/parser/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,32 @@
import me.predatorray.bud.lisp.parser.datum.DatumParserVisitor;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Parser {

private final DatumParserVisitor visitor;

public Parser() {
this(null);
}

public Parser(final ParserCallback parserCallback) {
if (parserCallback == null) {
visitor = new DatumParserVisitor();
} else {
visitor = new DatumParserVisitor() {
@Override
protected void rootDatumReady(Datum datumAtStackBottom) {
Expression expression = datumAtStackBottom.getExpression();
parserCallback.expressionReady(expression);
}
};
}
}

public List<Expression> parse(Iterable<? extends Token> tokens) {
DatumParserVisitor visitor = new DatumParserVisitor();
for (Token token : tokens) {
token.accept(visitor);
}
Expand All @@ -21,4 +41,15 @@ public List<Expression> parse(Iterable<? extends Token> tokens) {
}
return expressions;
}

public void feed(Iterator<? extends Token> tokenIterator) {
while (tokenIterator.hasNext()) {
tokenIterator.next().accept(visitor);
}
}

public interface ParserCallback {

void expressionReady(Expression expression);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import me.predatorray.bud.lisp.lexer.TokenVisitor;
import me.predatorray.bud.lisp.parser.ParserException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
Expand All @@ -24,10 +25,12 @@ public class DatumParserVisitor implements TokenVisitor {
private final SingleQuoteRecorder singleQuoteRecorder = new SingleQuoteRecorder();

private final Stack<List<Datum>> dataStack;
private final List<Datum> bottom;

public DatumParserVisitor() {
dataStack = new Stack<>();
dataStack.push(new LinkedList<Datum>());
bottom = new LinkedList<>();
dataStack.push(bottom);
}

private void appendOnTopOfStack(Datum datum) {
Expand All @@ -36,6 +39,13 @@ private void appendOnTopOfStack(Datum datum) {
throw new ParserException("parentheses are not balanced");
}
top.add(datum);
if (top == bottom) {
rootDatumReady(datum);
}
}

protected void rootDatumReady(Datum datumAtStackBottom) {
// does nothing
}

private void appendOnTopOfStackQuoteIfRequired(Datum datum, Token token) {
Expand Down Expand Up @@ -126,6 +136,6 @@ public List<Datum> getRootData() {
if (!parenthesisChecker.isBalanced()) {
throw new ParserException("parentheses are not balanced");
}
return dataStack.peek();
return new ArrayList<>(bottom);
}
}

0 comments on commit 1122fd3

Please sign in to comment.