basic interpreter kind of working

This commit is contained in:
nora 2021-01-17 12:57:21 +01:00
parent 6270363d96
commit 116ec117fa
12 changed files with 439 additions and 58 deletions

View file

@ -6,6 +6,7 @@ public class FunctionArgLookup {
return switch (name) {
case "Leorio.say" -> 1;
case "Leorio.listen" -> 0;
case "Wing.dump" -> 0;
default -> 0;
};
}

View file

@ -0,0 +1,36 @@
package com.github.nilstrieb.hunterlang.hllibrary;
import com.github.nilstrieb.hunterlang.interpreter.RuntimeException;
import com.github.nilstrieb.hunterlang.interpreter.Value;
import com.github.nilstrieb.hunterlang.lexer.WordType;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Scanner;
public class Leorio {
public static void say(Value s) {
System.out.println(s.toPrintString());
}
public static String listen() {
Scanner sc = new Scanner(System.in);
return sc.nextLine();
}
public static Value call(String name, Object[] args) throws RuntimeException {
switch (name) {
case "say" -> {
say((Value) args[0]);
return new Value();
}
case "listen" -> {
return new Value(listen(), WordType.STRING);
}
default -> {
throw new RuntimeException("function not found");
}
}
}
}

View file

@ -0,0 +1,15 @@
package com.github.nilstrieb.hunterlang.hllibrary;
import com.github.nilstrieb.hunterlang.interpreter.RuntimeException;
import com.github.nilstrieb.hunterlang.interpreter.Value;
public class Library {
public static Object call(String name, Object ... args) throws RuntimeException {
String[] parts = name.split("\\.");
return switch (parts[0]){
case "Leorio" -> Leorio.call(parts[1], args);
case "Wing" -> Wing.call(parts[1], args);
default -> throw new RuntimeException("Unexpected lib: " + parts[0]);
};
}
}

View file

@ -0,0 +1,30 @@
package com.github.nilstrieb.hunterlang.hllibrary;
import com.github.nilstrieb.hunterlang.interpreter.Memory;
import com.github.nilstrieb.hunterlang.interpreter.RuntimeException;
import com.github.nilstrieb.hunterlang.interpreter.Value;
import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
import java.util.ArrayList;
public class Wing {
public static void dump(Memory m) {
ArrayList<Value> list = m.getList();
for (int i = 0; i < list.size(); i++) {
Value value = list.get(i);
System.out.println(ConsoleColors.CYAN + i + ConsoleColors.YELLOW + " " + value + ConsoleColors.RESET);
}
}
public static Value call(String name, Object ... args) throws RuntimeException {
switch (name) {
case "dump" -> {
dump((Memory) args[0]);
return new Value();
}
default -> {
throw new RuntimeException("function not found");
}
}
}
}

View file

@ -0,0 +1,112 @@
package com.github.nilstrieb.hunterlang.interpreter;
import com.github.nilstrieb.hunterlang.hllibrary.Library;
import com.github.nilstrieb.hunterlang.hllibrary.Wing;
import com.github.nilstrieb.hunterlang.lexer.WordType;
import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
import com.github.nilstrieb.hunterlang.parser.ParseTreeBodyNode;
import com.github.nilstrieb.hunterlang.parser.ParseTreeNode;
import java.io.PrintStream;
import java.util.ArrayList;
public class Interpreter {
ArrayList<ParseTreeNode> statements;
Memory memory;
public void start(ArrayList<ParseTreeNode> statementNodes) throws RuntimeException {
System.out.println(ConsoleColors.GREEN_BACKGROUND + ConsoleColors.BLACK_BOLD + "------START INTERPRETER------" + ConsoleColors.RESET);
interpret(statementNodes);
System.out.println(ConsoleColors.GREEN_BACKGROUND + ConsoleColors.BLACK_BOLD + "------STOP INTERPRETER------" + ConsoleColors.RESET);
}
public void interpret(ArrayList<ParseTreeNode> statementNodes) throws RuntimeException {
statements = statementNodes;
memory = new Memory();
boolean lastIfTrue = false;
for (ParseTreeNode statement : statements) {
switch (statement.getKey()) {
case ASSIGNMENT -> {
ParseTreeNode memoryNode = statement.getChild(0);
ParseTreeNode valueNode = statement.getChild(1);
int memoryAdress = evaluateInt(memoryNode.getChild(0));
Value value = evaluate(valueNode);
memory.set(memoryAdress, value);
//Wing.dump(memory);
}
case IF -> {
if(evaluate(statement.getChild(0)).getBoolValue()){
lastIfTrue = true;
interpret(((ParseTreeBodyNode) statement).getStatements());
} else {
lastIfTrue = false;
}
}
case WANTS -> {
}
case ELSE -> {
}
case LIBFUNCCALL -> {
String call = statement.getValue();
ArrayList<ParseTreeNode> argsNode = statement.getChildren();
ArrayList<Value> args = new ArrayList<>();
for (ParseTreeNode parseTreeNode : argsNode) {
args.add(evaluate(parseTreeNode));
}
if (call.equals("Wing.dump")) {
Library.call(call, memory);
} else {
Library.call(call, args.toArray());
}
}
default -> {
throw new RuntimeException("illegal statement type: " + statement.getKey());
}
}
}
}
private int evaluateInt(ParseTreeNode parent) {
return evaluate(parent).getIntValue();
}
private Value evaluate(ParseTreeNode parent) {
switch (parent.getKey()) {
case MEMCALL -> {
return memory.get(evaluateInt(parent.getChild(0)));
}
case NUMBER -> {
return new Value(parent.getValue(), WordType.NUMBER);
}
case GTHAN -> {
Value v2 = evaluate(parent.getChild(1));
int comp = evaluate(parent.getChild(0)).compareTo(v2);
return comp > 0 ? new Value(true) : new Value(false);
}
case LTHAN -> {
int comp = evaluate(parent.getChild(0)).compareTo(evaluate(parent.getChild(1)));
return comp < 0 ? new Value(true) : new Value(false);
}
case EQUALS -> {
int comp = evaluate(parent.getChild(0)).compareTo(evaluate(parent.getChild(1)));
return comp == 0 ? new Value(true) : new Value(false);
}
case STRING -> {
return new Value(parent.getValue(), WordType.STRING);
}
case BOOL -> {
return new Value(parent.getValue(), WordType.BOOL);
}
default -> {
return new Value();
}
}
}
}

