aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Tuomi <jans.tuomi@gmail.com>2016-07-30 12:24:06 +0300
committerJan Tuomi <jans.tuomi@gmail.com>2016-07-30 12:24:06 +0300
commit8813de2902e06c61b2bdc8697b1cc987f920dc1f (patch)
treeba0f9d1086a8535aaef3321b2a4c6ee71b5141e0
parent6c6eabea8947a9ae83e6ba98112574c1a2f25a34 (diff)
Function references are now correctly first class citizens
Resolves #7
-rw-r--r--src/main/com/jantuomi/tunkki/core/parser/ast/CallNode.java25
-rw-r--r--src/main/com/jantuomi/tunkki/core/parser/ast/FunctionDefineNode.java6
-rw-r--r--src/main/com/jantuomi/tunkki/core/parser/ast/SymbolNode.java32
-rw-r--r--src/main/com/jantuomi/tunkki/core/parser/datatype/CallableDatatype.java46
-rw-r--r--src/main/com/jantuomi/tunkki/core/parser/datatype/Datatype.java4
-rw-r--r--src/main/com/jantuomi/tunkki/core/runtime/Scope.java20
-rw-r--r--src/main/com/jantuomi/tunkki/core/runtime/State.java12
-rw-r--r--src/main/com/jantuomi/tunkki/core/tokenizer/token/types/CallToken.java4
-rw-r--r--src/main/com/jantuomi/tunkki/exception/TunkkiError.java2
9 files changed, 131 insertions, 20 deletions
diff --git a/src/main/com/jantuomi/tunkki/core/parser/ast/CallNode.java b/src/main/com/jantuomi/tunkki/core/parser/ast/CallNode.java
new file mode 100644
index 0000000..6f4e240
--- /dev/null
+++ b/src/main/com/jantuomi/tunkki/core/parser/ast/CallNode.java
@@ -0,0 +1,25 @@
+package com.jantuomi.tunkki.core.parser.ast;
+
+import com.jantuomi.tunkki.core.parser.datatype.CallableDatatype;
+import com.jantuomi.tunkki.core.parser.datatype.Datatype;
+import com.jantuomi.tunkki.core.tokenizer.token.Token;
+import com.jantuomi.tunkki.exception.TunkkiError;
+
+/**
+ * Created by jan on 30.7.2016.
+ */
+public class CallNode extends SymbolNode {
+ public CallNode(Token token) {
+ super(token);
+ }
+
+ @Override
+ public Datatype evaluate() throws TunkkiError {
+ Datatype d = super.evaluate();
+ if (d.getType() == Datatype.Type.Callable) {
+ return ((CallableDatatype) d).call(evaluateParameters());
+ } else {
+ return d;
+ }
+ }
+}
diff --git a/src/main/com/jantuomi/tunkki/core/parser/ast/FunctionDefineNode.java b/src/main/com/jantuomi/tunkki/core/parser/ast/FunctionDefineNode.java
index 7339970..a9b0a7e 100644
--- a/src/main/com/jantuomi/tunkki/core/parser/ast/FunctionDefineNode.java
+++ b/src/main/com/jantuomi/tunkki/core/parser/ast/FunctionDefineNode.java
@@ -1,7 +1,7 @@
package com.jantuomi.tunkki.core.parser.ast;
+import com.jantuomi.tunkki.core.parser.datatype.CallableDatatype;
import com.jantuomi.tunkki.core.parser.datatype.Datatype;
-import com.jantuomi.tunkki.core.parser.datatype.StringDatatype;
import com.jantuomi.tunkki.core.runtime.Function;
import com.jantuomi.tunkki.core.runtime.State;
import com.jantuomi.tunkki.core.tokenizer.token.Token;
@@ -47,7 +47,9 @@ public class FunctionDefineNode extends VarargOperatorNode {
function.setName(name);
State.getInstance().addFunctionToScope(name, function);
- return new StringDatatype("function " + name);
+ CallableDatatype c = new CallableDatatype();
+ c.setData(function);
+ return c;
}
@Override
diff --git a/src/main/com/jantuomi/tunkki/core/parser/ast/SymbolNode.java b/src/main/com/jantuomi/tunkki/core/parser/ast/SymbolNode.java
index fde44c7..4cfa1df 100644
--- a/src/main/com/jantuomi/tunkki/core/parser/ast/SymbolNode.java
+++ b/src/main/com/jantuomi/tunkki/core/parser/ast/SymbolNode.java
@@ -5,11 +5,9 @@ import com.jantuomi.tunkki.core.runtime.State;
import com.jantuomi.tunkki.core.tokenizer.token.Token;
import com.jantuomi.tunkki.exception.ExceptionManager;
import com.jantuomi.tunkki.exception.TunkkiError;
-import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
-import java.util.stream.Collectors;
/**
* Created by jan on 17.6.2016.
@@ -42,17 +40,17 @@ public class SymbolNode extends ASTNode {
@Override
public Datatype evaluate() throws TunkkiError {
- List<Datatype> paramValues = new ArrayList<>();
- for (ASTNode param : parameters) {
- Datatype value = param.evaluate();
- if (value != null) {
- paramValues.add(value);
- }
- }
+
Datatype returnValue;
try {
- returnValue = State.getInstance().getSymbolValue(name, paramValues);
+ if (State.getInstance().isFunction(name)) {
+ returnValue = State.getInstance().makeFunctionReference(name);
+ } else {
+ List<Datatype> paramValues = evaluateParameters();
+ returnValue = State.getInstance().evaluateSymbol(name, paramValues);
+ }
+
}
/* If a TunkkiError is caught, pass it on with line information */
catch (TunkkiError ex) {
@@ -63,12 +61,22 @@ public class SymbolNode extends ASTNode {
if (returnValue != null) {
return returnValue;
} else {
- ExceptionManager.raise(TunkkiError.ExceptionType.UndeclaredSymbolError, getLine(), name,
- StringUtils.join(paramValues.stream().map(Datatype::toString).collect(Collectors.toList()), ","));
+ ExceptionManager.raise(TunkkiError.ExceptionType.UndeclaredSymbolError, getLine(), name);
return null;
}
}
+ public List<Datatype> evaluateParameters() throws TunkkiError {
+ List<Datatype> paramValues = new ArrayList<>();
+ for (ASTNode param : parameters) {
+ Datatype value = param.evaluate();
+ if (value != null) {
+ paramValues.add(value);
+ }
+ }
+ return paramValues;
+ }
+
@Override
List<ASTNode> getChildren() {
return parameters;
diff --git a/src/main/com/jantuomi/tunkki/core/parser/datatype/CallableDatatype.java b/src/main/com/jantuomi/tunkki/core/parser/datatype/CallableDatatype.java
new file mode 100644
index 0000000..3480b5d
--- /dev/null
+++ b/src/main/com/jantuomi/tunkki/core/parser/datatype/CallableDatatype.java
@@ -0,0 +1,46 @@
+package com.jantuomi.tunkki.core.parser.datatype;
+
+import com.jantuomi.tunkki.core.runtime.Function;
+import com.jantuomi.tunkki.exception.TunkkiError;
+
+import java.util.List;
+
+/**
+ * Created by jan on 30.7.2016.
+ */
+public class CallableDatatype extends Datatype<Function> {
+
+ @Override
+ public Type getType() {
+ return Type.Callable;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Callable %s", getData().getName());
+ }
+
+ public Datatype call(List<Datatype> params) throws TunkkiError {
+ return getData().evaluate(params);
+ }
+
+ @Override
+ public Datatype<Function> add(Datatype<Function> other) throws TunkkiError {
+ return null;
+ }
+
+ @Override
+ public Datatype<Function> subtract(Datatype<Function> other) throws TunkkiError {
+ return null;
+ }
+
+ @Override
+ public Datatype<Function> multiply(Datatype<Function> other) throws TunkkiError {
+ return null;
+ }
+
+ @Override
+ public Datatype<Function> divide(Datatype<Function> other) throws TunkkiError {
+ return null;
+ }
+}
diff --git a/src/main/com/jantuomi/tunkki/core/parser/datatype/Datatype.java b/src/main/com/jantuomi/tunkki/core/parser/datatype/Datatype.java
index a161f09..887b2f4 100644
--- a/src/main/com/jantuomi/tunkki/core/parser/datatype/Datatype.java
+++ b/src/main/com/jantuomi/tunkki/core/parser/datatype/Datatype.java
@@ -16,7 +16,9 @@ abstract public class Datatype<T> {
Double,
String,
Boolean,
- Nada, Void
+ Nada,
+ Void,
+ Callable
}
abstract public Type getType();
diff --git a/src/main/com/jantuomi/tunkki/core/runtime/Scope.java b/src/main/com/jantuomi/tunkki/core/runtime/Scope.java
index 2f7e3a8..0565227 100644
--- a/src/main/com/jantuomi/tunkki/core/runtime/Scope.java
+++ b/src/main/com/jantuomi/tunkki/core/runtime/Scope.java
@@ -1,5 +1,6 @@
package com.jantuomi.tunkki.core.runtime;
+import com.jantuomi.tunkki.core.parser.datatype.CallableDatatype;
import com.jantuomi.tunkki.core.parser.datatype.Datatype;
import com.jantuomi.tunkki.exception.TunkkiError;
@@ -40,6 +41,21 @@ public class Scope {
}
}
+ public CallableDatatype getCallable(String symbol) {
+ if (functions.containsKey(symbol)) {
+ Function f = functions.get(symbol);
+ CallableDatatype c = new CallableDatatype();
+ c.setData(f);
+ return c;
+ }
+ else if (parent != null) {
+ return parent.getCallable(symbol);
+ }
+ else {
+ return null;
+ }
+ }
+
public void setParent(Scope parent) {
this.parent = parent;
}
@@ -47,4 +63,8 @@ public class Scope {
public void addFunction(String symbol, Function func) {
functions.put(symbol, func);
}
+
+ public boolean isFunction(String symbol) {
+ return functions.containsKey(symbol);
+ }
}
diff --git a/src/main/com/jantuomi/tunkki/core/runtime/State.java b/src/main/com/jantuomi/tunkki/core/runtime/State.java
index 1b25712..742e603 100644
--- a/src/main/com/jantuomi/tunkki/core/runtime/State.java
+++ b/src/main/com/jantuomi/tunkki/core/runtime/State.java
@@ -40,15 +40,19 @@ public class State {
return scopes.peek().resolveSymbol(symbol, Arrays.asList());
}
- public Datatype getSymbolValue(String symbol) throws TunkkiError {
+ public Datatype evaluateSymbol(String symbol) throws TunkkiError {
Datatype d = resolveSymbol(symbol);
return d;
}
- public Datatype getSymbolValue(String symbol, List<Datatype> parameters) throws TunkkiError {
+ public Datatype evaluateSymbol(String symbol, List<Datatype> parameters) throws TunkkiError {
return scopes.peek().resolveSymbol(symbol, parameters);
}
+ public boolean isFunction(String symbol) {
+ return scopes.peek().isFunction(symbol);
+ }
+
public Scope createScope() {
Scope scope = new Scope();
if (scopes.size() > 0) {
@@ -75,4 +79,8 @@ public class State {
public Scope popScope() {
return scopes.pop();
}
+
+ public Datatype makeFunctionReference(String name) {
+ return scopes.peek().getCallable(name);
+ }
}
diff --git a/src/main/com/jantuomi/tunkki/core/tokenizer/token/types/CallToken.java b/src/main/com/jantuomi/tunkki/core/tokenizer/token/types/CallToken.java
index fb925f2..daa55ce 100644
--- a/src/main/com/jantuomi/tunkki/core/tokenizer/token/types/CallToken.java
+++ b/src/main/com/jantuomi/tunkki/core/tokenizer/token/types/CallToken.java
@@ -1,7 +1,7 @@
package com.jantuomi.tunkki.core.tokenizer.token.types;
import com.jantuomi.tunkki.core.parser.ast.ASTNode;
-import com.jantuomi.tunkki.core.parser.ast.SymbolNode;
+import com.jantuomi.tunkki.core.parser.ast.CallNode;
import com.jantuomi.tunkki.core.tokenizer.token.Token;
import com.jantuomi.tunkki.exception.TunkkiError;
@@ -18,7 +18,7 @@ public class CallToken extends VarargOperatorToken {
@Override
public ASTNode generateNode() throws TunkkiError {
- SymbolNode node = new SymbolNode(this);
+ CallNode node = new CallNode(this);
node.setName(this.getText());
List<ASTNode> arguments = new ArrayList<>();
diff --git a/src/main/com/jantuomi/tunkki/exception/TunkkiError.java b/src/main/com/jantuomi/tunkki/exception/TunkkiError.java
index 9e0163c..dd48077 100644
--- a/src/main/com/jantuomi/tunkki/exception/TunkkiError.java
+++ b/src/main/com/jantuomi/tunkki/exception/TunkkiError.java
@@ -31,7 +31,7 @@ public class TunkkiError extends Exception {
errorTexts.put(ExceptionType.TypeError, "Incompatible types %s and %s.");
errorTexts.put(ExceptionType.ExpectedDifferentTokenError, "Token '%s' expects a different token stack.");
errorTexts.put(ExceptionType.FunctionArgumentError, "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].");
+ errorTexts.put(ExceptionType.UndeclaredSymbolError, "No symbol %s defined in the current scope.");
errorTexts.put(ExceptionType.IncludeError, "File %s could not be included.");
errorTexts.put(ExceptionType.GeneralError, "%s");
errorTexts.put(ExceptionType.NadaError, "Can't do operation with a nada value.");