serene-simple/src/main/java/serene/simple/Main.java

189 lines
5.6 KiB
Java

/**
* Serene (simple) - A PoC lisp to collect data on Serenes concepts
* Copyright (C) 2019-2020 Sameer Rahmani <lxsameer@gnu.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package serene.simple;
import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.Console;
import java.io.FileInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* What is missing:
* * A namespace functionality. Because creating and compiling dynamic classes
* is a rabbit hole and tons of work which doesn't make sense for a toy
* project.
* * Unified function interface.
* * Requiring different namespaces
* * A sophisticated parser. My Reader implementation is really cheap that
* suits a toy project. It might worth investigating on different solutions
* including using a parser generator or a head of time read implementation.
* * Primitive functions in Serene. I implemented lots of primitive functions
* in java rather than Serene itself mostly because of two reasons. Lack of
* macros and namespaces.
* * Decent [functional] data structures. The only data structure I implemented
* is list.
* * Quality code. The general quality of this implementation is not great, I
* sacrificed quality for time.
*/
public class Main {
private static int port = 5544;
private static String host = "localhost";
private static String licenseHeader = "\nSerene(simple), Copyright (C) 2019-2020 " +
"Sameer Rahmani <lxsameer@gnu.org>\n" +
"Serene(simple) comes with ABSOLUTELY NO WARRANTY;\n" +
"This is free software, and you are welcome\n" +
"to redistribute it under certain conditions; \n" +
"for details take a look at the LICENSE file.\n";
public static void main(String[] args) throws IOException, RuntimeException {
if (args.length == 0) {
startRepl();
return;
}
if (args[0].equals("nrepl")) {
nrepl();
return;
}
runSerene(args[0]);
}
private static void startRepl() throws IOException {
RootScope rootScope = new RootScope();
Console console = System.console();
System.out.println("Serene 'simple' v0.1.0");
System.out.println(licenseHeader);
while(true) {
String inputData = console.readLine("serene-> ");
if (inputData == null) break;
ByteArrayInputStream inputStream = new ByteArrayInputStream(inputData.getBytes());
try {
ListNode<Node> nodes = Reader.read(inputStream);
Object result = ListNode.EMPTY;
for (Node n : nodes) {
result = n.eval(rootScope);
}
System.out.print(";; ");
if (result == null) {
System.out.println("nil");
}
else {
System.out.println(result.toString());
}
}
catch(Exception e) {
System.out.println("Error: ");
e.printStackTrace(System.out);
}
}
}
public static void nrepl() throws IOException {
RootScope rootScope = new RootScope();
ServerSocket socket = new ServerSocket(Main.port);;
System.out.println("Serene 'simple' v0.1.0");
System.out.println(licenseHeader);
System.out.println(
String.format("nRepl has been started on tcp://%s:%s", Main.host, Main.port));
try {
Socket clientSocket = socket.accept();
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while(true) {
String inputData = in.readLine();
if (inputData == null) break;
ByteArrayInputStream inputStream = new ByteArrayInputStream(inputData.getBytes());
try {
ListNode<Node> nodes = Reader.read(inputStream);
Object result = ListNode.EMPTY;
for (Node n : nodes) {
result = n.eval(rootScope);
}
if (result == null) {
out.println("0nil");
}
else {
out.println(
String.format("0%s", result.toString()));
}
}
catch(Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
out.println(
String.format("1%s", exceptionAsString));
}
}
}
catch (IOException e) {
System.out.println("Exception caught when trying to listen on port "
+ Main.port + " or listening for a connection");
System.out.println(e.getMessage());
}
finally {
socket.close();
}
}
private static void runSerene(String filePath) throws IOException {
IScope rootScope = new RootScope();
FileInputStream input = new FileInputStream(filePath);
ListNode<Node> nodes = Reader.read(input);
for (Node n : nodes) {
n.eval(rootScope);
}
}
}