View file

@ -0,0 +1,35 @@
package com.github.nilstrieb.hunterlang.interpreter;
import java.lang.reflect.Array;
import java.util.ArrayList;
public class Memory {
private ArrayList<Value> mem;
public Memory() {
mem = new ArrayList<>();
}
public Value get(int i){
if(i >= mem.size()){
return new Value();
} else {
return mem.get(i);
}
}
public void set(int i, Value v){
if(i >= mem.size()){
int dif = i - mem.size() + 1;
for (int j = 0; j < dif; j++) {
mem.add(new Value());
}
}
mem.set(i, v);
}
public ArrayList<Value> getList() {
return mem;
}
}

View file

@ -0,0 +1,7 @@
package com.github.nilstrieb.hunterlang.interpreter;
public class RuntimeException extends Exception {
public RuntimeException(String message) {
super(message);
}
}

View file

@ -0,0 +1,106 @@
package com.github.nilstrieb.hunterlang.interpreter;
import com.github.nilstrieb.hunterlang.lexer.WordType;
public class Value {
private Type type;
private String stringValue;
private int intValue;
private double floatValue;
private boolean boolValue;
public Value(String value, WordType tType) {
if (tType == WordType.NUMBER && value.matches("\\d+")) {
type = Type.INT;
fromInt(value);
} else if (tType == WordType.NUMBER && value.matches("\\d+.\\d")) {
type = Type.FLOAT;
fromFloat(value);
} else if (tType == WordType.BOOL) {
type = Type.BOOL;
fromBool(value);
} else if (tType == WordType.STRING) {
type = Type.STRING;
fromString(value);
}
}
public Value() {
type = Type.INT;
fromInt("0");
}
public Value(boolean b) {
type = Type.BOOL;
fromBool(String.valueOf(b));
}
private void fromInt(String value){
intValue = Integer.parseInt(value);
stringValue = value;
floatValue = intValue;
boolValue = intValue != 0;
}
private void fromFloat(String value){
floatValue = Double.parseDouble(value);
intValue = (int) floatValue;
stringValue = value;
boolValue = intValue != 0;
}
private void fromBool(String value){
boolValue = Boolean.parseBoolean(value);
intValue = boolValue ? 1 : 0;
floatValue = intValue;
stringValue = value;
}
private void fromString(String value){
stringValue = value;
boolValue = false;
intValue = stringValue.length();
floatValue = intValue;
}
public String getStringValue() {
return stringValue;
}
public int getIntValue() {
return intValue;
}
public double getFloatValue() {
return floatValue;
}
public boolean isBoolValue() {
return boolValue;
}
@Override
public String toString() {
return stringValue + " " + type;
}
public void setValue(String value){
}
public int compareTo(Value v2) {
return Double.compare(this.floatValue, v2.floatValue);
}
public String toPrintString() {
return stringValue;
}
public boolean getBoolValue() {
return boolValue;
}
enum Type {
INT, FLOAT, STRING, BOOL
}
}

View file

