diff --git a/.idea/.gitignore b/.idea/.gitignore
index 69ee9e0..a203e0d 100644
--- a/.idea/.gitignore
+++ b/.idea/.gitignore
@@ -2,4 +2,4 @@
/shelf/
/workspace.xml
out\
-.class
\ No newline at end of file
+*.class
\ No newline at end of file
diff --git a/src/main/java/com/github/nilstrieb/hunterlang/editor/EditorView.form b/src/main/java/com/github/nilstrieb/hunterlang/editor/EditorView.form
deleted file mode 100644
index 43d331a..0000000
--- a/src/main/java/com/github/nilstrieb/hunterlang/editor/EditorView.form
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
diff --git a/src/main/java/com/github/nilstrieb/hunterlang/editor/EditorView.java b/src/main/java/com/github/nilstrieb/hunterlang/editor/EditorView.java
deleted file mode 100644
index 6b996a2..0000000
--- a/src/main/java/com/github/nilstrieb/hunterlang/editor/EditorView.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.github.nilstrieb.hunterlang.editor;
-
-import javax.swing.*;
-
-public class EditorView {
- private JEditorPane editorPane1;
- private JPanel panel1;
-}
diff --git a/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/FunctionArgLookup.java b/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/FunctionArgLookup.java
new file mode 100644
index 0000000..870ab37
--- /dev/null
+++ b/src/main/java/com/github/nilstrieb/hunterlang/hllibrary/FunctionArgLookup.java
@@ -0,0 +1,15 @@
+package com.github.nilstrieb.hunterlang.hllibrary;
+
+public class FunctionArgLookup {
+
+ public static int argLookup(String lib, String name){
+ return switch (lib){
+ case "Leorio" -> switch (name){
+ case "say" -> 1;
+ case "listen" -> 0;
+ default -> 0;
+ };
+ default -> 0;
+ };
+ }
+}
diff --git a/src/main/java/com/github/nilstrieb/hunterlang/lexer/LexToken.java b/src/main/java/com/github/nilstrieb/hunterlang/lexer/LexToken.java
index 3fa8c45..76fc9d8 100644
--- a/src/main/java/com/github/nilstrieb/hunterlang/lexer/LexToken.java
+++ b/src/main/java/com/github/nilstrieb/hunterlang/lexer/LexToken.java
@@ -1,6 +1,7 @@
package com.github.nilstrieb.hunterlang.lexer;
import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
+import com.github.nilstrieb.hunterlang.parser.ParseTreeNode;
public class LexToken {
WordType key;
@@ -11,11 +12,34 @@ public class LexToken {
this.value = value;
}
+ public LexToken(WordType key) {
+ this(key, "");
+ }
+
+ public int expectsPostArgCount() {
+ return key.expectsPostArg();
+ }
+ public boolean expectsPreArg() {
+ return key.expectsPreArg() > 0;
+ }
+
+ public ParseTreeNode toNode(){
+ return new ParseTreeNode(key, value);
+ }
+
@Override
public String toString() {
- return ConsoleColors.BLUE_BOLD + "{Key=" +
+ return ConsoleColors.PURPLE_BOLD + "T" + ConsoleColors.BLUE_BOLD + "{Key=" +
ConsoleColors.RED_BOLD_BRIGHT + key +
ConsoleColors.BLUE_BOLD + ", value=" +
- ConsoleColors.YELLOW + value + ConsoleColors.BLUE_BOLD + "}";
+ ConsoleColors.YELLOW + value + ConsoleColors.BLUE_BOLD + "}" + ConsoleColors.RESET;
+ }
+
+ public WordType getKey() {
+ return key;
+ }
+
+ public String getValue() {
+ return value;
}
}
diff --git a/src/main/java/com/github/nilstrieb/hunterlang/lexer/LexedList.java b/src/main/java/com/github/nilstrieb/hunterlang/lexer/LexedList.java
deleted file mode 100644
index fe37092..0000000
--- a/src/main/java/com/github/nilstrieb/hunterlang/lexer/LexedList.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.github.nilstrieb.hunterlang.lexer;
-
-import java.util.ArrayList;
-
-public class LexedList {
- private ArrayList> list;
-
- public LexedList() {
- list = new ArrayList<>();
- }
-
- public void newLine(){
- list.add(new ArrayList<>());
- }
-
- public void add(int line, WordType type, String value) {
- list.get(line).add(new LexToken(type, value));
- }
-
- public void add(int line, WordType type){
- add(line, type, "");
- }
-
- public ArrayList get(int i) {
- return list.get(i);
- }
-}
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 82b0339..b58a87f 100644
--- a/src/main/java/com/github/nilstrieb/hunterlang/lexer/Lexer.java
+++ b/src/main/java/com/github/nilstrieb/hunterlang/lexer/Lexer.java
@@ -1,6 +1,9 @@
package com.github.nilstrieb.hunterlang.lexer;
import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
+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;
@@ -31,15 +34,16 @@ public class Lexer {
public static final String STRING_REGEX = "^\"(.*)\".*";
public static final String NUMBER_REGEX = "^(-?\\d+.?\\d*).*";
- private LexedList tokens;
+ private ArrayList tokens;
+ private ArrayList temp;
+
+ public ArrayList lex(String code) {
+ tokens = new ArrayList<>();
+ temp = new ArrayList<>();
- public LexedList lex(String code) {
- tokens = new LexedList();
- ArrayList tempList = new ArrayList<>();
String[] lines = code.split("\\r\\n|\\n");
for (int i = 0; i < lines.length; i++) {
- tokens.newLine();
String line = lines[i];
for (int j = 0; j < line.length(); j++) {
String sub = line.substring(j);
@@ -53,103 +57,127 @@ public class Lexer {
//FIXED KEYWORDS
else if (sub.startsWith(MEMCALL)) {
- tokens.add(i, WordType.MEMCALL);
+ addToken(WordType.MEMCALL);
j += MEMCALL.length() - 1;
} else if (sub.startsWith(ASSIGNMENT)) {
- tokens.add(i, WordType.ASSIGNMENT);
+ addToken(WordType.ASSIGNMENT);
j += ASSIGNMENT.length() - 1;
} else if (sub.startsWith(IF)) {
- tokens.add(i, WordType.IF);
+ addToken(WordType.IF);
j += IF.length() - 1;
- } else if (sub.startsWith(WANTS)){
- tokens.add(i, WordType.WANTS);
+ } else if (sub.startsWith(WANTS)) {
+ addToken(WordType.WANTS);
j += WANTS.length() - 1;
- } else if (sub.startsWith(ELSE)){
- tokens.add(i, WordType.ELSE);
+ } else if (sub.startsWith(ELSE)) {
+ addToken(WordType.ELSE);
j += ELSE.length() - 1;
}
//CONDITIONS
- else if (sub.startsWith(GTHAN)){
- tokens.add(i, WordType.GTHAN);
+ else if (sub.startsWith(GTHAN)) {
+ addToken(WordType.GTHAN);
j += GTHAN.length() - 1;
- } else if (sub.startsWith(LTHAN)){
- tokens.add(i, WordType.LTHAN);
+ } else if (sub.startsWith(LTHAN)) {
+ addToken(WordType.LTHAN);
j += LTHAN.length() - 1;
- } else if (sub.startsWith(EQUALS)){
- tokens.add(i, WordType.EQUALS);
+ } else if (sub.startsWith(EQUALS)) {
+ addToken(WordType.EQUALS);
j += EQUALS.length() - 1;
}
//OPERATORS
- else if (sub.startsWith(PLUS)){
- tokens.add(i, WordType.PLUS);
- } else if (sub.startsWith(MINUS)){
- tokens.add(i, WordType.MINUS);
- } else if (sub.startsWith(MULTIPLY)){
- tokens.add(i, WordType.MULTIPLY);
- }else if (sub.startsWith(DIVIDE)){
- tokens.add(i, WordType.DIVIDE);
- } else if (sub.startsWith(MOD)){
- tokens.add(i, WordType.MOD);
+ else if (sub.startsWith(PLUS)) {
+ addToken(WordType.PLUS);
+ } else if (sub.startsWith(MINUS)) {
+ addToken(WordType.MINUS);
+ } else if (sub.startsWith(MULTIPLY)) {
+ addToken(WordType.MULTIPLY);
+ } else if (sub.startsWith(DIVIDE)) {
+ addToken(WordType.DIVIDE);
+ } else if (sub.startsWith(MOD)) {
+ addToken(WordType.MOD);
}
// BRACKETS
- else if (sub.startsWith(BOPEN)){
- tokens.add(i, WordType.BOPEN);
- } else if (sub.startsWith(BCLOSE)){
- tokens.add(i, WordType.BCLOSE);
+ else if (sub.startsWith(BOPEN)) {
+ addToken(WordType.BOPEN);
+ } else if (sub.startsWith(BCLOSE)) {
+ addToken(WordType.BCLOSE);
}
//VALUES
else if (sub.matches(STRING_REGEX)) {
String string = sub.replaceAll(STRING_REGEX, "$1");
- tokens.add(i, WordType.STRING, string);
+ addToken(WordType.STRING, string);
j += string.length() + 1;
} else if (sub.matches(NUMBER_REGEX)) {
String number = sub.replaceAll(NUMBER_REGEX, "$1");
- tokens.add(i, WordType.NUMBER, number);
+ addToken(WordType.NUMBER, number);
j += number.length() - 1;
- } else if (sub.matches(BOOL_REGEX)){
+ } else if (sub.matches(BOOL_REGEX)) {
String bool = sub.replaceAll(BOOL_REGEX, "$1");
- tokens.add(i, WordType.BOOL, bool);
+ addToken(WordType.BOOL, bool);
j += bool.length() - 1;
}
//Calls
- else if(sub.matches(LIBFUNCCALL_REGEX)){
+ else if (sub.matches(LIBFUNCCALL_REGEX)) {
String libName = sub.replaceAll(LIBFUNCCALL_REGEX, "$1");
String funcName = sub.replaceAll(LIBFUNCCALL_REGEX, "$2");
- tokens.add(i, WordType.LIB, libName);
- tokens.add(i, WordType.FUNCCALL, funcName);
+ addToken(WordType.LIB, libName);
+ addToken(WordType.FUNCCALL, funcName);
j += libName.length(); //lib name
j += 1 + 4 + 1; // space + does + space
j += funcName.length() - 1; //func name
}
}
System.out.println(ConsoleColors.GREEN_BOLD + line);
- System.out.println(ConsoleColors.BLUE_BOLD + tokens.get(i));
+ System.out.println(ConsoleColors.BLUE_BOLD + temp);
+ tokens.addAll(temp);
+ temp.clear();
}
return tokens;
}
+ private void addToken(WordType type, String value) {
+ temp.add(new LexToken(type, value));
+ }
+
+ private void addToken(WordType type) {
+ temp.add(new LexToken(type));
+ }
+
public static void main(String[] args) {
Lexer l = new Lexer();
- LexedList tokens = l.lex("""
+ String assign = """
killua0 hunts 3
killua0 hunts -3.4 #hunts nothing
- killua0 hunts 4
killua1 hunts "hallo"
- #comment
+ #comment""";
+ String ifs = """
Gon wants false {
Leorio does say "false"
- } wants killua0 > 3 {
+ }
+ wants killua0 > 3 {
Leorio does say "big killua"
} got {
Leorio does say "small killua"
}
- """);
+ """;
+
+ ArrayList tokens = l.lex(ifs);
+
+ Parser p = new Parser();
+ try {
+ ArrayList nodes = p.parse(tokens);
+
+ for (ParseTreeNode node : nodes) {
+ System.out.println(node);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
}
}
diff --git a/src/main/java/com/github/nilstrieb/hunterlang/lexer/WordType.java b/src/main/java/com/github/nilstrieb/hunterlang/lexer/WordType.java
index 2bf17c0..c26609f 100644
--- a/src/main/java/com/github/nilstrieb/hunterlang/lexer/WordType.java
+++ b/src/main/java/com/github/nilstrieb/hunterlang/lexer/WordType.java
@@ -1,5 +1,49 @@
package com.github.nilstrieb.hunterlang.lexer;
public enum WordType {
- ASSIGNMENT, MEMCALL, STRING, NUMBER, BOOL, IF, WANTS, ELSE, BOPEN, BCLOSE, GTHAN, LTHAN, EQUALS, FUNCNAME, FUNCARGS, FUNCRETURN, IOCALL, FUNCCALL, OPERATOR, LIB, MINUS, DEFAULT, PLUS, MULTIPLY, DIVIDE, MOD;
+ ASSIGNMENT(1, 1), //memory, value
+ MEMCALL(1), //adress
+ STRING,
+ NUMBER,
+ BOOL,
+ IF(1), //wants
+ WANTS(2), //condition, body
+ ELSE(1), //body
+ BOPEN(-1), //body, close
+ BCLOSE,
+ GTHAN(1, 1),
+ LTHAN(1, 1),
+ EQUALS(1, 1),
+ FUNCCALL(-1), //args
+ LIB(1), //function
+ MINUS(1, 1),
+ PLUS(1, 1),
+ MULTIPLY(1, 1),
+ DIVIDE(1, 1),
+ MOD(1, 1),
+ NEGATIVE(1),
+ EMPTY;
+
+ private int postArgAmount;
+ private int preArgAmount;
+
+ WordType(int postArgAmount, int preArgAmount) {
+ this.postArgAmount = postArgAmount;
+ this.preArgAmount = preArgAmount;
+ }
+
+ WordType(int postArgAmount) {
+ this(postArgAmount, 0);
+ }
+
+ WordType() {
+ this(0, 0);
+ }
+
+ public int expectsPostArg() {
+ return postArgAmount;
+ }
+ public int expectsPreArg() {
+ return preArgAmount;
+ }
}
diff --git a/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseException.java b/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseException.java
new file mode 100644
index 0000000..15f38c2
--- /dev/null
+++ b/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseException.java
@@ -0,0 +1,7 @@
+package com.github.nilstrieb.hunterlang.parser;
+
+public class ParseException extends Exception{
+ public ParseException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseTreeBodyNode.java b/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseTreeBodyNode.java
new file mode 100644
index 0000000..ee70b1b
--- /dev/null
+++ b/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseTreeBodyNode.java
@@ -0,0 +1,44 @@
+package com.github.nilstrieb.hunterlang.parser;
+
+import com.github.nilstrieb.hunterlang.lexer.LexToken;
+import com.github.nilstrieb.hunterlang.lexer.WordType;
+
+import java.util.ArrayList;
+
+public class ParseTreeBodyNode extends ParseTreeNode{
+ private ArrayList statements;
+ private ArrayList tokens;
+
+ public ParseTreeBodyNode(WordType key, String value) {
+ super(key, value);
+ this.statements = new ArrayList<>();
+ this.tokens = new ArrayList<>();
+ }
+
+ public ParseTreeBodyNode(ParseTreeNode node) {
+ this(node.key, node.value);
+ }
+
+ public ArrayList getStatements() {
+ return statements;
+ }
+
+ public void addToken(LexToken currentToken) {
+ tokens.add(currentToken);
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + statements;
+ }
+
+ @Override
+ public String toString(String indent) {
+ return super.toString(indent) + statements;
+ }
+
+ public void parse() throws ParseException {
+ Parser p = new Parser();
+ statements = p.parse(tokens);
+ }
+}
diff --git a/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseTreeNode.java b/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseTreeNode.java
new file mode 100644
index 0000000..16b0fc7
--- /dev/null
+++ b/src/main/java/com/github/nilstrieb/hunterlang/parser/ParseTreeNode.java
@@ -0,0 +1,99 @@
+package com.github.nilstrieb.hunterlang.parser;
+
+import com.github.nilstrieb.hunterlang.lexer.WordType;
+import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
+
+import java.util.ArrayList;
+
+public class ParseTreeNode {
+ WordType key;
+ String value;
+ ArrayList children;
+
+ int remainingPreArgs;
+ int remainingPostArgs;
+
+ public ParseTreeNode(WordType key, String value) {
+ this.key = key;
+ this.value = value;
+ children = new ArrayList<>();
+ remainingPostArgs = key.expectsPostArg();
+ remainingPreArgs = key.expectsPreArg();
+ }
+
+ public ParseTreeNode() {
+ this(WordType.EMPTY, "");
+ }
+
+ public ArrayList getChildren() {
+ return children;
+ }
+
+ public void addChild(ParseTreeNode n, boolean pre) {
+ children.add(n);
+ if (pre) {
+ remainingPreArgs--;
+ }
+ }
+
+ public void addChild(ParseTreeNode n) {
+ addChild(n, false);
+ }
+
+ public int expectsPostArgCount() {
+ return remainingPostArgs;
+ }
+
+ public boolean expectsPreArg() {
+ return remainingPreArgs > 0;
+ }
+
+ public void setKey(WordType key) {
+ this.key = key;
+ remainingPostArgs = key.expectsPostArg();
+ remainingPreArgs = key.expectsPreArg();
+ }
+
+ @Override
+ public String toString() {
+ return ConsoleColors.PURPLE_BOLD + "N" + ConsoleColors.BLUE_BOLD + "{name=" +
+ ConsoleColors.RED_BOLD_BRIGHT + key +
+ ConsoleColors.BLUE_BOLD + ", value=" +
+ ConsoleColors.YELLOW + value +
+ ConsoleColors.BLUE_BOLD + ", children=" + printList(children, "") +
+ ConsoleColors.BLUE_BOLD + "}" + ConsoleColors.RESET;
+ }
+
+ public String toString(String indent) {
+ return ConsoleColors.PURPLE_BOLD + indent + "N" + ConsoleColors.BLUE_BOLD + "{name=" +
+ ConsoleColors.RED_BOLD_BRIGHT + key +
+ ConsoleColors.BLUE_BOLD + ", value=" +
+ ConsoleColors.YELLOW + value +
+ ConsoleColors.BLUE_BOLD + ", children=" + printList(children, indent + " ") +
+ ConsoleColors.BLUE_BOLD + "}" + ConsoleColors.RESET;
+ }
+
+ public String printList(ArrayList list, String indent) {
+ if(list.size() == 0){
+ return "[]";
+ }
+
+ String indentHigher = indent + " ";
+
+ StringBuilder sb = new StringBuilder();
+ for (ParseTreeNode node : list) {
+ sb.append("[\n");
+ sb.append(node.toString(indentHigher));
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public WordType getKey() {
+ return key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+}
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 83017e7..2a10b29 100644
--- a/src/main/java/com/github/nilstrieb/hunterlang/parser/Parser.java
+++ b/src/main/java/com/github/nilstrieb/hunterlang/parser/Parser.java
@@ -1,7 +1,118 @@
package com.github.nilstrieb.hunterlang.parser;
-public class Parser {
-}
+import com.github.nilstrieb.hunterlang.hllibrary.FunctionArgLookup;
+import com.github.nilstrieb.hunterlang.lexer.LexToken;
+import com.github.nilstrieb.hunterlang.lexer.WordType;
+import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
-class ParseTreeNode {
+import java.util.ArrayList;
+import java.util.ListIterator;
+
+public class Parser {
+
+ private ListIterator iterator;
+
+ private LexToken currentToken = null;
+ private LexToken prevToken = null;
+ private LexToken nextToken = null;
+
+ private ParseTreeNode prevNode;
+
+ public ArrayList parse(ArrayList tokens) throws ParseException {
+ System.out.println(ConsoleColors.GREEN_BACKGROUND + ConsoleColors.BLACK_BOLD + "------START PARSER------" + ConsoleColors.RESET);
+
+ ArrayList statements = new ArrayList<>();
+
+ iterator = tokens.listIterator();
+
+ currentToken = iterator.next();
+ if (iterator.hasNext()) {
+ nextToken = iterator.next();
+ }
+
+ //goes through each statement. On pass -> one statement
+ do {
+ System.out.println(ConsoleColors.GREEN_BRIGHT + "NEXT STATEMENT");
+
+ prevNode = new ParseTreeNode();
+
+ //start with first token
+ ParseTreeNode startNode = currentToken.toNode();
+
+ //if it wants a pre argument theres an error
+ if (currentToken.expectsPreArg()) {
+ throw new ParseException("previous expression expected, doesn't exist");
+ }
+
+ //calculate the arguments of the start node, parsing the whole statement
+ getArguments(startNode, true);
+ System.out.println(prevNode);
+ statements.add(prevNode);
+ } while (iterator.hasNext());
+
+ System.out.println(ConsoleColors.GREEN_BACKGROUND + ConsoleColors.BLACK_BOLD + "------STOP PARSER------" + ConsoleColors.RESET);
+ return statements;
+ }
+
+ private void getArguments(ParseTreeNode node, boolean isParent) throws ParseException {
+ if (node.getKey() == WordType.MINUS && prevNode.getKey() != WordType.NUMBER) {
+ node.setKey(WordType.NEGATIVE);
+ }
+
+ if (node.expectsPreArg()) {
+ node.addChild(prevNode, true);
+ }
+ int expectedArg = node.expectsPostArgCount();
+ if (expectedArg == -1) {
+ if (node.getKey() == WordType.FUNCCALL) {
+ //a function. will only support lib functions
+ System.out.println(currentToken);
+ expectedArg = FunctionArgLookup.argLookup(prevToken.getValue(), currentToken.getValue());
+ } else {
+ ParseTreeBodyNode bNode = new ParseTreeBodyNode(node);
+ node = bNode;
+ fillBody(bNode);
+ }
+ }
+ if (isParent) {
+ prevNode = node;
+ }
+ if (expectedArg == 0) {
+ nextToken();
+ } else {
+ nextToken();
+ for (int i = 0; i < expectedArg; i++) {
+ ParseTreeNode child = currentToken.toNode();
+ getArguments(child, false);
+ node.addChild(child);
+ }
+ }
+
+ if (currentToken != null && currentToken.expectsPreArg()) {
+ getArguments(currentToken.toNode(), true);
+ }
+ }
+
+ private void fillBody(ParseTreeBodyNode node) throws ParseException {
+ int level = 0;
+ nextToken();
+ while (currentToken.getKey() != WordType.BCLOSE || level != 0) {
+ if (currentToken.getKey() == WordType.BOPEN) {
+ level++;
+ } else if (currentToken.getKey() == WordType.BCLOSE) {
+ level--;
+ }
+ node.addToken(currentToken);
+ nextToken();
+ }
+ node.parse();
+ }
+
+ private void nextToken() {
+ prevToken = currentToken;
+ currentToken = nextToken;
+ if (iterator.hasNext()) {
+ nextToken = iterator.next();
+ }
+ }
}
\ No newline at end of file