diff --git a/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/FunctionArgLookup.java b/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/FunctionArgLookup.java index 1098b5c..dd1bbf9 100644 --- a/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/FunctionArgLookup.java +++ b/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/FunctionArgLookup.java @@ -6,6 +6,7 @@ public class FunctionArgLookup { return switch (name) { case "Leorio.say" -> 1; case "Leorio.listen" -> 0; + case "Wing.dump" -> 0; default -> 0; }; } diff --git a/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/Leorio.java b/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/Leorio.java new file mode 100644 index 0000000..e624ba0 --- /dev/null +++ b/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/Leorio.java @@ -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"); + } + } + } +} diff --git a/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/Library.java b/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/Library.java new file mode 100644 index 0000000..3e4d45b --- /dev/null +++ b/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/Library.java @@ -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]); + }; + } +} diff --git a/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/Wing.java b/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/Wing.java new file mode 100644 index 0000000..9c187d9 --- /dev/null +++ b/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/Wing.java @@ -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 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"); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/github/nilstrieb/hunterlang/interpreter/Interpreter.java b/src/main/java/com/github/nilstrieb/hunterlang/interpreter/Interpreter.java new file mode 100644 index 0000000..4c12825 --- /dev/null +++ b/src/main/java/com/github/nilstrieb/hunterlang/interpreter/Interpreter.java @@ -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 statements; + Memory memory; + + public void start(ArrayList 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 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 argsNode = statement.getChildren(); + ArrayList 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(); + } + } + } +} diff --git a/src/main/java/com/github/nilstrieb/hunterlang/interpreter/Memory.java b/src/main/java/com/github/nilstrieb/hunterlang/interpreter/Memory.java new file mode 100644 index 0000000..2f6dc27 --- /dev/null +++ b/src/main/java/com/github/nilstrieb/hunterlang/interpreter/Memory.java @@ -0,0 +1,35 @@ +package com.github.nilstrieb.hunterlang.interpreter; + +import java.lang.reflect.Array; +import java.util.ArrayList; + +public class Memory { + private ArrayList 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 getList() { + return mem; + } +} diff --git a/src/main/java/com/github/nilstrieb/hunterlang/interpreter/RuntimeException.java b/src/main/java/com/github/nilstrieb/hunterlang/interpreter/RuntimeException.java new file mode 100644 index 0000000..eae702e --- /dev/null +++ b/src/main/java/com/github/nilstrieb/hunterlang/interpreter/RuntimeException.java @@ -0,0 +1,7 @@ +package com.github.nilstrieb.hunterlang.interpreter; + +public class RuntimeException extends Exception { + public RuntimeException(String message) { + super(message); + } +} diff --git a/src/main/java/com/github/nilstrieb/hunterlang/interpreter/Value.java b/src/main/java/com/github/nilstrieb/hunterlang/interpreter/Value.java new file mode 100644 index 0000000..8fe1516 --- /dev/null +++ b/src/main/java/com/github/nilstrieb/hunterlang/interpreter/Value.java @@ -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 + } +} \ No newline at end of file diff --git a/src/main/java/com/github/nilstrieb/hunterlang/lexer/Lexer.java b/src/main/java/com/github/nilstrieb/hunterlang/lexer/Lexer.java index 6b413c9..bd9e04d 100644 --- a/src/main/java/com/github/nilstrieb/hunterlang/lexer/Lexer.java +++ b/src/main/java/com/github/nilstrieb/hunterlang/lexer/Lexer.java @@ -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 tokens; private ArrayList 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 tokens = l.lex(ifs); - - Parser p = new Parser(); - try { - ArrayList nodes = p.parse(tokens); - - for (ParseTreeNode parseTreeNode : nodes) { - System.out.println(parseTreeNode); - } - } catch (ParseException e) { - e.printStackTrace(); - } - } } diff --git a/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseTreeNode.java b/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseTreeNode.java index 16b0fc7..d8d344f 100644 --- a/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseTreeNode.java +++ b/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseTreeNode.java @@ -25,8 +25,8 @@ public class ParseTreeNode { this(WordType.EMPTY, ""); } - public ArrayList 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 getChildren() { + return children; + } } diff --git a/src/main/java/com/github/nilstrieb/hunterlang/parser/Parser.java b/src/main/java/com/github/nilstrieb/hunterlang/parser/Parser.java index 99a58c1..a155e36 100644 --- a/src/main/java/com/github/nilstrieb/hunterlang/parser/Parser.java +++ b/src/main/java/com/github/nilstrieb/hunterlang/parser/Parser.java @@ -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()); diff --git a/src/main/java/com/github/nilstrieb/hunterlang/run/Main.java b/src/main/java/com/github/nilstrieb/hunterlang/run/Main.java new file mode 100644 index 0000000..aff249a --- /dev/null +++ b/src/main/java/com/github/nilstrieb/hunterlang/run/Main.java @@ -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 tokens = l.lex(weird); + + Parser p = new Parser(); + try { + ArrayList 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(); + } + } +}