@ -1,5 +1,7 @@
package com.github.nilstrieb.hunterlang.lexer;
import com.github.nilstrieb.hunterlang.interpreter.Interpreter;
import com.github.nilstrieb.hunterlang.interpreter.RuntimeException;
import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
import com.github.nilstrieb.hunterlang.parser.ParseException;
import com.github.nilstrieb.hunterlang.parser.ParseTreeNode;
@ -32,7 +34,7 @@ public class Lexer {
public static final String BOOL_REGEX = "(true|false).*";
public static final String STRING_REGEX = "^\"(.*)\".*";
public static final String NUMBER_REGEX = "^(-?\\d+.?\\d*).*";
public static final String NUMBER_REGEX = "^(-?\\d+\\.?\\d*).*";
private ArrayList<LexToken> tokens;
private ArrayList<LexToken> temp;
@ -149,58 +151,4 @@ public class Lexer {
temp.add(new LexToken(type));
}
public static void main(String[] args) {
Lexer l = new Lexer();
String assign = """
killua70 hunts 3 > 0
killua0 hunts 3
killua0 hunts -3.4 #hunts nothing
killua1 hunts "hallo"
#comment""";
String ifs = """
killua0 hunts 3 > 0
Gon wants false {
Leorio does say "false"
}
wants killua0 > 3 {
Leorio does say "big killua"
} got {
Leorio does say "small killua"
}
Gon wants true {
Gon wants true {
Leorio does say "that is actually very true"
}
}
""";
String ifif = """
Gon wants true {
Gon wants true {
Leorio does say "hallo"
}
}
""";
String sif = """
Gon wants true {
Leorio does say "hallo"
}
""";
String hierarchy = """
killua0 hunts 3 > 3
""";
ArrayList<LexToken> tokens = l.lex(ifs);
Parser p = new Parser();
try {
ArrayList<ParseTreeNode> nodes = p.parse(tokens);
for (ParseTreeNode parseTreeNode : nodes) {
System.out.println(parseTreeNode);
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}

View file

@ -25,8 +25,8 @@ public class ParseTreeNode {
this(WordType.EMPTY, "");
}
public ArrayList<ParseTreeNode> getChildren() {
return children;
public ParseTreeNode getChild(int index) {
return children.get(index);
}
public void addChild(ParseTreeNode n, boolean pre) {
@ -96,4 +96,8 @@ public class ParseTreeNode {
public String getValue() {
return value;
}
public ArrayList<ParseTreeNode> getChildren() {
return children;
}
}

View file

@ -97,7 +97,9 @@ public class Parser {
}
case LIBFUNCCALL -> {
parent = current.toNode();
parent.addChild(evaluate(tokens.subList(1, tokens.size())));
if(current.hasPostfix()) {
parent.addChild(evaluate(statement.subList(1, statement.size())));
}
}
default -> throw new ParseException("Unexpected value at start of statement: " + current.getKey());

View file

@ -0,0 +1,85 @@
package com.github.nilstrieb.hunterlang.run;
import com.github.nilstrieb.hunterlang.interpreter.Interpreter;
import com.github.nilstrieb.hunterlang.interpreter.RuntimeException;
import com.github.nilstrieb.hunterlang.lexer.LexToken;
import com.github.nilstrieb.hunterlang.lexer.Lexer;
import com.github.nilstrieb.hunterlang.parser.ParseException;
import com.github.nilstrieb.hunterlang.parser.ParseTreeNode;
import com.github.nilstrieb.hunterlang.parser.Parser;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
Lexer l = new Lexer();
String assign = """
killua70 hunts 3 > 0
killua0 hunts 3
killua0 hunts -3.4 #hunts nothing
killua1 hunts "hallo"
#comment""";
String ifs = """
killua0 hunts 3 > 0
Gon wants false {
Leorio does say "false"
}
wants killua0 > 3 {
Leorio does say "big killua"
} got {
Leorio does say "small killua"
}
Gon wants true {
Gon wants true {
Leorio does say "that is actually very true"
}
}
""";
String ifif = """
Gon wants true {
Gon wants true {
Leorio does say "hallo"
}
}
""";
String sif = """
Gon wants true {
Leorio does say "hallo"
}
""";
String hierarchy = """
killua0 hunts 3 > 3
""";
String weird = """
killua1 hunts 2
Wing does dump
Gon wants 5 < killua1 {
Leorio does say "its actually smaller gon!!!"
} wants 1 < killua1 {
Leorio does say "at least that"
}
""";
String hw = """
Leorio does say "Hello World!"
""";
ArrayList<LexToken> tokens = l.lex(weird);
Parser p = new Parser();
try {
ArrayList<ParseTreeNode> nodes = p.parse(tokens);
for (ParseTreeNode parseTreeNode : nodes) {
System.out.println(parseTreeNode);
}
Interpreter i = new Interpreter();
i.start(nodes);
} catch (ParseException | RuntimeException e) {
e.printStackTrace();
}
}
}