mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
В REPL добавлен вывод функций, переменных и всего исходника
This commit is contained in:
parent
e326cb7d5d
commit
c9249e8577
@ -1,6 +1,5 @@
|
||||
package com.annimon.ownlang;
|
||||
|
||||
import com.annimon.ownlang.exceptions.LexerException;
|
||||
import com.annimon.ownlang.exceptions.StoppedException;
|
||||
import com.annimon.ownlang.parser.Beautifier;
|
||||
import com.annimon.ownlang.parser.Lexer;
|
||||
@ -11,10 +10,10 @@ import com.annimon.ownlang.parser.SourceLoader;
|
||||
import com.annimon.ownlang.parser.Token;
|
||||
import com.annimon.ownlang.parser.ast.Statement;
|
||||
import com.annimon.ownlang.parser.visitors.FunctionAdder;
|
||||
import com.annimon.ownlang.utils.Repl;
|
||||
import com.annimon.ownlang.utils.TimeMeasurement;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@ -22,7 +21,7 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
public final class Main {
|
||||
|
||||
private static final String VERSION = "1.2.0";
|
||||
public static final String VERSION = "1.2.0";
|
||||
|
||||
private static String[] ownlangArgs = new String[0];
|
||||
|
||||
@ -97,7 +96,7 @@ public final class Main {
|
||||
|
||||
case "-r":
|
||||
case "--repl":
|
||||
repl();
|
||||
Repl.main(new String[0]);
|
||||
return;
|
||||
|
||||
case "-l":
|
||||
@ -192,46 +191,6 @@ public final class Main {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void repl() {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
final Scanner scanner = new Scanner(System.in);
|
||||
System.out.println("Welcome to OwnLang " + VERSION + " REPL\n"
|
||||
+ "Type in expressions to have them evaluated.\n"
|
||||
+ "Type :reset to clear buffer.\n"
|
||||
+ "Type :exit to exit REPL.");
|
||||
while (true) {
|
||||
System.out.print((buffer.length() == 0) ? "\n> " : " ");
|
||||
|
||||
if (!scanner.hasNextLine()) break;
|
||||
|
||||
final String line = scanner.nextLine();
|
||||
if (":exit".equalsIgnoreCase(line)) break;
|
||||
if (":reset".equalsIgnoreCase(line)) {
|
||||
buffer.setLength(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer.append(line).append(System.lineSeparator());
|
||||
try {
|
||||
final List<Token> tokens = Lexer.tokenize(buffer.toString());
|
||||
final Parser parser = new Parser(tokens);
|
||||
final Statement program = parser.parse();
|
||||
if (parser.getParseErrors().hasErrors()) {
|
||||
continue;
|
||||
}
|
||||
program.execute();
|
||||
} catch (LexerException lex) {
|
||||
continue;
|
||||
} catch (StoppedException ex) {
|
||||
// skip
|
||||
} catch (Exception ex) {
|
||||
Console.handleException(Thread.currentThread(), ex);
|
||||
}
|
||||
buffer.setLength(0);
|
||||
}
|
||||
scanner.close();
|
||||
}
|
||||
|
||||
private static class Options {
|
||||
boolean showTokens, showAst, showMeasurements;
|
||||
|
140
src/main/java/com/annimon/ownlang/utils/Repl.java
Normal file
140
src/main/java/com/annimon/ownlang/utils/Repl.java
Normal file
@ -0,0 +1,140 @@
|
||||
package com.annimon.ownlang.utils;
|
||||
|
||||
import com.annimon.ownlang.Console;
|
||||
import com.annimon.ownlang.Main;
|
||||
import com.annimon.ownlang.exceptions.LexerException;
|
||||
import com.annimon.ownlang.exceptions.StoppedException;
|
||||
import com.annimon.ownlang.lib.Functions;
|
||||
import com.annimon.ownlang.lib.UserDefinedFunction;
|
||||
import com.annimon.ownlang.lib.Variables;
|
||||
import com.annimon.ownlang.parser.Lexer;
|
||||
import com.annimon.ownlang.parser.Parser;
|
||||
import com.annimon.ownlang.parser.Token;
|
||||
import com.annimon.ownlang.parser.ast.BlockStatement;
|
||||
import com.annimon.ownlang.parser.ast.Statement;
|
||||
import com.annimon.ownlang.parser.visitors.PrintVisitor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class Repl {
|
||||
|
||||
private static final String
|
||||
HELP = ":help",
|
||||
VARS = ":vars",
|
||||
FUNCS = ":funcs",
|
||||
SOURCE = ":source",
|
||||
RESET = ":reset",
|
||||
EXIT = ":exit";
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Welcome to OwnLang " + Main.VERSION + " REPL");
|
||||
printHelp(false);
|
||||
|
||||
final BlockStatement history = new BlockStatement();
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
final Scanner scanner = new Scanner(System.in);
|
||||
while (true) {
|
||||
System.out.print((buffer.length() == 0) ? "\n> " : " ");
|
||||
|
||||
if (!scanner.hasNextLine()) break;
|
||||
|
||||
final String line = scanner.nextLine();
|
||||
if (EXIT.equalsIgnoreCase(line)) break;
|
||||
switch (line.toLowerCase(Locale.ENGLISH)) {
|
||||
case RESET:
|
||||
buffer.setLength(0);
|
||||
continue;
|
||||
case HELP:
|
||||
printHelp(true);
|
||||
continue;
|
||||
case VARS:
|
||||
printVariables();
|
||||
continue;
|
||||
case FUNCS:
|
||||
printFunctions();
|
||||
continue;
|
||||
case SOURCE:
|
||||
System.out.println(history.accept(new PrintVisitor(), new StringBuilder()));
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer.append(line).append(System.lineSeparator());
|
||||
Statement program = null;
|
||||
try {
|
||||
final List<Token> tokens = Lexer.tokenize(buffer.toString());
|
||||
final Parser parser = new Parser(tokens);
|
||||
program = parser.parse();
|
||||
if (parser.getParseErrors().hasErrors()) {
|
||||
continue;
|
||||
}
|
||||
program.execute();
|
||||
} catch (LexerException lex) {
|
||||
continue;
|
||||
} catch (StoppedException ex) {
|
||||
// skip
|
||||
} catch (Exception ex) {
|
||||
Console.handleException(Thread.currentThread(), ex);
|
||||
}
|
||||
if (program != null) {
|
||||
history.add(program);
|
||||
}
|
||||
buffer.setLength(0);
|
||||
}
|
||||
scanner.close();
|
||||
}
|
||||
|
||||
private static void printHelp(boolean full) {
|
||||
System.out.println("Type in expressions to have them evaluated.");
|
||||
final List<String> commands = new ArrayList<>();
|
||||
if (full) {
|
||||
commands.add(VARS + " - listing variables");
|
||||
commands.add(FUNCS + " - listing functions");
|
||||
commands.add(SOURCE + " - listing source");
|
||||
}
|
||||
commands.add(HELP + " - show help");
|
||||
commands.add(RESET + " - clear buffer");
|
||||
commands.add(EXIT + " - exit REPL");
|
||||
|
||||
int maxLength = commands.stream()
|
||||
.mapToInt(String::length)
|
||||
.max().getAsInt();
|
||||
|
||||
final int maxCols = 2;
|
||||
final int size = commands.size();
|
||||
for (int i = 0; i < size; i += maxCols) {
|
||||
// Pad to max length and print in tab-separatex maxCols columns
|
||||
System.out.println(commands
|
||||
.subList(i, Math.min(size, i + maxCols))
|
||||
.stream()
|
||||
.map(str -> String.format("%-" + maxLength + "s", str))
|
||||
.collect(Collectors.joining("\t", " ", ""))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void printVariables() {
|
||||
Variables.variables().entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByKey())
|
||||
.forEach(e -> System.out.printf("\t%s = %s%n",
|
||||
e.getKey(), e.getValue().toString()));
|
||||
}
|
||||
|
||||
private static void printFunctions() {
|
||||
System.out.println("User functions:");
|
||||
Functions.getFunctions().entrySet().stream()
|
||||
.filter(p -> p.getValue() instanceof UserDefinedFunction)
|
||||
.sorted(Map.Entry.comparingByKey())
|
||||
.forEach(e -> System.out.printf("\t%s%s%n",
|
||||
e.getKey(), ((UserDefinedFunction)e.getValue()).arguments));
|
||||
|
||||
System.out.println("Library functions:");
|
||||
Functions.getFunctions().entrySet().stream()
|
||||
.filter(p -> !(p.getValue() instanceof UserDefinedFunction))
|
||||
.sorted(Map.Entry.comparingByKey())
|
||||
.forEach(e -> System.out.printf("\t%s%n", e.getKey()));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user