aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/com/jantuomi/borker
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/com/jantuomi/borker')
-rw-r--r--src/main/com/jantuomi/borker/Main.java90
-rw-r--r--src/main/com/jantuomi/borker/core/CommandLineArgumentContainer.java73
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ASTGenerator.java43
-rw-r--r--src/main/com/jantuomi/borker/core/parser/Parser.java108
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/ASTNode.java40
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/AdditionNode.java39
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/AssignmentNode.java34
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/BinaryOperatorNode.java17
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/BlockBodyNode.java26
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/BooleanLiteralNode.java30
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/BranchNode.java42
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/DivisionNode.java39
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/DoubleLiteralNode.java30
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/EmptyNode.java27
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/FunctionDefineNode.java73
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/IntegerLiteralNode.java30
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/MultiplicationNode.java39
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/NegationNode.java34
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/ParameterListNode.java38
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/StringLiteralNode.java27
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/SubtractionNode.java38
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/SymbolNode.java70
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/UnaryOperatorNode.java31
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/VarargOperatorNode.java26
-rw-r--r--src/main/com/jantuomi/borker/core/parser/ast/VariableDeclareNode.java32
-rw-r--r--src/main/com/jantuomi/borker/core/parser/datatype/BooleanDataContainer.java44
-rw-r--r--src/main/com/jantuomi/borker/core/parser/datatype/DataContainer.java37
-rw-r--r--src/main/com/jantuomi/borker/core/parser/datatype/DoubleDataContainer.java86
-rw-r--r--src/main/com/jantuomi/borker/core/parser/datatype/IntegerDataContainer.java91
-rw-r--r--src/main/com/jantuomi/borker/core/parser/datatype/StringDataContainer.java46
-rw-r--r--src/main/com/jantuomi/borker/core/parser/datatype/VoidDataContainer.java39
-rw-r--r--src/main/com/jantuomi/borker/core/runtime/Function.java52
-rw-r--r--src/main/com/jantuomi/borker/core/runtime/Interpreter.java35
-rw-r--r--src/main/com/jantuomi/borker/core/runtime/Scope.java50
-rw-r--r--src/main/com/jantuomi/borker/core/runtime/State.java74
-rw-r--r--src/main/com/jantuomi/borker/core/runtime/builtins/AsIntBuiltinFunction.java52
-rw-r--r--src/main/com/jantuomi/borker/core/runtime/builtins/BuiltinManager.java30
-rw-r--r--src/main/com/jantuomi/borker/core/runtime/builtins/ConcatBuiltinFunction.java38
-rw-r--r--src/main/com/jantuomi/borker/core/runtime/builtins/InBuiltinFunction.java38
-rw-r--r--src/main/com/jantuomi/borker/core/runtime/builtins/OutBuiltinFunction.java32
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/Tokenizer.java119
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/ArgumentInfo.java49
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/Token.java212
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/TokenFactory.java71
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/AdditionToken.java22
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/AssignmentToken.java36
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/BinaryOperatorToken.java40
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/BlockBodyToken.java35
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/BooleanLiteralToken.java18
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/BranchToken.java48
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/ClosedParenToken.java18
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/CommentToken.java18
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/DivisionToken.java23
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/DoubleLiteralToken.java18
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/EndBlockToken.java17
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/FunctionDefineToken.java39
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/IntegerLiteralToken.java18
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/MultiplicationToken.java23
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/NegationToken.java20
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/OpenParenToken.java34
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/OptionalArgumentToken.java48
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/StringLiteralToken.java19
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/SubtractionToken.java22
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/SymbolToken.java31
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/TerminalToken.java39
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/UnaryOperatorToken.java39
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/VarargOperatorToken.java45
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/VariableDeclareToken.java25
-rw-r--r--src/main/com/jantuomi/borker/core/tokenizer/token/types/WhitespaceToken.java37
-rw-r--r--src/main/com/jantuomi/borker/exception/ExceptionManager.java21
-rw-r--r--src/main/com/jantuomi/borker/exception/InterpreterException.java53
-rw-r--r--src/main/com/jantuomi/borker/utils/Utilities.java17
72 files changed, 3094 insertions, 0 deletions
diff --git a/src/main/com/jantuomi/borker/Main.java b/src/main/com/jantuomi/borker/Main.java
new file mode 100644
index 0000000..d7445a8
--- /dev/null
+++ b/src/main/com/jantuomi/borker/Main.java
@@ -0,0 +1,90 @@
+package com.jantuomi.borker;
+
+import com.jantuomi.borker.core.CommandLineArgumentContainer;
+import com.jantuomi.borker.core.parser.ASTGenerator;
+import com.jantuomi.borker.core.parser.Parser;
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.runtime.Interpreter;
+import com.jantuomi.borker.core.tokenizer.Tokenizer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.InterpreterException;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Scanner;
+
+public class Main {
+
+ public static void main(String[] args) throws Exception {
+ boolean parseSuccess = parseArguments(args);
+ if (!parseSuccess) {
+ return;
+ }
+
+ if (CommandLineArgumentContainer.getInstance().isInteractive()) {
+ repl();
+ } else {
+ String sourceFileContents = CommandLineArgumentContainer.getInstance().getSourceFileContents();
+ run(sourceFileContents);
+ }
+ }
+
+ public static void repl() {
+ Scanner scanner = new Scanner(System.in);
+ String input;
+ while (true) {
+ System.out.print(">> ");
+ input = scanner.nextLine();
+
+ try {
+ run(input);
+ } catch (InterpreterException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static void run(String input) throws InterpreterException {
+ Tokenizer tokenizer = Tokenizer.getInstance();
+ List<Token> sequence = tokenizer.tokenize(input);
+
+ Collections.reverse(sequence);
+
+ List<Token> trees = Parser.getInstance().parse(sequence);
+ if (CommandLineArgumentContainer.getInstance().isDebugModeActive()) {
+ Parser.getInstance().printAllTrees(trees);
+ }
+
+ List<ASTNode> nodes = ASTGenerator.getInstance().generate(trees);
+ if (CommandLineArgumentContainer.getInstance().isDebugModeActive()) {
+ ASTGenerator.getInstance().printAllTrees(nodes);
+ }
+
+ String output = Interpreter.execute(nodes);
+
+ if (output.trim().length() > 0) {
+ System.out.println(output);
+ }
+ }
+
+ public static boolean parseArguments(String[] args) {
+ CommandLineArgumentContainer container = CommandLineArgumentContainer.getInstance();
+ CmdLineParser parser = new CmdLineParser(container);
+
+
+ try {
+ if (args.length == 0) {
+ throw new CmdLineException("Please provide an argument.");
+ }
+ parser.parseArgument(args);
+ } catch (CmdLineException e) {
+ System.err.println(e.getMessage());
+ parser.printUsage(System.err);
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/CommandLineArgumentContainer.java b/src/main/com/jantuomi/borker/core/CommandLineArgumentContainer.java
new file mode 100644
index 0000000..b89c88e
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/CommandLineArgumentContainer.java
@@ -0,0 +1,73 @@
+package com.jantuomi.borker.core;
+
+
+import org.kohsuke.args4j.Option;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * Created by jan on 10.6.2016.
+ */
+
+public class CommandLineArgumentContainer {
+
+ private CommandLineArgumentContainer() {}
+
+ private static final CommandLineArgumentContainer instance = new CommandLineArgumentContainer();
+ private File srcFile;
+
+
+ @Option(name="-f", usage="Execute script in file FILE.")
+ public void setFile(File file) {
+ this.srcFile = file;
+ }
+
+ @Option(name="-i", usage="Run in interactive mode.")
+ public boolean interactiveModeActive = false;
+
+
+ @Option(name="-d", usage="Display verbose debug output.")
+ public boolean debugModeActive = false;
+
+ public static CommandLineArgumentContainer getInstance() {
+ return instance;
+ }
+
+ public boolean isInteractive() {
+ return interactiveModeActive;
+ }
+
+ public boolean isDebugModeActive() {
+ return debugModeActive;
+ }
+
+ public String getSourceFileContents() {
+ if (srcFile == null) {
+ return null;
+ }
+
+ BufferedReader br;
+ String contents = null;
+ try {
+ br = new BufferedReader(new FileReader(srcFile));
+ StringBuilder sb = new StringBuilder();
+ String line = br.readLine();
+
+ while (line != null) {
+ sb.append(line);
+ sb.append(System.lineSeparator());
+ line = br.readLine();
+ }
+ contents = sb.toString();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ } finally {
+ // Add a newline at the end for comment rows to terminate nicely
+ return contents + "\n";
+ }
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ASTGenerator.java b/src/main/com/jantuomi/borker/core/parser/ASTGenerator.java
new file mode 100644
index 0000000..4086929
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ASTGenerator.java
@@ -0,0 +1,43 @@
+package com.jantuomi.borker.core.parser;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class ASTGenerator {
+ private static final ASTGenerator instance = new ASTGenerator();
+
+ private ASTGenerator() {}
+
+ public static ASTGenerator getInstance() {
+ return instance;
+ }
+
+ public List<ASTNode> generate(List<Token> trees) throws InterpreterException {
+ List<ASTNode> list = new ArrayList<>();
+
+ for (Token root : trees) {
+ list.add(root.generateNode());
+ }
+
+ return list;
+ }
+
+ public void printTree(ASTNode root) {
+ System.out.println("### AST Tree begin ###");
+ root.print(0);
+ System.out.println("### AST Tree end ###");
+ }
+
+ public void printAllTrees(List<ASTNode> trees) {
+ for (ASTNode tree : trees) {
+ printTree(tree);
+ }
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/Parser.java b/src/main/com/jantuomi/borker/core/parser/Parser.java
new file mode 100644
index 0000000..99f81e9
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/Parser.java
@@ -0,0 +1,108 @@
+package com.jantuomi.borker.core.parser;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.tokenizer.token.ArgumentInfo;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.ExceptionManager;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * Created by jan on 11.6.2016.
+ */
+public class Parser {
+ private static final Parser instance = new Parser();
+
+ private List<Token> tokens;
+ private List<ASTNode> statementSequence;
+
+ public static Parser getInstance() {
+ return instance;
+ }
+
+ private Parser() {
+
+ }
+
+ private Stack<Token> stack;
+
+ public List<Token> parse(List<Token> tokens) throws InterpreterException {
+ this.tokens = tokens;
+ this.stack = new Stack<>();
+
+ List<Token> args;
+ List<Token> output = new ArrayList<>();
+ for (Token t : tokens) {
+ if (t.getTokenType() == Token.Type.NewlineToken) {
+// if (stack.size() > 0) {
+// output.add(stack.pop());
+// }
+ continue;
+ }
+
+ args = new ArrayList<>();
+ ArgumentInfo argumentInfo = t.getArgumentInfo();
+
+ /*
+ This branch is executed if the token has a variable list of arguments
+ */
+ if (argumentInfo.getVarargs()) {
+ while (true) {
+ if (stack.size() > 0) {
+ Token arg = stack.pop();
+ if (arg.getTokenType() != argumentInfo.getTerminator()) {
+ args.add(arg);
+ }
+ else {
+ args.add(arg);
+ break;
+ }
+ }
+ }
+ }
+ /*
+ If the token has an optional argument type (it is only an argument if
+ it is of certain type)
+ */
+ else if (argumentInfo.getOptionalArgument() != null) {
+ if (stack.size() > 0 && stack.peek().getTokenType() == argumentInfo.getOptionalArgument()) {
+ args.add(stack.pop());
+ }
+ }
+ /* Normal cases with a fixed list of arguments */
+ else {
+ for (int i = 0; i < argumentInfo.getCount(); i++) {
+ if (stack.size() > 0) {
+ args.add(stack.pop());
+ } else {
+ ExceptionManager.raise(InterpreterException.ExceptionType.ArgumentError, t.getLine(),
+ t.toString(), Integer.toString(argumentInfo.getCount()));
+ return null;
+ }
+ }
+ }
+
+ Token result = t.setArguments(args);
+ stack.push(result);
+ }
+ while (stack.size() > 0) {
+ output.add(stack.pop());
+ }
+ return output;
+ }
+
+ public void printTree(Token e) {
+ System.out.println("### Token Tree begin ###");
+ e.print(0);
+ System.out.println("### Token Tree end ###");
+ }
+
+ public void printAllTrees(List<Token> trees) {
+ for (Token tree : trees) {
+ printTree(tree);
+ }
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/ASTNode.java b/src/main/com/jantuomi/borker/core/parser/ast/ASTNode.java
new file mode 100644
index 0000000..3967edb
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/ASTNode.java
@@ -0,0 +1,40 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.List;
+
+/**
+ * Created by jan on 11.6.2016.
+ */
+abstract public class ASTNode {
+
+ public abstract DataContainer evaluate() throws InterpreterException;
+
+ protected Token source;
+
+ public ASTNode(Token token) {
+ this.source = token;
+ }
+
+ public Token.Type tokenType() {
+ return source.getTokenType();
+ }
+
+ abstract List<ASTNode> getChildren();
+
+ public void print(int indent) {
+ for (int i = 0; i < indent; i++) {
+ System.out.print("\t");
+ }
+
+ System.out.println(source.toString());
+ for (ASTNode node : getChildren()) {
+ if (node != null) {
+ node.print(indent + 1);
+ }
+ }
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/AdditionNode.java b/src/main/com/jantuomi/borker/core/parser/ast/AdditionNode.java
new file mode 100644
index 0000000..ba99a54
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/AdditionNode.java
@@ -0,0 +1,39 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.ExceptionManager;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class AdditionNode extends BinaryOperatorNode {
+
+ public AdditionNode(Token token, ASTNode lhs, ASTNode rhs) {
+ super(token, lhs, rhs);
+ }
+
+ @Override
+ public DataContainer evaluate() throws InterpreterException {
+ DataContainer operand1 = lhs.evaluate();
+ DataContainer operand2 = rhs.evaluate();
+
+ DataContainer result = operand1.add(operand2);
+ if (result != null) {
+ return result;
+ } else {
+ ExceptionManager.raise(InterpreterException.ExceptionType.TypeError, source.getLine(),
+ operand1.getType().toString(), operand2.getType().toString());
+ return null;
+ }
+
+ }
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList(lhs, rhs);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/AssignmentNode.java b/src/main/com/jantuomi/borker/core/parser/ast/AssignmentNode.java
new file mode 100644
index 0000000..94013c2
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/AssignmentNode.java
@@ -0,0 +1,34 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.runtime.State;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 21.6.2016.
+ */
+public class AssignmentNode extends BinaryOperatorNode {
+ public AssignmentNode(Token token, SymbolNode lhs, ASTNode rhs) {
+ super(token, lhs, rhs);
+ }
+
+ @Override
+ public DataContainer evaluate() throws InterpreterException {
+ SymbolNode symbol = (SymbolNode) lhs;
+ DataContainer rValue = rhs.evaluate();
+ State.getInstance().setSymbolValueToScope(
+ symbol.getName(),
+ rValue
+ );
+ return rValue;
+ }
+
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList(lhs, rhs);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/BinaryOperatorNode.java b/src/main/com/jantuomi/borker/core/parser/ast/BinaryOperatorNode.java
new file mode 100644
index 0000000..a8f473f
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/BinaryOperatorNode.java
@@ -0,0 +1,17 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+abstract public class BinaryOperatorNode extends ASTNode {
+ protected ASTNode lhs;
+ protected ASTNode rhs;
+
+ public BinaryOperatorNode(Token token, ASTNode lhs, ASTNode rhs) {
+ super(token);
+ this.lhs = lhs;
+ this.rhs = rhs;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/BlockBodyNode.java b/src/main/com/jantuomi/borker/core/parser/ast/BlockBodyNode.java
new file mode 100644
index 0000000..dd0582c
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/BlockBodyNode.java
@@ -0,0 +1,26 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.parser.datatype.VoidDataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 17.6.2016.
+ */
+public class BlockBodyNode extends VarargOperatorNode {
+ public BlockBodyNode(Token token) {
+ super(token);
+ }
+
+ @Override
+ public DataContainer evaluate() throws InterpreterException {
+ DataContainer returnValue = new VoidDataContainer();
+
+ for (ASTNode node : args) {
+ returnValue = node.evaluate();
+ }
+
+ return returnValue;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/BooleanLiteralNode.java b/src/main/com/jantuomi/borker/core/parser/ast/BooleanLiteralNode.java
new file mode 100644
index 0000000..b5818a9
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/BooleanLiteralNode.java
@@ -0,0 +1,30 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.BooleanDataContainer;
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class BooleanLiteralNode extends ASTNode {
+ private BooleanDataContainer value;
+
+ public BooleanLiteralNode(Token token) {
+ super(token);
+ value = new BooleanDataContainer(Boolean.parseBoolean(token.getText()));
+ }
+
+ @Override
+ public DataContainer evaluate() {
+ return value;
+ }
+
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList();
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/BranchNode.java b/src/main/com/jantuomi/borker/core/parser/ast/BranchNode.java
new file mode 100644
index 0000000..12f304c
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/BranchNode.java
@@ -0,0 +1,42 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.BooleanDataContainer;
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 17.6.2016.
+ */
+public class BranchNode extends ASTNode {
+
+ private ASTNode expression;
+ private BlockBodyNode branch;
+
+ public BranchNode(Token token, ASTNode expression, BlockBodyNode branch) {
+ super(token);
+ this.expression = expression;
+ this.branch = branch;
+ }
+
+ @Override
+ public DataContainer evaluate() throws InterpreterException {
+ DataContainer ev = expression.evaluate();
+ boolean returnValue = false;
+ if (ev instanceof BooleanDataContainer) {
+ returnValue = ((BooleanDataContainer) ev).getData();
+ if (returnValue) {
+ branch.evaluate();
+ }
+ }
+ return new BooleanDataContainer(returnValue);
+ }
+
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList(expression, branch);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/DivisionNode.java b/src/main/com/jantuomi/borker/core/parser/ast/DivisionNode.java
new file mode 100644
index 0000000..04af834
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/DivisionNode.java
@@ -0,0 +1,39 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.ExceptionManager;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class DivisionNode extends BinaryOperatorNode {
+
+ public DivisionNode(Token token, ASTNode lhs, ASTNode rhs) {
+ super(token, lhs, rhs);
+ }
+
+ @Override
+ public DataContainer evaluate() throws InterpreterException {
+ DataContainer operand1 = lhs.evaluate();
+ DataContainer operand2 = rhs.evaluate();
+
+ DataContainer result = operand1.divide(operand2);
+ if (result != null) {
+ return result;
+ } else {
+ ExceptionManager.raise(InterpreterException.ExceptionType.TypeError, source.getLine(),
+ operand1.getType().toString(), operand2.getType().toString());
+ return null;
+ }
+
+ }
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList(lhs, rhs);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/DoubleLiteralNode.java b/src/main/com/jantuomi/borker/core/parser/ast/DoubleLiteralNode.java
new file mode 100644
index 0000000..084218b
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/DoubleLiteralNode.java
@@ -0,0 +1,30 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.parser.datatype.DoubleDataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class DoubleLiteralNode extends ASTNode {
+ private DoubleDataContainer value;
+
+ public DoubleLiteralNode(Token token) {
+ super(token);
+ value = new DoubleDataContainer(Double.parseDouble(token.getText()));
+ }
+
+ @Override
+ public DataContainer evaluate() {
+ return value;
+ }
+
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList();
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/EmptyNode.java b/src/main/com/jantuomi/borker/core/parser/ast/EmptyNode.java
new file mode 100644
index 0000000..cd97f44
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/EmptyNode.java
@@ -0,0 +1,27 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.parser.datatype.VoidDataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 17.6.2016.
+ */
+public class EmptyNode extends ASTNode {
+ public EmptyNode(Token source) {
+ super(source);
+ }
+
+ @Override
+ public DataContainer evaluate() {
+ return new VoidDataContainer();
+ }
+
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList();
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/FunctionDefineNode.java b/src/main/com/jantuomi/borker/core/parser/ast/FunctionDefineNode.java
new file mode 100644
index 0000000..2365511
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/FunctionDefineNode.java
@@ -0,0 +1,73 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.parser.datatype.StringDataContainer;
+import com.jantuomi.borker.core.runtime.Function;
+import com.jantuomi.borker.core.runtime.State;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by jan on 17.6.2016.
+ */
+public class FunctionDefineNode extends VarargOperatorNode {
+
+ private String name;
+
+ public void setBody(ASTNode body) {
+ this.body = body;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ private ASTNode body;
+
+ public FunctionDefineNode(Token token) {
+ super(token);
+ }
+
+ @Override
+ public DataContainer evaluate() {
+ List<String> argumentNames = new ArrayList<>();
+ for (ASTNode arg : args) {
+ SymbolNode argSym = (SymbolNode) arg;
+ argumentNames.add(argSym.getName());
+ }
+ Function function = new Function(argumentNames, (BlockBodyNode) body);
+ function.setName(name);
+ State.getInstance().addFunctionToScope(name, function);
+
+ return new StringDataContainer("function " + name);
+ }
+
+ @Override
+ public void print(int indent) {
+
+ for (int i = 0; i < indent; i++) {
+ System.out.print("\t");
+ }
+
+ System.out.println(String.format("Function %s", name));
+
+ for (int i = 0; i < indent + 1; i++) {
+ System.out.print("\t");
+ }
+
+ System.out.println(String.format("Arguments: "));
+
+ for (ASTNode node : args) {
+ node.print(indent + 2);
+ }
+
+ for (int i = 0; i < indent + 1; i++) {
+ System.out.print("\t");
+ }
+
+ System.out.println(String.format("Body statements: "));
+ body.print(indent + 2);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/IntegerLiteralNode.java b/src/main/com/jantuomi/borker/core/parser/ast/IntegerLiteralNode.java
new file mode 100644
index 0000000..573d491
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/IntegerLiteralNode.java
@@ -0,0 +1,30 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.parser.datatype.IntegerDataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class IntegerLiteralNode extends ASTNode {
+ private IntegerDataContainer value;
+
+ public IntegerLiteralNode(Token token) {
+ super(token);
+ value = new IntegerDataContainer(Integer.parseInt(token.getText()));
+ }
+
+ @Override
+ public DataContainer evaluate() {
+ return value;
+ }
+
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList();
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/MultiplicationNode.java b/src/main/com/jantuomi/borker/core/parser/ast/MultiplicationNode.java
new file mode 100644
index 0000000..53bf8ee
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/MultiplicationNode.java
@@ -0,0 +1,39 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.ExceptionManager;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class MultiplicationNode extends BinaryOperatorNode {
+
+ public MultiplicationNode(Token token, ASTNode lhs, ASTNode rhs) {
+ super(token, lhs, rhs);
+ }
+
+ @Override
+ public DataContainer evaluate() throws InterpreterException {
+ DataContainer operand1 = lhs.evaluate();
+ DataContainer operand2 = rhs.evaluate();
+
+ DataContainer result = operand1.multiply(operand2);
+ if (result != null) {
+ return result;
+ } else {
+ ExceptionManager.raise(InterpreterException.ExceptionType.TypeError, source.getLine(),
+ operand1.getType().toString(), operand2.getType().toString());
+ return null;
+ }
+
+ }
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList(lhs, rhs);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/NegationNode.java b/src/main/com/jantuomi/borker/core/parser/ast/NegationNode.java
new file mode 100644
index 0000000..2617198
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/NegationNode.java
@@ -0,0 +1,34 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.BooleanDataContainer;
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.parser.datatype.IntegerDataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.ExceptionManager;
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 21.6.2016.
+ */
+public class NegationNode extends UnaryOperatorNode {
+ public NegationNode(Token token, ASTNode operand) {
+ super(token, operand);
+ }
+
+ @Override
+ public DataContainer evaluate() throws InterpreterException {
+ DataContainer d = getOperand().evaluate();
+
+ if (d instanceof BooleanDataContainer) {
+ return new BooleanDataContainer(!((BooleanDataContainer) d).getData());
+ }
+ else if (d instanceof IntegerDataContainer) {
+ return new BooleanDataContainer(
+ ((IntegerDataContainer) d).getData() != 0
+ );
+ }
+ ExceptionManager.raise(InterpreterException.ExceptionType.TypeError, source.getLine(), "not", d.toString());
+ return null;
+
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/ParameterListNode.java b/src/main/com/jantuomi/borker/core/parser/ast/ParameterListNode.java
new file mode 100644
index 0000000..2d76694
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/ParameterListNode.java
@@ -0,0 +1,38 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by jan on 19.6.2016.
+ */
+public class ParameterListNode extends ASTNode {
+
+ private List<ASTNode> parameters = new ArrayList<>();
+
+ public void addParameter(ASTNode param) {
+ parameters.add(param);
+ }
+
+ public List<ASTNode> getParameters() {
+ return parameters;
+ }
+
+ public ParameterListNode(Token token) {
+ super(token);
+ }
+
+ @Override
+ public DataContainer evaluate() {
+ // TODO use State to evaluate function
+ return null;
+ }
+
+ @Override
+ List<ASTNode> getChildren() {
+ return parameters;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/StringLiteralNode.java b/src/main/com/jantuomi/borker/core/parser/ast/StringLiteralNode.java
new file mode 100644
index 0000000..214316a
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/StringLiteralNode.java
@@ -0,0 +1,27 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.parser.datatype.StringDataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 21.6.2016.
+ */
+public class StringLiteralNode extends ASTNode {
+ @Override
+ public DataContainer evaluate() {
+ return new StringDataContainer(source.getText());
+ }
+
+ public StringLiteralNode(Token source) {
+ super(source);
+ }
+
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList();
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/SubtractionNode.java b/src/main/com/jantuomi/borker/core/parser/ast/SubtractionNode.java
new file mode 100644
index 0000000..6f0b3fb
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/SubtractionNode.java
@@ -0,0 +1,38 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.ExceptionManager;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class SubtractionNode extends BinaryOperatorNode {
+ public SubtractionNode(Token token, ASTNode lhs, ASTNode rhs) {
+ super(token, lhs, rhs);
+ }
+
+ @Override
+ public DataContainer evaluate() throws InterpreterException {
+ DataContainer operand1 = lhs.evaluate();
+ DataContainer operand2 = rhs.evaluate();
+
+ DataContainer result = operand1.subtract(operand2);
+ if (result != null) {
+ return result;
+ } else {
+ ExceptionManager.raise(InterpreterException.ExceptionType.TypeError, source.getLine(),
+ operand1.getType().toString(), operand2.getType().toString());
+ return null;
+ }
+
+ }
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList(lhs, rhs);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/SymbolNode.java b/src/main/com/jantuomi/borker/core/parser/ast/SymbolNode.java
new file mode 100644
index 0000000..f473989
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/SymbolNode.java
@@ -0,0 +1,70 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.runtime.State;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.ExceptionManager;
+import com.jantuomi.borker.exception.InterpreterException;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Created by jan on 17.6.2016.
+ */
+public class SymbolNode extends ASTNode {
+
+ public ParameterListNode getParameterListNode() {
+ return parameterListNode;
+ }
+
+ public void setParameterListNode(ParameterListNode parameterListNode) {
+ this.parameterListNode = parameterListNode;
+ }
+
+ private ParameterListNode parameterListNode;
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ private String name;
+
+ public SymbolNode(Token token) {
+ super(token);
+ }
+
+ @Override
+ public DataContainer evaluate() throws InterpreterException {
+ List<DataContainer> paramValues = new ArrayList<>();
+ if (parameterListNode != null) {
+ for (ASTNode param : parameterListNode.getChildren()) {
+ paramValues.add(param.evaluate());
+ }
+ }
+ DataContainer returnValue = State.getInstance().getSymbolValue(name, paramValues);
+ if (returnValue != null) {
+ return returnValue;
+ } else {
+ ExceptionManager.raise(InterpreterException.ExceptionType.UndeclaredSymbolError, source.getLine(), name,
+ StringUtils.join(paramValues.stream().map(dataContainer -> dataContainer.toString()).collect(Collectors.toList()), ","));
+ return null;
+ }
+ }
+
+ @Override
+ List<ASTNode> getChildren() {
+ if (parameterListNode == null) {
+ return Arrays.asList();
+ } else {
+ return Arrays.asList(parameterListNode);
+ }
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/UnaryOperatorNode.java b/src/main/com/jantuomi/borker/core/parser/ast/UnaryOperatorNode.java
new file mode 100644
index 0000000..2636bfe
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/UnaryOperatorNode.java
@@ -0,0 +1,31 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 21.6.2016.
+ */
+abstract public class UnaryOperatorNode extends ASTNode {
+ public UnaryOperatorNode(Token token, ASTNode operand) {
+ super(token);
+ this.operand = operand;
+ }
+
+ public ASTNode getOperand() {
+ return operand;
+ }
+
+ public void setOperand(ASTNode operand) {
+ this.operand = operand;
+ }
+
+ private ASTNode operand;
+
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList(operand);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/VarargOperatorNode.java b/src/main/com/jantuomi/borker/core/parser/ast/VarargOperatorNode.java
new file mode 100644
index 0000000..007bdf6
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/VarargOperatorNode.java
@@ -0,0 +1,26 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.List;
+
+/**
+ * Created by jan on 17.6.2016.
+ */
+public abstract class VarargOperatorNode extends ASTNode {
+
+ protected List<ASTNode> args;
+
+ public VarargOperatorNode(Token token) {
+ super(token);
+ }
+
+ @Override
+ public List<ASTNode> getChildren() {
+ return args;
+ }
+
+ public void setArgs(List<ASTNode> args) {
+ this.args = args;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/ast/VariableDeclareNode.java b/src/main/com/jantuomi/borker/core/parser/ast/VariableDeclareNode.java
new file mode 100644
index 0000000..e37b17f
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/ast/VariableDeclareNode.java
@@ -0,0 +1,32 @@
+package com.jantuomi.borker.core.parser.ast;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.parser.datatype.StringDataContainer;
+import com.jantuomi.borker.core.runtime.State;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 20.6.2016.
+ */
+public class VariableDeclareNode extends ASTNode {
+ private SymbolNode variable;
+
+ public VariableDeclareNode(Token source, SymbolNode variable) {
+ super(source);
+ this.variable = variable;
+ }
+
+ @Override
+ public DataContainer evaluate() {
+ State.getInstance().addSymbolToScope(variable.getName());
+ return new StringDataContainer(variable.getName());
+ }
+
+ @Override
+ List<ASTNode> getChildren() {
+ return Arrays.asList();
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/datatype/BooleanDataContainer.java b/src/main/com/jantuomi/borker/core/parser/datatype/BooleanDataContainer.java
new file mode 100644
index 0000000..14f4a80
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/datatype/BooleanDataContainer.java
@@ -0,0 +1,44 @@
+package com.jantuomi.borker.core.parser.datatype;
+
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class BooleanDataContainer extends DataContainer<Boolean> {
+
+
+ public BooleanDataContainer(boolean value) {
+ setData(value);
+ }
+
+ @Override
+ public Type getType() {
+ return Type.Boolean;
+ }
+
+ @Override
+ public String toString() {
+ return Boolean.toString(getData());
+ }
+
+ @Override
+ public DataContainer<Boolean> add(DataContainer<Boolean> other) throws InterpreterException {
+ return null;
+ }
+
+ @Override
+ public DataContainer<Boolean> subtract(DataContainer<Boolean> other) throws InterpreterException {
+ return null;
+ }
+
+ @Override
+ public DataContainer<Boolean> multiply(DataContainer<Boolean> other) throws InterpreterException {
+ return null;
+ }
+
+ @Override
+ public DataContainer<Boolean> divide(DataContainer<Boolean> other) throws InterpreterException {
+ return null;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/datatype/DataContainer.java b/src/main/com/jantuomi/borker/core/parser/datatype/DataContainer.java
new file mode 100644
index 0000000..cdb202d
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/datatype/DataContainer.java
@@ -0,0 +1,37 @@
+package com.jantuomi.borker.core.parser.datatype;
+
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 11.6.2016.
+ */
+abstract public class DataContainer<T> {
+
+ public enum Type {
+ Integer,
+ Double,
+ String,
+ Boolean,
+ Void
+ }
+
+ abstract public Type getType();
+
+ private T data;
+
+ public T getData() {
+ return data;
+ }
+
+ public void setData(T data) {
+ this.data = data;
+ }
+
+ @Override
+ abstract public String toString();
+
+ abstract public DataContainer<T> add(DataContainer<T> other) throws InterpreterException;
+ public abstract DataContainer<T> subtract(DataContainer<T> other) throws InterpreterException;
+ public abstract DataContainer<T> multiply(DataContainer<T> other) throws InterpreterException;
+ public abstract DataContainer<T> divide(DataContainer<T> other) throws InterpreterException;
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/datatype/DoubleDataContainer.java b/src/main/com/jantuomi/borker/core/parser/datatype/DoubleDataContainer.java
new file mode 100644
index 0000000..e7fea19
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/datatype/DoubleDataContainer.java
@@ -0,0 +1,86 @@
+package com.jantuomi.borker.core.parser.datatype;
+
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 22.6.2016.
+ */
+public class DoubleDataContainer extends DataContainer<Double> {
+ public DoubleDataContainer(double value) {
+ setData(value);
+ }
+
+ @Override
+ public Type getType() {
+ return Type.Double;
+ }
+
+ @Override
+ public String toString() {
+ return getData().toString();
+ }
+
+ @Override
+ public DataContainer add(DataContainer other) throws InterpreterException {
+ switch (other.getType()) {
+ case Double:
+ return new DoubleDataContainer(
+ getData() + ((DoubleDataContainer) other).getData()
+ );
+ case Integer:
+ return new DoubleDataContainer(
+ getData() + ((IntegerDataContainer) other).getData()
+ );
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public DataContainer subtract(DataContainer other) throws InterpreterException {
+ switch (other.getType()) {
+ case Double:
+ return new DoubleDataContainer(
+ getData() - ((DoubleDataContainer) other).getData()
+ );
+ case Integer:
+ return new DoubleDataContainer(
+ getData() - ((IntegerDataContainer) other).getData()
+ );
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public DataContainer multiply(DataContainer other) throws InterpreterException {
+ switch (other.getType()) {
+ case Double:
+ return new DoubleDataContainer(
+ getData() * ((DoubleDataContainer) other).getData()
+ );
+ case Integer:
+ return new DoubleDataContainer(
+ getData() * ((IntegerDataContainer) other).getData()
+ );
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public DataContainer divide(DataContainer other) throws InterpreterException {
+ switch (other.getType()) {
+ case Double:
+ return new DoubleDataContainer(
+ getData() / ((DoubleDataContainer) other).getData()
+ );
+ case Integer:
+ return new DoubleDataContainer(
+ getData() / ((IntegerDataContainer) other).getData()
+ );
+ default:
+ return null;
+ }
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/datatype/IntegerDataContainer.java b/src/main/com/jantuomi/borker/core/parser/datatype/IntegerDataContainer.java
new file mode 100644
index 0000000..a0e42f6
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/datatype/IntegerDataContainer.java
@@ -0,0 +1,91 @@
+package com.jantuomi.borker.core.parser.datatype;
+
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class IntegerDataContainer extends DataContainer<Integer> {
+
+ public IntegerDataContainer(int value) {
+ setData(value);
+ }
+
+ @Override
+ public Type getType() {
+ return Type.Integer;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(getData());
+ }
+
+ @Override
+ public DataContainer add(DataContainer other) {
+ switch (other.getType()) {
+ case Integer:
+ return new IntegerDataContainer(
+ this.getData() + ((IntegerDataContainer) other).getData()
+ );
+ case Double:
+ return new DoubleDataContainer(
+ (double) getData() + ((DoubleDataContainer) other).getData()
+ );
+ default:
+ return null;
+
+ }
+ }
+
+ @Override
+ public DataContainer subtract(DataContainer other) {
+ switch (other.getType()) {
+ case Integer:
+ return new IntegerDataContainer(
+ this.getData() - ((IntegerDataContainer) other).getData()
+ );
+ case Double:
+ return new DoubleDataContainer(
+ (double) getData() - ((DoubleDataContainer) other).getData()
+ );
+ default:
+ return null;
+
+ }
+ }
+
+ @Override
+ public DataContainer multiply(DataContainer other) throws InterpreterException {
+ switch (other.getType()) {
+ case Integer:
+ return new IntegerDataContainer(
+ this.getData() * ((IntegerDataContainer) other).getData()
+ );
+ case Double:
+ return new DoubleDataContainer(
+ (double) getData() * ((DoubleDataContainer) other).getData()
+ );
+ default:
+ return null;
+
+ }
+ }
+
+ @Override
+ public DataContainer divide(DataContainer other) throws InterpreterException {
+ switch (other.getType()) {
+ case Integer:
+ return new IntegerDataContainer(
+ this.getData() / ((IntegerDataContainer) other).getData()
+ );
+ case Double:
+ return new DoubleDataContainer(
+ (double) getData() / ((DoubleDataContainer) other).getData()
+ );
+ default:
+ return null;
+
+ }
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/datatype/StringDataContainer.java b/src/main/com/jantuomi/borker/core/parser/datatype/StringDataContainer.java
new file mode 100644
index 0000000..6984642
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/datatype/StringDataContainer.java
@@ -0,0 +1,46 @@
+package com.jantuomi.borker.core.parser.datatype;
+
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class StringDataContainer extends DataContainer<String> {
+
+
+ public StringDataContainer(String text) {
+ setData(text);
+ }
+
+ @Override
+ public Type getType() {
+ return Type.String;
+ }
+
+ @Override
+ public String toString() {
+ return getData();
+ }
+
+ @Override
+ public DataContainer<String> add(DataContainer<String> other) {
+ return new StringDataContainer(
+ getData() + other.getData()
+ );
+ }
+
+ @Override
+ public DataContainer<String> subtract(DataContainer<String> other) throws InterpreterException {
+ return null;
+ }
+
+ @Override
+ public DataContainer<String> multiply(DataContainer<String> other) throws InterpreterException {
+ return null;
+ }
+
+ @Override
+ public DataContainer<String> divide(DataContainer<String> other) throws InterpreterException {
+ return null;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/parser/datatype/VoidDataContainer.java b/src/main/com/jantuomi/borker/core/parser/datatype/VoidDataContainer.java
new file mode 100644
index 0000000..4b7be6c
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/parser/datatype/VoidDataContainer.java
@@ -0,0 +1,39 @@
+package com.jantuomi.borker.core.parser.datatype;
+
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 17.6.2016.
+ */
+public class VoidDataContainer extends DataContainer<Integer> {
+
+ @Override
+ public Type getType() {
+ return Type.Void;
+ }
+
+ @Override
+ public String toString() {
+ return "";
+ }
+
+ @Override
+ public DataContainer<Integer> add(DataContainer<Integer> other) {
+ return null;
+ }
+
+ @Override
+ public DataContainer<Integer> subtract(DataContainer<Integer> other) {
+ return null;
+ }
+
+ @Override
+ public DataContainer<Integer> multiply(DataContainer<Integer> other) throws InterpreterException {
+ return null;
+ }
+
+ @Override
+ public DataContainer<Integer> divide(DataContainer<Integer> other) throws InterpreterException {
+ return null;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/runtime/Function.java b/src/main/com/jantuomi/borker/core/runtime/Function.java
new file mode 100644
index 0000000..714dcea
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/runtime/Function.java
@@ -0,0 +1,52 @@
+package com.jantuomi.borker.core.runtime;
+
+import com.jantuomi.borker.core.parser.ast.BlockBodyNode;
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.List;
+
+/**
+ * Created by jan on 20.6.2016.
+ */
+public class Function {
+
+ private List<String> argumentNames;
+
+ private BlockBodyNode body;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ private String name;
+
+ public Function(List<String> argumentNames, BlockBodyNode body) {
+ this.argumentNames = argumentNames;
+ this.body = body;
+ }
+
+ public DataContainer evaluate(List<DataContainer> params) throws InterpreterException {
+ State.getInstance().createScope();
+
+ if (params.size() != argumentNames.size()) {
+ return null;
+ }
+
+ for (int i = 0; i < argumentNames.size(); i++) {
+ State.getInstance().addSymbolToScope(argumentNames.get(i));
+ State.getInstance().setSymbolValueToScope(argumentNames.get(i), params.get(i));
+ }
+
+ DataContainer returnValue = body.evaluate();
+
+ State.getInstance().popScope();
+
+ return returnValue;
+ }
+
+}
diff --git a/src/main/com/jantuomi/borker/core/runtime/Interpreter.java b/src/main/com/jantuomi/borker/core/runtime/Interpreter.java
new file mode 100644
index 0000000..2a7bbbf
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/runtime/Interpreter.java
@@ -0,0 +1,35 @@
+package com.jantuomi.borker.core.runtime;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.List;
+
+/**
+ * Created by jan on 14.6.2016.
+ */
+public class Interpreter {
+ private static final Interpreter instance = new Interpreter();
+
+ public static Interpreter getInstance() {
+ return instance;
+ }
+
+ private Interpreter() {
+
+ }
+ public static String execute(List<ASTNode> sequence) throws InterpreterException {
+ String output = "";
+ for (ASTNode node : sequence) {
+ DataContainer data = node.evaluate();
+
+ if (data != null) {
+ output = data.toString();
+ } else {
+ break;
+ }
+ }
+ return output;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/runtime/Scope.java b/src/main/com/jantuomi/borker/core/runtime/Scope.java
new file mode 100644
index 0000000..90c1578
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/runtime/Scope.java
@@ -0,0 +1,50 @@
+package com.jantuomi.borker.core.runtime;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by jan on 20.6.2016.
+ */
+public class Scope {
+ private Scope parent = null;
+
+ private Map<String, DataContainer> variables = new HashMap<>();
+ private Map<String, Function> functions = new HashMap<>();
+
+ public void addVariable(String symbol) {
+ variables.put(symbol, null);
+ }
+
+ public void setVariableValue(String symbol, DataContainer value) {
+ variables.replace(symbol, value);
+ }
+
+ public DataContainer resolveSymbol(String symbol, List<DataContainer> params) throws InterpreterException {
+ if (functions.containsKey(symbol)) {
+ DataContainer r = functions.get(symbol).evaluate(params);
+ return r;
+ }
+ if (variables.containsKey(symbol)) {
+ return variables.get(symbol);
+ }
+ else if (parent != null) {
+ return parent.resolveSymbol(symbol, params);
+ }
+ else {
+ return null;
+ }
+ }
+
+ public void setParent(Scope parent) {
+ this.parent = parent;
+ }
+
+ public void addFunction(String symbol, Function func) {
+ functions.put(symbol, func);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/runtime/State.java b/src/main/com/jantuomi/borker/core/runtime/State.java
new file mode 100644
index 0000000..1ad09e7
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/runtime/State.java
@@ -0,0 +1,74 @@
+package com.jantuomi.borker.core.runtime;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.runtime.builtins.BuiltinManager;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * Created by jan on 11.6.2016.
+ */
+public class State {
+ private static final State instance = new State();
+
+ public static State getInstance() {
+ return instance;
+ }
+
+ private Stack<Scope> scopes = new Stack<>();
+
+ private State() {
+ /* Push global scope onto the stack */
+ Scope globalScope = new Scope();
+
+ for (Function builtin : BuiltinManager.getInstance().getBuiltins()) {
+ globalScope.addFunction(builtin.getName(), builtin);
+ }
+
+ scopes.push(globalScope);
+
+ }
+
+ private DataContainer resolveSymbol(String symbol) throws InterpreterException {
+ return scopes.peek().resolveSymbol(symbol, Arrays.asList());
+ }
+
+ public DataContainer getSymbolValue(String symbol) throws InterpreterException {
+ DataContainer d = resolveSymbol(symbol);
+ return d;
+ }
+
+ public DataContainer getSymbolValue(String symbol, List<DataContainer> parameters) throws InterpreterException {
+ return scopes.peek().resolveSymbol(symbol, parameters);
+ }
+
+ public Scope createScope() {
+ Scope scope = new Scope();
+ if (scopes.size() > 0) {
+ scope.setParent(scopes.peek());
+ } else {
+ scope.setParent(null);
+ }
+ scopes.push(scope);
+ return scope;
+ }
+
+ public void addSymbolToScope(String symbol) {
+ scopes.peek().addVariable(symbol);
+ }
+
+ public void addFunctionToScope(String symbol, Function func) {
+ scopes.peek().addFunction(symbol, func);
+ }
+
+ public void setSymbolValueToScope(String symbol, DataContainer value) {
+ scopes.peek().setVariableValue(symbol, value);
+ }
+
+ public Scope popScope() {
+ return scopes.pop();
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/runtime/builtins/AsIntBuiltinFunction.java b/src/main/com/jantuomi/borker/core/runtime/builtins/AsIntBuiltinFunction.java
new file mode 100644
index 0000000..e1f2a93
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/runtime/builtins/AsIntBuiltinFunction.java
@@ -0,0 +1,52 @@
+package com.jantuomi.borker.core.runtime.builtins;
+
+import com.jantuomi.borker.core.parser.datatype.BooleanDataContainer;
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.parser.datatype.IntegerDataContainer;
+import com.jantuomi.borker.core.parser.datatype.StringDataContainer;
+import com.jantuomi.borker.core.runtime.Function;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 21.6.2016.
+ */
+public class AsIntBuiltinFunction extends Function {
+ public AsIntBuiltinFunction() {
+ super(
+ Arrays.asList("expression"),
+ null
+ );
+ }
+
+ @Override
+ public String getName() {
+ return "as_int";
+ }
+
+ @Override
+ public DataContainer evaluate(List<DataContainer> params) throws InterpreterException {
+ if (params.size() != 1) {
+ return null;
+ }
+ DataContainer param = params.get(0);
+ int i = 0;
+ if (param instanceof StringDataContainer) {
+ try {
+ i = Integer.parseInt(((StringDataContainer) param).getData());
+ }
+ catch (NumberFormatException ex) {
+ return null;
+ }
+ }
+ else if (param instanceof IntegerDataContainer) {
+ i = ((IntegerDataContainer) param).getData();
+ }
+ else if (param instanceof BooleanDataContainer) {
+ i = ((BooleanDataContainer) param).getData() ? 1 : 0;
+ }
+ return new IntegerDataContainer(i);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/runtime/builtins/BuiltinManager.java b/src/main/com/jantuomi/borker/core/runtime/builtins/BuiltinManager.java
new file mode 100644
index 0000000..18f49a9
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/runtime/builtins/BuiltinManager.java
@@ -0,0 +1,30 @@
+package com.jantuomi.borker.core.runtime.builtins;
+
+import com.jantuomi.borker.core.runtime.Function;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by jan on 21.6.2016.
+ */
+public class BuiltinManager {
+ private static BuiltinManager instance = new BuiltinManager();
+
+ public static BuiltinManager getInstance() {
+ return instance;
+ }
+
+ private List<Function> builtins = new ArrayList<>();
+
+ private BuiltinManager() {
+ builtins.add(new OutBuiltinFunction());
+ builtins.add(new InBuiltinFunction());
+ builtins.add(new ConcatBuiltinFunction());
+ builtins.add(new AsIntBuiltinFunction());
+ }
+
+ public List<Function> getBuiltins() {
+ return builtins;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/runtime/builtins/ConcatBuiltinFunction.java b/src/main/com/jantuomi/borker/core/runtime/builtins/ConcatBuiltinFunction.java
new file mode 100644
index 0000000..293b918
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/runtime/builtins/ConcatBuiltinFunction.java
@@ -0,0 +1,38 @@
+package com.jantuomi.borker.core.runtime.builtins;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.parser.datatype.StringDataContainer;
+import com.jantuomi.borker.core.runtime.Function;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 21.6.2016.
+ */
+public class ConcatBuiltinFunction extends Function {
+ public ConcatBuiltinFunction() {
+ super(
+ Arrays.asList("strings"),
+ null
+ );
+ }
+
+ @Override
+ public String getName() {
+ return "concat";
+ }
+
+ @Override
+ public DataContainer evaluate(List<DataContainer> params) throws InterpreterException {
+ StringBuilder sb = new StringBuilder();
+ for (DataContainer d : params) {
+ sb.append(d.getData());
+ }
+
+ return new StringDataContainer(
+ sb.toString()
+ );
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/runtime/builtins/InBuiltinFunction.java b/src/main/com/jantuomi/borker/core/runtime/builtins/InBuiltinFunction.java
new file mode 100644
index 0000000..8d9184f
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/runtime/builtins/InBuiltinFunction.java
@@ -0,0 +1,38 @@
+package com.jantuomi.borker.core.runtime.builtins;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.parser.datatype.StringDataContainer;
+import com.jantuomi.borker.core.runtime.Function;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Scanner;
+
+/**
+ * Created by jan on 21.6.2016.
+ */
+public class InBuiltinFunction extends Function {
+ public InBuiltinFunction() {
+ super(
+ Arrays.asList("expression"),
+ null
+ );
+ }
+
+ @Override
+ public String getName() {
+ return "in";
+ }
+
+ @Override
+ public DataContainer evaluate(List<DataContainer> params) throws InterpreterException {
+ if (params.size() > 0) {
+ DataContainer param = params.get(0);
+ System.out.print(param.getData().toString());
+ }
+ Scanner in = new Scanner(System.in);
+ String userInput = in.nextLine();
+ return new StringDataContainer(userInput);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/runtime/builtins/OutBuiltinFunction.java b/src/main/com/jantuomi/borker/core/runtime/builtins/OutBuiltinFunction.java
new file mode 100644
index 0000000..4e977c8
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/runtime/builtins/OutBuiltinFunction.java
@@ -0,0 +1,32 @@
+package com.jantuomi.borker.core.runtime.builtins;
+
+import com.jantuomi.borker.core.parser.datatype.DataContainer;
+import com.jantuomi.borker.core.runtime.Function;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 21.6.2016.
+ */
+public class OutBuiltinFunction extends Function {
+ public OutBuiltinFunction() {
+ super(
+ Arrays.asList("expression"),
+ null
+ );
+ }
+
+ @Override
+ public String getName() {
+ return "out";
+ }
+
+ @Override
+ public DataContainer evaluate(List<DataContainer> params) throws InterpreterException {
+ DataContainer param = params.get(0);
+ System.out.println(param.getData().toString());
+ return param;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/Tokenizer.java b/src/main/com/jantuomi/borker/core/tokenizer/Tokenizer.java
new file mode 100644
index 0000000..d7d8870
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/Tokenizer.java
@@ -0,0 +1,119 @@
+package com.jantuomi.borker.core.tokenizer;
+
+
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.ExceptionManager;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by jan on 10.6.2016.
+ */
+public class Tokenizer {
+ private String sourceString;
+
+ public List<Token> getTokens() {
+ return tokens;
+ }
+
+ private List<Token> tokens = new ArrayList<>();
+
+ private static Map<Token.Type, String> tokenRegexes = new LinkedHashMap<>();
+ private static final List<Token.Type> discardedTokenTypes = new ArrayList<>();
+ private static final List<Token.Type> erroneousTokenTypes = new ArrayList<>();
+
+ private static final Tokenizer instance = new Tokenizer();
+
+ public static final Tokenizer getInstance() {
+ return instance;
+ }
+
+ private Tokenizer() {
+ tokenRegexes.put(Token.Type.CommentToken, "^\\/\\*(.*?)\\*\\/");
+
+ tokenRegexes.put(Token.Type.DoubleLiteralToken, "^([-+]?[0-9]*\\.?[0-9]+)f\\b");
+ tokenRegexes.put(Token.Type.IntegerLiteralToken, "^([-+]?\\d+)\\b");
+ tokenRegexes.put(Token.Type.BooleanLiteralToken, "^(true|false)\\b");
+ tokenRegexes.put(Token.Type.StringLiteralToken, "^\"(.*?)\"");
+
+ tokenRegexes.put(Token.Type.WhitespaceToken, "^( |\t)");
+ tokenRegexes.put(Token.Type.NewlineToken, "^(\n|\r\n)");
+ tokenRegexes.put(Token.Type.AdditionToken, "^(\\+)");
+ tokenRegexes.put(Token.Type.SubtractionToken, "^(\\-)");
+ tokenRegexes.put(Token.Type.DivisionToken, "^(\\/)");
+ tokenRegexes.put(Token.Type.MultiplicationToken, "^(\\*)");
+ tokenRegexes.put(Token.Type.AssignmentToken, "^(set)\\b");
+ tokenRegexes.put(Token.Type.LessThanToken, "^(\\<)");
+ tokenRegexes.put(Token.Type.GreaterThanToken, "^(\\>)");
+ tokenRegexes.put(Token.Type.LessOrEqualThanToken, "^(\\<\\=)");
+ tokenRegexes.put(Token.Type.GreaterOrEqualThanToken, "^(\\>\\=)");
+ tokenRegexes.put(Token.Type.EqualsToken, "^(\\=\\=)");
+ tokenRegexes.put(Token.Type.NotEqualsToken, "^(\\!\\=)");
+ tokenRegexes.put(Token.Type.OpenParenToken, "^(\\()");
+ tokenRegexes.put(Token.Type.ClosedParenToken, "^(\\))");
+ tokenRegexes.put(Token.Type.FunctionDefineToken, "^(func)\\b");
+ tokenRegexes.put(Token.Type.FunctionBodyToken, "^(as)\\b");
+ tokenRegexes.put(Token.Type.BranchBodyToken, "^(then)\\b");
+ tokenRegexes.put(Token.Type.EndBlockToken, "^(end)\\b");
+ tokenRegexes.put(Token.Type.NegationToken, "^(not)\\b");
+ tokenRegexes.put(Token.Type.DeclarationToken, "^(decl)\\b");
+ tokenRegexes.put(Token.Type.BranchToken, "^(if)\\b");
+
+ tokenRegexes.put(Token.Type.SymbolToken, "^([a-zA-Z]+\\w*)");
+
+ discardedTokenTypes.add(Token.Type.WhitespaceToken);
+ discardedTokenTypes.add(Token.Type.CommentToken);
+
+ erroneousTokenTypes.add(Token.Type.NotAToken);
+ }
+
+ public List<Token> tokenize(String string) throws InterpreterException {
+ sourceString = string;
+ tokens.clear();
+ int line = 1;
+ for (int i = 0; i < string.length();) {
+
+ Token token = Token.makeToken(string.substring(i), tokenRegexes, line);
+
+ if (token == null) {
+ i++;
+ continue;
+ }
+
+ if (token.getTokenType() == Token.Type.NewlineToken) {
+ line++;
+ }
+
+ if (!discardedTokenTypes.contains(token.getTokenType())) {
+ tokens.add(token);
+ }
+
+ if (erroneousTokenTypes.contains(token.getTokenType())) {
+ ExceptionManager.raise(InterpreterException.ExceptionType.IllegalTokenError, line, token.getText());
+ }
+
+ String tokenRawText = token.getRawText();
+ if (tokenRawText == null) {
+ tokenRawText = token.getText();
+ }
+ if (tokenRawText != null) {
+ i += tokenRawText.length();
+ } else {
+ i++;
+ }
+ }
+ return tokens;
+ }
+
+ public static void printTokens(List<Token> tokens) {
+ System.out.println("### Tokens: ###");
+ for (Token token : tokens) {
+ System.out.println(String.format("%-40s %s", token.getTokenType(), token.getText()));
+ }
+ System.out.println("### End ###");
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/ArgumentInfo.java b/src/main/com/jantuomi/borker/core/tokenizer/token/ArgumentInfo.java
new file mode 100644
index 0000000..967b341
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/ArgumentInfo.java
@@ -0,0 +1,49 @@
+package com.jantuomi.borker.core.tokenizer.token;
+
+/**
+ * Created by jan on 15.6.2016.
+ */
+public class ArgumentInfo {
+ private int count = 0;
+ private boolean isVarargs = false;
+
+ public Token.Type getOptionalArgument() {
+ return optionalArgument;
+ }
+
+ public void setOptionalArgument(Token.Type optionalArgument) {
+ this.optionalArgument = optionalArgument;
+ }
+
+ private Token.Type optionalArgument = null;
+
+ public Token.Type getTerminator() {
+ return terminator;
+ }
+
+ public void setTerminator(Token.Type terminator) {
+ this.terminator = terminator;
+ }
+
+ private Token.Type terminator;
+
+ public ArgumentInfo(int count) {
+ this.count = count;
+ }
+
+ public ArgumentInfo() {
+
+ }
+
+ public void setVariable(boolean value) {
+ this.isVarargs = value;
+ }
+
+ public boolean getVarargs() {
+ return isVarargs;
+ }
+
+ public int getCount() {
+ return count;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/Token.java b/src/main/com/jantuomi/borker/core/tokenizer/token/Token.java
new file mode 100644
index 0000000..b43755d
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/Token.java
@@ -0,0 +1,212 @@
+package com.jantuomi.borker.core.tokenizer.token;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.exception.ExceptionManager;
+import com.jantuomi.borker.exception.InterpreterException;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * Created by jan on 10.6.2016.
+ */
+abstract public class Token {
+
+ public void print(int indent) {
+ for (int i = 0; i < indent; i++) {
+ System.out.print("\t");
+ }
+ System.out.println(toString());
+ for (Token child : getChildren()) {
+ child.print(indent + 1);
+ }
+ }
+
+ abstract public ASTNode generateNode() throws InterpreterException;
+
+ /* Token types, ordered by precedence */
+ public enum Type {
+ CommentToken,
+
+ AdditionToken,
+ SubtractionToken,
+ DivisionToken,
+ MultiplicationToken,
+
+ AssignmentToken,
+
+ LessThanToken,
+ GreaterThanToken,
+ LessOrEqualThanToken,
+ GreaterOrEqualThanToken,
+ EqualsToken,
+ NotEqualsToken,
+
+ OpenParenToken,
+ ClosedParenToken,
+
+ FunctionDefineToken,
+ DeclarationToken,
+
+ StringLiteralToken,
+ IntegerLiteralToken,
+ BooleanLiteralToken,
+ DoubleLiteralToken,
+
+ WhitespaceToken,
+ NewlineToken,
+
+ BranchToken,
+ SymbolToken,
+ EndBlockToken,
+ FunctionBodyToken,
+ BranchBodyToken,
+ NegationToken,
+
+ NotAToken
+ }
+
+ abstract public Token setArguments(List<Token> args);
+
+ abstract public List<Token> getChildren();
+
+ public boolean is(Type type) {
+ return getTokenType() == type;
+ }
+
+ public int getLine() {
+ return line;
+ }
+
+ public void setLine(int line) {
+ this.line = line;
+ }
+
+ private int line;
+ private String rawText;
+ private String text;
+ private Type type;
+
+ public String getText() {
+ return text;
+ }
+
+ public Type getTokenType() {
+ return this.type;
+ }
+
+ public String getRawText() {
+ return rawText;
+ }
+
+ public boolean isHigherPrecedenceThan(Token other) {
+ return getTokenType().ordinal() <= other.getTokenType().ordinal();
+ }
+
+ public Token(Type type, String text, String rawText) {
+ initialize(type, text, rawText);
+ }
+
+ public Token(Type type, String text) {
+ initialize(type, text);
+ }
+
+ public Token(Type type) {
+ initialize(type, null);
+ }
+
+ private void initialize(Type type, String text, String rawText) {
+ this.type = type;
+ this.text = text;
+ this.rawText = rawText;
+ }
+
+ private void initialize(Type type, String text) {
+ initialize(type, text, text);
+ }
+
+ public static Token makeToken(String string, Map<Type, String> regexes, int line) throws InterpreterException {
+ Type type = Type.NotAToken;
+ String text = Character.toString(string.charAt(0));
+
+ for (Type t : regexes.keySet()) {
+ String regex = regexes.get(t);
+ Token found = matchToken(string, t, regex, line);
+ if (found != null) {
+ found.setLine(line);
+ return found;
+ }
+ }
+
+ // TODO raise error
+ return null;
+ }
+
+ public static Token matchToken(String string, Type type, String regex, int line) throws InterpreterException {
+ Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
+ Matcher matcher = pattern.matcher(string);
+
+ if (matcher.find()) {
+ String lexeme = matcher.group(1);
+ String rawText = matcher.group(0);
+
+ Token token = TokenFactory.create(type, lexeme, rawText);
+ if (token != null) {
+ token.setLine(line);
+ }
+ else {
+ ExceptionManager.raise(InterpreterException.ExceptionType.IllegalTokenError, line,
+ type.toString()
+ );
+ }
+
+ return token;
+ }
+ return null;
+ }
+
+ abstract public ArgumentInfo getArgumentInfo();
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(17, 37)
+ .append(text)
+ .append(getTokenType())
+ .toHashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Token)) return false;
+ if (o == this) return true;
+
+ Token rhs = (Token) o;
+ return new EqualsBuilder()
+ .append(getTokenType(), rhs.getTokenType())
+ .append(text, rhs.text)
+ .isEquals();
+ }
+
+ @Override
+ public String toString() {
+ return String.format(String.format(
+ "%s%s",
+ getTokenType().toString().replace("Token", ""),
+ getText() == null ? "" : " " + getText()
+ ));
+ }
+
+ public String toFormattedString() {
+ String textRepr = text;
+ return String.format("%-40s %s", getTokenType(), textRepr);
+ }
+
+ public boolean isSameType(Token other) {
+ return type == other.type;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/TokenFactory.java b/src/main/com/jantuomi/borker/core/tokenizer/token/TokenFactory.java
new file mode 100644
index 0000000..5fa9473
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/TokenFactory.java
@@ -0,0 +1,71 @@
+package com.jantuomi.borker.core.tokenizer.token;
+
+import com.jantuomi.borker.core.tokenizer.token.types.*;
+
+/**
+ * Created by jan on 28.6.2016.
+ */
+public class TokenFactory {
+ private static TokenFactory instance = new TokenFactory();
+
+ public static TokenFactory getInstance() {
+ return instance;
+ }
+
+ private TokenFactory() {
+ }
+
+ public static Token create(Token.Type type, String text, String rawText) {
+ switch (type) {
+ case WhitespaceToken:
+ return new WhitespaceToken();
+ case CommentToken:
+ return new CommentToken(text, rawText);
+
+ // TODO placeholder whitespace instead of newline
+ case NewlineToken:
+ return new WhitespaceToken();
+
+ case IntegerLiteralToken:
+ return new IntegerLiteralToken(text);
+ case StringLiteralToken:
+ return new StringLiteralToken(text, rawText);
+ case BooleanLiteralToken:
+ return new BooleanLiteralToken(text);
+ case DoubleLiteralToken:
+ return new DoubleLiteralToken(text, rawText);
+ case AdditionToken:
+ return new AdditionToken();
+ case SubtractionToken:
+ return new SubtractionToken();
+ case MultiplicationToken:
+ return new MultiplicationToken();
+ case DivisionToken:
+ return new DivisionToken();
+ case FunctionDefineToken:
+ return new FunctionDefineToken();
+ case EndBlockToken:
+ return new EndBlockToken();
+ case FunctionBodyToken:
+ return new BlockBodyToken("as");
+ case BranchBodyToken:
+ return new BlockBodyToken("then");
+ case DeclarationToken:
+ return new VariableDeclareToken();
+ case AssignmentToken:
+ return new AssignmentToken();
+ case SymbolToken:
+ return new SymbolToken(text);
+ case OpenParenToken:
+ return new OpenParenToken();
+ case ClosedParenToken:
+ return new ClosedParenToken();
+ case BranchToken:
+ return new BranchToken();
+ case NegationToken:
+ return new NegationToken();
+ default:
+ return null;
+ }
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/AdditionToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/AdditionToken.java
new file mode 100644
index 0000000..ee49846
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/AdditionToken.java
@@ -0,0 +1,22 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.AdditionNode;
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 15.6.2016.
+ */
+public class AdditionToken extends BinaryOperatorToken {
+ public AdditionToken() {
+ super(Type.AdditionToken);
+ }
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ return new AdditionNode(this,
+ lhs.generateNode(),
+ rhs.generateNode()
+ );
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/AssignmentToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/AssignmentToken.java
new file mode 100644
index 0000000..8d8903e
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/AssignmentToken.java
@@ -0,0 +1,36 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.AssignmentNode;
+import com.jantuomi.borker.core.parser.ast.SymbolNode;
+import com.jantuomi.borker.exception.ExceptionManager;
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 20.6.2016.
+ */
+public class AssignmentToken extends BinaryOperatorToken {
+
+ public AssignmentToken() {
+ super(Type.AssignmentToken, "set");
+ }
+
+ // TODO this and the node
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ ASTNode lhsNode = lhs.generateNode();
+
+ if (!(lhsNode instanceof SymbolNode)) {
+ ExceptionManager.raise(InterpreterException.ExceptionType.SyntaxError, getLine(), "non-symbol " + toString());
+ return null;
+ }
+
+ AssignmentNode node = new AssignmentNode(this,
+ (SymbolNode) lhsNode,
+ rhs.generateNode()
+ );
+
+ return node;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/BinaryOperatorToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/BinaryOperatorToken.java
new file mode 100644
index 0000000..207820a
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/BinaryOperatorToken.java
@@ -0,0 +1,40 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.tokenizer.token.ArgumentInfo;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 15.6.2016.
+ */
+abstract public class BinaryOperatorToken extends Token {
+ protected Token lhs;
+ protected Token rhs;
+
+ public BinaryOperatorToken(Type type) {
+ super(type);
+ }
+
+ public BinaryOperatorToken(Type type, String text) {
+ super(type, text);
+ }
+
+ @Override
+ public Token setArguments(List<Token> args) {
+ lhs = args.get(0);
+ rhs = args.get(1);
+ return this;
+ }
+
+ @Override
+ public List<Token> getChildren() {
+ return Arrays.asList(lhs, rhs);
+ }
+
+ @Override
+ public ArgumentInfo getArgumentInfo() {
+ return new ArgumentInfo(2);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/BlockBodyToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/BlockBodyToken.java
new file mode 100644
index 0000000..c6a251d
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/BlockBodyToken.java
@@ -0,0 +1,35 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.BlockBodyNode;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class BlockBodyToken extends VarargOperatorToken {
+ public BlockBodyToken(String keyword) {
+ super(Type.FunctionBodyToken, keyword);
+ }
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ BlockBodyNode node = new BlockBodyNode(this);
+ List<ASTNode> statements = new ArrayList<>();
+ for (int i = 0; i < args.size() - 1; i++) {
+ Token arg = args.get(i);
+ statements.add(arg.generateNode());
+ }
+ node.setArgs(statements);
+ return node;
+ }
+
+ @Override
+ public Type getTerminatorTokenType() {
+ return Type.EndBlockToken;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/BooleanLiteralToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/BooleanLiteralToken.java
new file mode 100644
index 0000000..4e8510c
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/BooleanLiteralToken.java
@@ -0,0 +1,18 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.BooleanLiteralNode;
+
+/**
+ * Created by jan on 15.6.2016.
+ */
+public class BooleanLiteralToken extends TerminalToken{
+ public BooleanLiteralToken(String text) {
+ super(Type.BooleanLiteralToken, text);
+ }
+
+ @Override
+ public ASTNode generateNode() {
+ return new BooleanLiteralNode(this);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/BranchToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/BranchToken.java
new file mode 100644
index 0000000..dd74c50
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/BranchToken.java
@@ -0,0 +1,48 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.BlockBodyNode;
+import com.jantuomi.borker.core.parser.ast.BranchNode;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 21.6.2016.
+ */
+public class BranchToken extends VarargOperatorToken {
+
+ private Token expression;
+ private BlockBodyToken branch;
+
+ public BranchToken() {
+ super(Type.BranchToken, "if");
+ }
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ return new BranchNode(this,
+ expression.generateNode(),
+ (BlockBodyNode) branch.generateNode()
+ );
+ }
+
+ @Override
+ public Token setArguments(List<Token> args) {
+ expression = args.get(0);
+ branch = (BlockBodyToken) args.get(1);
+ return this;
+ }
+
+ @Override
+ public List<Token> getChildren() {
+ return Arrays.asList(expression, branch);
+ }
+
+ @Override
+ public Type getTerminatorTokenType() {
+ return Type.BranchBodyToken;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/ClosedParenToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/ClosedParenToken.java
new file mode 100644
index 0000000..3071aaf
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/ClosedParenToken.java
@@ -0,0 +1,18 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+
+/**
+ * Created by jan on 19.6.2016.
+ */
+public class ClosedParenToken extends TerminalToken {
+ public ClosedParenToken() {
+ super(Type.ClosedParenToken);
+ }
+
+ @Override
+ public ASTNode generateNode() {
+ return null;
+ }
+
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/CommentToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/CommentToken.java
new file mode 100644
index 0000000..4908116
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/CommentToken.java
@@ -0,0 +1,18 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.EmptyNode;
+
+/**
+ * Created by jan on 19.6.2016.
+ */
+public class CommentToken extends TerminalToken {
+ public CommentToken(String text, String rawText) {
+ super(Type.CommentToken, text, rawText);
+ }
+
+ @Override
+ public ASTNode generateNode() {
+ return new EmptyNode(this);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/DivisionToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/DivisionToken.java
new file mode 100644
index 0000000..2b9892e
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/DivisionToken.java
@@ -0,0 +1,23 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.DivisionNode;
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 15.6.2016.
+ */
+public class DivisionToken extends BinaryOperatorToken {
+ public DivisionToken() {
+ super(Type.DivisionToken);
+ }
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ return new DivisionNode(this,
+ lhs.generateNode(),
+ rhs.generateNode()
+ );
+
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/DoubleLiteralToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/DoubleLiteralToken.java
new file mode 100644
index 0000000..71da848
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/DoubleLiteralToken.java
@@ -0,0 +1,18 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.DoubleLiteralNode;
+
+/**
+ * Created by jan on 15.6.2016.
+ */
+public class DoubleLiteralToken extends TerminalToken {
+ public DoubleLiteralToken(String text, String rawText) {
+ super(Type.DoubleLiteralToken, text, rawText);
+ }
+
+ @Override
+ public ASTNode generateNode() {
+ return new DoubleLiteralNode(this);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/EndBlockToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/EndBlockToken.java
new file mode 100644
index 0000000..3a07432
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/EndBlockToken.java
@@ -0,0 +1,17 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class EndBlockToken extends TerminalToken {
+ public EndBlockToken() {
+ super(Type.EndBlockToken, "end");
+ }
+
+ @Override
+ public ASTNode generateNode() {
+ return null;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/FunctionDefineToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/FunctionDefineToken.java
new file mode 100644
index 0000000..dab0e3a
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/FunctionDefineToken.java
@@ -0,0 +1,39 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.BlockBodyNode;
+import com.jantuomi.borker.core.parser.ast.FunctionDefineNode;
+import com.jantuomi.borker.exception.InterpreterException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class FunctionDefineToken extends VarargOperatorToken {
+ public FunctionDefineToken() {
+ super(Type.FunctionDefineToken, "func");
+ }
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ FunctionDefineNode node = new FunctionDefineNode(this);
+ node.setName(args.get(0).getText());
+
+ List<ASTNode> funcArgs = new ArrayList<>();
+ for (int i = 1; i < args.size() - 1; i++) {
+ funcArgs.add(args.get(i).generateNode());
+ }
+ node.setArgs(funcArgs);
+
+ BlockBodyNode bodyNode = (BlockBodyNode) args.get(args.size() - 1).generateNode();
+ node.setBody(bodyNode);
+ return node;
+ }
+
+ @Override
+ public Type getTerminatorTokenType() {
+ return Type.FunctionBodyToken;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/IntegerLiteralToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/IntegerLiteralToken.java
new file mode 100644
index 0000000..1b18373
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/IntegerLiteralToken.java
@@ -0,0 +1,18 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.IntegerLiteralNode;
+
+/**
+ * Created by jan on 15.6.2016.
+ */
+public class IntegerLiteralToken extends TerminalToken {
+ public IntegerLiteralToken(String text) {
+ super(Type.IntegerLiteralToken, text);
+ }
+
+ @Override
+ public ASTNode generateNode() {
+ return new IntegerLiteralNode(this);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/MultiplicationToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/MultiplicationToken.java
new file mode 100644
index 0000000..fc55e7a
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/MultiplicationToken.java
@@ -0,0 +1,23 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.MultiplicationNode;
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 15.6.2016.
+ */
+public class MultiplicationToken extends BinaryOperatorToken {
+ public MultiplicationToken() {
+ super(Type.MultiplicationToken);
+ }
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ return new MultiplicationNode(this,
+ lhs.generateNode(),
+ rhs.generateNode()
+ );
+
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/NegationToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/NegationToken.java
new file mode 100644
index 0000000..fbe0787
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/NegationToken.java
@@ -0,0 +1,20 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.NegationNode;
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 21.6.2016.
+ */
+public class NegationToken extends UnaryOperatorToken {
+
+ public NegationToken() {
+ super(Type.NegationToken, "not");
+ }
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ return new NegationNode(this, operand.generateNode());
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/OpenParenToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/OpenParenToken.java
new file mode 100644
index 0000000..37a1df0
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/OpenParenToken.java
@@ -0,0 +1,34 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.ParameterListNode;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 19.6.2016.
+ */
+public class OpenParenToken extends VarargOperatorToken {
+ public OpenParenToken() {
+ super(Type.OpenParenToken);
+ }
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ ParameterListNode node = new ParameterListNode(this);
+
+ for (Token token : args) {
+ if (token.getTokenType() == Type.ClosedParenToken) {
+ continue;
+ }
+
+ node.addParameter(token.generateNode());
+ }
+ return node;
+ }
+
+ @Override
+ public Type getTerminatorTokenType() {
+ return Type.ClosedParenToken;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/OptionalArgumentToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/OptionalArgumentToken.java
new file mode 100644
index 0000000..8cf41af
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/OptionalArgumentToken.java
@@ -0,0 +1,48 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.tokenizer.token.ArgumentInfo;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 28.6.2016.
+ */
+public abstract class OptionalArgumentToken extends Token {
+ public OptionalArgumentToken(Type type, String text) {
+ super(type, text);
+ }
+
+ protected Token optionalArgument;
+
+ public void setOptionalArgument(OpenParenToken optionalArgument) {
+ this.optionalArgument = optionalArgument;
+ }
+
+ abstract public Token.Type getOptionalArgumentType();
+
+ @Override
+ public ArgumentInfo getArgumentInfo() {
+ ArgumentInfo ai = new ArgumentInfo();
+ ai.setOptionalArgument(getOptionalArgumentType());
+ return ai;
+ }
+
+ @Override
+ public Token setArguments(List<Token> args) {
+ if (args.size() > 0) {
+ setOptionalArgument((OpenParenToken) args.get(0));
+ }
+ return this;
+ }
+
+ @Override
+ public List<Token> getChildren() {
+ if (optionalArgument == null) {
+ return Arrays.asList();
+ } else {
+ return Arrays.asList(optionalArgument);
+ }
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/StringLiteralToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/StringLiteralToken.java
new file mode 100644
index 0000000..7370444
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/StringLiteralToken.java
@@ -0,0 +1,19 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.StringLiteralNode;
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 21.6.2016.
+ */
+public class StringLiteralToken extends TerminalToken {
+ public StringLiteralToken(String text, String rawText) {
+ super(Type.StringLiteralToken, text, rawText);
+ }
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ return new StringLiteralNode(this);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/SubtractionToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/SubtractionToken.java
new file mode 100644
index 0000000..9e9d2cb
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/SubtractionToken.java
@@ -0,0 +1,22 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.SubtractionNode;
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class SubtractionToken extends BinaryOperatorToken {
+ public SubtractionToken() {
+ super(Type.SubtractionToken);
+ }
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ return new SubtractionNode(this,
+ lhs.generateNode(),
+ rhs.generateNode()
+ );
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/SymbolToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/SymbolToken.java
new file mode 100644
index 0000000..76dbad2
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/SymbolToken.java
@@ -0,0 +1,31 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.ParameterListNode;
+import com.jantuomi.borker.core.parser.ast.SymbolNode;
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class SymbolToken extends OptionalArgumentToken {
+
+ public SymbolToken(String name) {
+ super(Type.SymbolToken, name);
+ }
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ SymbolNode node = new SymbolNode(this);
+ node.setName(this.getText());
+ if (optionalArgument != null) {
+ node.setParameterListNode((ParameterListNode) optionalArgument.generateNode());
+ }
+ return node;
+ }
+
+ @Override
+ public Type getOptionalArgumentType() {
+ return Type.OpenParenToken;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/TerminalToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/TerminalToken.java
new file mode 100644
index 0000000..fb943fe
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/TerminalToken.java
@@ -0,0 +1,39 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.tokenizer.token.ArgumentInfo;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 28.6.2016.
+ */
+abstract public class TerminalToken extends Token {
+ public TerminalToken(Type type, String text, String rawText) {
+ super(type, text, rawText);
+ }
+
+ public TerminalToken(Type type, String text) {
+ super(type, text);
+ }
+
+ public TerminalToken(Type type) {
+ super(type);
+ }
+
+ @Override
+ public Token setArguments(List<Token> args) {
+ return this;
+ }
+
+ @Override
+ public List<Token> getChildren() {
+ return Arrays.asList();
+ }
+
+ @Override
+ public ArgumentInfo getArgumentInfo() {
+ return new ArgumentInfo(0);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/UnaryOperatorToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/UnaryOperatorToken.java
new file mode 100644
index 0000000..7c13ad0
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/UnaryOperatorToken.java
@@ -0,0 +1,39 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.tokenizer.token.ArgumentInfo;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 28.6.2016.
+ */
+abstract public class UnaryOperatorToken extends Token {
+ public UnaryOperatorToken(Type type, String text) {
+ super(type, text);
+ }
+
+ public UnaryOperatorToken(Type type) {
+ super(type);
+ }
+
+ protected Token operand;
+
+
+ @Override
+ public ArgumentInfo getArgumentInfo() {
+ return new ArgumentInfo(1);
+ }
+
+ @Override
+ public Token setArguments(List<Token> args) {
+ operand = args.get(0);
+ return this;
+ }
+
+ @Override
+ public List<Token> getChildren() {
+ return Arrays.asList(operand);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/VarargOperatorToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/VarargOperatorToken.java
new file mode 100644
index 0000000..fe82a43
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/VarargOperatorToken.java
@@ -0,0 +1,45 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.tokenizer.token.ArgumentInfo;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.List;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+abstract public class VarargOperatorToken extends Token {
+
+ protected List<Token> args;
+
+ public VarargOperatorToken(Type type, String text) {
+ super(type, text);
+ }
+
+ public VarargOperatorToken(Type type) {
+ super(type);
+ }
+
+ @Override
+ public Token setArguments(List<Token> args) {
+ this.args = args;
+ return this;
+ }
+
+ @Override
+ public List<Token> getChildren() {
+ return args;
+ }
+
+ abstract public Token.Type getTerminatorTokenType();
+
+ @Override
+ public ArgumentInfo getArgumentInfo() {
+ ArgumentInfo ai = new ArgumentInfo();
+ ai.setVariable(true);
+ ai.setTerminator(getTerminatorTokenType());
+ return ai;
+
+ }
+
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/VariableDeclareToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/VariableDeclareToken.java
new file mode 100644
index 0000000..c999452
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/VariableDeclareToken.java
@@ -0,0 +1,25 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.parser.ast.SymbolNode;
+import com.jantuomi.borker.core.parser.ast.VariableDeclareNode;
+import com.jantuomi.borker.exception.InterpreterException;
+
+/**
+ * Created by jan on 20.6.2016.
+ */
+public class VariableDeclareToken extends UnaryOperatorToken {
+
+
+ public VariableDeclareToken() {
+ super(Type.DeclarationToken, "decl");
+ }
+
+ @Override
+ public ASTNode generateNode() throws InterpreterException {
+ SymbolToken st = (SymbolToken) operand;
+ VariableDeclareNode node = new VariableDeclareNode(this,
+ (SymbolNode) st.generateNode());
+ return node;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/core/tokenizer/token/types/WhitespaceToken.java b/src/main/com/jantuomi/borker/core/tokenizer/token/types/WhitespaceToken.java
new file mode 100644
index 0000000..7b15e01
--- /dev/null
+++ b/src/main/com/jantuomi/borker/core/tokenizer/token/types/WhitespaceToken.java
@@ -0,0 +1,37 @@
+package com.jantuomi.borker.core.tokenizer.token.types;
+
+import com.jantuomi.borker.core.parser.ast.ASTNode;
+import com.jantuomi.borker.core.tokenizer.token.ArgumentInfo;
+import com.jantuomi.borker.core.tokenizer.token.Token;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by jan on 16.6.2016.
+ */
+public class WhitespaceToken extends Token {
+ public WhitespaceToken() {
+ super(Type.WhitespaceToken);
+ }
+
+ @Override
+ public ASTNode generateNode() {
+ return null;
+ }
+
+ @Override
+ public Token setArguments(List<Token> args) {
+ return this;
+ }
+
+ @Override
+ public List<Token> getChildren() {
+ return Arrays.asList();
+ }
+
+ @Override
+ public ArgumentInfo getArgumentInfo() {
+ return new ArgumentInfo(0);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/exception/ExceptionManager.java b/src/main/com/jantuomi/borker/exception/ExceptionManager.java
new file mode 100644
index 0000000..b9b302b
--- /dev/null
+++ b/src/main/com/jantuomi/borker/exception/ExceptionManager.java
@@ -0,0 +1,21 @@
+package com.jantuomi.borker.exception;
+
+/**
+ * Created by jan on 10.6.2016.
+ */
+public class ExceptionManager {
+
+ private static final ExceptionManager instance = new ExceptionManager();
+
+ private ExceptionManager() {
+ }
+
+ public static ExceptionManager getInstance() {
+ return instance;
+ }
+
+ public static void raise(InterpreterException.ExceptionType ex, int line, String... args) throws InterpreterException {
+ InterpreterException e = new InterpreterException(ex, line, args);
+ throw e;
+ }
+}
diff --git a/src/main/com/jantuomi/borker/exception/InterpreterException.java b/src/main/com/jantuomi/borker/exception/InterpreterException.java
new file mode 100644
index 0000000..153da0a
--- /dev/null
+++ b/src/main/com/jantuomi/borker/exception/InterpreterException.java
@@ -0,0 +1,53 @@
+package com.jantuomi.borker.exception;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by jan on 12.6.2016.
+ */
+public class InterpreterException extends Exception {
+
+ public enum ExceptionType {
+ IllegalTokenError,
+ SyntaxError,
+ TypeError,
+ ArgumentError,
+ UndeclaredSymbolError
+ }
+
+ public static Map<ExceptionType, String> errorTexts = new HashMap<>();
+
+ static {
+ errorTexts.put(ExceptionType.IllegalTokenError, "Unknown or illegal token %s found.");
+ errorTexts.put(ExceptionType.SyntaxError, "Unexpected %s.");
+ errorTexts.put(ExceptionType.TypeError, "Incompatible types %s and %s.");
+ errorTexts.put(ExceptionType.ArgumentError, "The parameter list given to function %s is either of wrong length or the parameters are of wrong type. Actual: %s");
+ errorTexts.put(ExceptionType.UndeclaredSymbolError, "No symbol %s defined, parameters: [%s].");
+ }
+
+ private ExceptionType exceptionType;
+ private String completeMessage;
+
+ public InterpreterException(ExceptionType exceptionType, int line, String... args) {
+ super(exceptionType.toString(), null, false, false);
+ this.exceptionType = exceptionType;
+ this.completeMessage = formatMessage(exceptionType.toString() + ": " + what(exceptionType), line, args);
+ }
+
+ private static String formatMessage(String message, int line, String... args) {
+
+ message = String.format(message, args);
+ return String.format("\nline %d: ", line) + message;
+ }
+
+ public static String what(ExceptionType type) {
+ return errorTexts.get(type);
+ }
+
+ @Override
+ public void printStackTrace() {
+ System.err.println(completeMessage);
+ }
+}
diff --git a/src/main/com/jantuomi/borker/utils/Utilities.java b/src/main/com/jantuomi/borker/utils/Utilities.java
new file mode 100644
index 0000000..60e221d
--- /dev/null
+++ b/src/main/com/jantuomi/borker/utils/Utilities.java
@@ -0,0 +1,17 @@
+package com.jantuomi.borker.utils;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Created by jan on 10.6.2016.
+ */
+public class Utilities {
+ private Utilities() {}
+
+ public static String getBasePath() {
+ Path currentRelativePath = Paths.get("");
+ String s = currentRelativePath.toAbsolutePath().toString();
+ return s;
+ }
+}