diff options
| author | Jan Tuomi <jans.tuomi@gmail.com> | 2016-07-30 12:24:06 +0300 |
|---|---|---|
| committer | Jan Tuomi <jans.tuomi@gmail.com> | 2016-07-30 12:24:06 +0300 |
| commit | 8813de2902e06c61b2bdc8697b1cc987f920dc1f (patch) | |
| tree | ba0f9d1086a8535aaef3321b2a4c6ee71b5141e0 /src/main/com/jantuomi | |
| parent | 6c6eabea8947a9ae83e6ba98112574c1a2f25a34 (diff) | |
Function references are now correctly first class citizens
Resolves #7
Diffstat (limited to 'src/main/com/jantuomi')
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."); |
