diff options
| author | Jan Tuomi <jans.tuomi@gmail.com> | 2016-06-21 20:07:32 +0300 |
|---|---|---|
| committer | Jan Tuomi <jans.tuomi@gmail.com> | 2016-07-26 19:47:03 +0300 |
| commit | 45a2b88d584fc8bdee1fbaf0def1d9b55ba26eff (patch) | |
| tree | 1cf80f1b4384e27054c3cb2f90ac6f1953e89f35 /main | |
| parent | d745f000d6d60b9cdf0ba40dbf80660c1aa6bc61 (diff) | |
Added scopes, variables and functions
Diffstat (limited to 'main')
20 files changed, 336 insertions, 27 deletions
diff --git a/main/core/parser/ASTGenerator.java b/main/core/parser/ASTGenerator.java index 548735b..3d19a8c 100644 --- a/main/core/parser/ASTGenerator.java +++ b/main/core/parser/ASTGenerator.java @@ -2,6 +2,7 @@ package com.jantuomi.interpreter.main.core.parser; import com.jantuomi.interpreter.main.core.parser.ast.ASTNode; import com.jantuomi.interpreter.main.core.tokenizer.token.Token; +import com.jantuomi.interpreter.main.exception.InterpreterException; import java.util.ArrayList; import java.util.List; @@ -18,7 +19,7 @@ public class ASTGenerator { return instance; } - public List<ASTNode> generate(List<Token> trees) { + public List<ASTNode> generate(List<Token> trees) throws InterpreterException { List<ASTNode> list = new ArrayList<>(); for (Token root : trees) { diff --git a/main/core/parser/ast/AssignmentNode.java b/main/core/parser/ast/AssignmentNode.java new file mode 100644 index 0000000..bcbff1c --- /dev/null +++ b/main/core/parser/ast/AssignmentNode.java @@ -0,0 +1,33 @@ +package com.jantuomi.interpreter.main.core.parser.ast; + +import com.jantuomi.interpreter.main.core.parser.datatype.DataContainer; +import com.jantuomi.interpreter.main.core.runtime.State; +import com.jantuomi.interpreter.main.core.tokenizer.token.Token; + +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() { + 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/main/core/parser/ast/FunctionDefineNode.java b/main/core/parser/ast/FunctionDefineNode.java index e867f78..2402bed 100644 --- a/main/core/parser/ast/FunctionDefineNode.java +++ b/main/core/parser/ast/FunctionDefineNode.java @@ -1,8 +1,14 @@ package com.jantuomi.interpreter.main.core.parser.ast; import com.jantuomi.interpreter.main.core.parser.datatype.DataContainer; +import com.jantuomi.interpreter.main.core.parser.datatype.StringDataContainer; +import com.jantuomi.interpreter.main.core.runtime.Function; +import com.jantuomi.interpreter.main.core.runtime.State; import com.jantuomi.interpreter.main.core.tokenizer.token.Token; +import java.util.ArrayList; +import java.util.List; + /** * Created by jan on 17.6.2016. */ @@ -26,8 +32,15 @@ public class FunctionDefineNode extends VarargOperatorNode { @Override public DataContainer evaluate() { - // TODO add function in State - return null; + List<String> argumentNames = new ArrayList<>(); + for (ASTNode arg : args) { + SymbolNode argSym = (SymbolNode) arg; + argumentNames.add(argSym.getName()); + } + Function function = new Function(argumentNames, (FunctionBodyNode) body); + State.getInstance().addFunctionToScope(name, function); + + return new StringDataContainer("function " + name); } @Override diff --git a/main/core/parser/ast/SymbolNode.java b/main/core/parser/ast/SymbolNode.java index 7ea8d96..4dfb403 100644 --- a/main/core/parser/ast/SymbolNode.java +++ b/main/core/parser/ast/SymbolNode.java @@ -4,6 +4,7 @@ import com.jantuomi.interpreter.main.core.parser.datatype.DataContainer; import com.jantuomi.interpreter.main.core.runtime.State; import com.jantuomi.interpreter.main.core.tokenizer.token.Token; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -26,6 +27,10 @@ public class SymbolNode extends ASTNode { this.name = name; } + public String getName() { + return name; + } + private String name; public SymbolNode(Token token) { @@ -34,7 +39,13 @@ public class SymbolNode extends ASTNode { @Override public DataContainer evaluate() { - return State.getInstance().getSymbolValue(name, parameterListNode.getParameters()); + List<DataContainer> paramValues = new ArrayList<>(); + if (parameterListNode != null) { + for (ASTNode param : parameterListNode.getChildren()) { + paramValues.add(param.evaluate()); + } + } + return State.getInstance().getSymbolValue(name, paramValues); } @Override diff --git a/main/core/parser/ast/VariableDeclareNode.java b/main/core/parser/ast/VariableDeclareNode.java new file mode 100644 index 0000000..185edda --- /dev/null +++ b/main/core/parser/ast/VariableDeclareNode.java @@ -0,0 +1,32 @@ +package com.jantuomi.interpreter.main.core.parser.ast; + +import com.jantuomi.interpreter.main.core.parser.datatype.DataContainer; +import com.jantuomi.interpreter.main.core.parser.datatype.StringDataContainer; +import com.jantuomi.interpreter.main.core.runtime.State; +import com.jantuomi.interpreter.main.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/main/core/runtime/Function.java b/main/core/runtime/Function.java new file mode 100644 index 0000000..cf6422f --- /dev/null +++ b/main/core/runtime/Function.java @@ -0,0 +1,41 @@ +package com.jantuomi.interpreter.main.core.runtime; + +import com.jantuomi.interpreter.main.core.parser.ast.FunctionBodyNode; +import com.jantuomi.interpreter.main.core.parser.datatype.DataContainer; + +import java.util.List; + +/** + * Created by jan on 20.6.2016. + */ +public class Function { + + private List<String> argumentNames; + + private FunctionBodyNode body; + + public Function(List<String> argumentNames, FunctionBodyNode body) { + this.argumentNames = argumentNames; + this.body = body; + } + + public DataContainer evaluate(List<DataContainer> params) { + 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/main/core/runtime/Scope.java b/main/core/runtime/Scope.java new file mode 100644 index 0000000..a45cdd7 --- /dev/null +++ b/main/core/runtime/Scope.java @@ -0,0 +1,48 @@ +package com.jantuomi.interpreter.main.core.runtime; + +import com.jantuomi.interpreter.main.core.parser.datatype.DataContainer; + +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) { + if (functions.containsKey(symbol)) { + return functions.get(symbol).evaluate(params); + } + 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/main/core/runtime/State.java b/main/core/runtime/State.java index 7d1a2fa..72a268b 100644 --- a/main/core/runtime/State.java +++ b/main/core/runtime/State.java @@ -1,11 +1,10 @@ package com.jantuomi.interpreter.main.core.runtime; -import com.jantuomi.interpreter.main.core.parser.ast.ASTNode; import com.jantuomi.interpreter.main.core.parser.datatype.DataContainer; -import java.util.HashMap; +import java.util.Arrays; import java.util.List; -import java.util.Map; +import java.util.Stack; /** * Created by jan on 11.6.2016. @@ -17,26 +16,50 @@ public class State { return instance; } - private Map<String, DataContainer> variables = new HashMap<>(); + private Stack<Scope> scopes = new Stack<>(); private State() { + /* Push global scope onto the stack */ + scopes.push(new Scope()); + } + private DataContainer resolveSymbol(String symbol) { + return scopes.peek().resolveSymbol(symbol, Arrays.asList()); } public DataContainer getSymbolValue(String symbol) { - if (variables.keySet().contains(symbol)) { - return variables.get(symbol); + DataContainer d = resolveSymbol(symbol); + return d; + } + + public DataContainer getSymbolValue(String symbol, List<DataContainer> parameters) { + return scopes.peek().resolveSymbol(symbol, parameters); + } + + public Scope createScope() { + Scope scope = new Scope(); + if (scopes.size() > 0) { + scope.setParent(scopes.peek()); } else { - return null; + 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 DataContainer getSymbolValue(String symbol, List<ASTNode> parameters) { - // TODO - return null; + public void setSymbolValueToScope(String symbol, DataContainer value) { + scopes.peek().setVariableValue(symbol, value); } - public void setSymbolValue(String symbol, DataContainer value) { - variables.put(symbol, value); + public Scope popScope() { + return scopes.pop(); } } diff --git a/main/core/tokenizer/Tokenizer.java b/main/core/tokenizer/Tokenizer.java index 9aed09c..30bc86e 100644 --- a/main/core/tokenizer/Tokenizer.java +++ b/main/core/tokenizer/Tokenizer.java @@ -41,7 +41,7 @@ public class Tokenizer { tokenRegexes.put(Token.Type.SubtractionToken, "^(\\-)"); tokenRegexes.put(Token.Type.DivisionToken, "^(\\/)"); tokenRegexes.put(Token.Type.MultiplicationToken, "^(\\*)"); - tokenRegexes.put(Token.Type.AssignmentToken, "^(\\<\\-)"); + tokenRegexes.put(Token.Type.AssignmentToken, "^(set)\\b"); tokenRegexes.put(Token.Type.LessThanToken, "^(\\<)"); tokenRegexes.put(Token.Type.GreaterThanToken, "^(\\>)"); tokenRegexes.put(Token.Type.LessOrEqualThanToken, "^(\\<\\=)"); diff --git a/main/core/tokenizer/token/Token.java b/main/core/tokenizer/token/Token.java index 5248799..2582590 100644 --- a/main/core/tokenizer/token/Token.java +++ b/main/core/tokenizer/token/Token.java @@ -28,7 +28,7 @@ abstract public class Token { } } - abstract public ASTNode generateNode(); + abstract public ASTNode generateNode() throws InterpreterException; /* Token types, ordered by precedence */ public enum Type { @@ -165,6 +165,10 @@ abstract public class Token { return new EndFunctionDefineToken(); case FunctionBodyToken: return new FunctionBodyToken(); + case DeclarationToken: + return new VariableDeclareToken(); + case AssignmentToken: + return new AssignmentToken(); case SymbolToken: return new SymbolToken(text); case OpenParenToken: diff --git a/main/core/tokenizer/token/types/AdditionToken.java b/main/core/tokenizer/token/types/AdditionToken.java index 2d77b46..4623d73 100644 --- a/main/core/tokenizer/token/types/AdditionToken.java +++ b/main/core/tokenizer/token/types/AdditionToken.java @@ -2,6 +2,7 @@ package com.jantuomi.interpreter.main.core.tokenizer.token.types; import com.jantuomi.interpreter.main.core.parser.ast.ASTNode; import com.jantuomi.interpreter.main.core.parser.ast.AdditionNode; +import com.jantuomi.interpreter.main.exception.InterpreterException; /** * Created by jan on 15.6.2016. @@ -12,7 +13,7 @@ public class AdditionToken extends BinaryOperatorToken { } @Override - public ASTNode generateNode() { + public ASTNode generateNode() throws InterpreterException { return new AdditionNode(this, lhs.generateNode(), rhs.generateNode() diff --git a/main/core/tokenizer/token/types/AssignmentToken.java b/main/core/tokenizer/token/types/AssignmentToken.java new file mode 100644 index 0000000..57f404c --- /dev/null +++ b/main/core/tokenizer/token/types/AssignmentToken.java @@ -0,0 +1,55 @@ +package com.jantuomi.interpreter.main.core.tokenizer.token.types; + +import com.jantuomi.interpreter.main.core.parser.ast.ASTNode; +import com.jantuomi.interpreter.main.core.parser.ast.AssignmentNode; +import com.jantuomi.interpreter.main.core.parser.ast.SymbolNode; +import com.jantuomi.interpreter.main.core.tokenizer.token.Token; +import com.jantuomi.interpreter.main.exception.ExceptionManager; +import com.jantuomi.interpreter.main.exception.InterpreterException; + +import java.util.Arrays; +import java.util.List; + +/** + * Created by jan on 20.6.2016. + */ +public class AssignmentToken extends Token { + + private Token lhs; + private Token rhs; + + 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; + } + + @Override + public Token setArguments(List<Token> args) { + this.lhs = args.get(0); + this.rhs = args.get(1); + return this; + } + + @Override + public List<Token> getChildren() { + return Arrays.asList(lhs, rhs); + } +} diff --git a/main/core/tokenizer/token/types/FunctionBodyToken.java b/main/core/tokenizer/token/types/FunctionBodyToken.java index 647ed55..f71e8a0 100644 --- a/main/core/tokenizer/token/types/FunctionBodyToken.java +++ b/main/core/tokenizer/token/types/FunctionBodyToken.java @@ -3,6 +3,7 @@ package com.jantuomi.interpreter.main.core.tokenizer.token.types; import com.jantuomi.interpreter.main.core.parser.ast.ASTNode; import com.jantuomi.interpreter.main.core.parser.ast.FunctionBodyNode; import com.jantuomi.interpreter.main.core.tokenizer.token.Token; +import com.jantuomi.interpreter.main.exception.InterpreterException; import java.util.ArrayList; import java.util.List; @@ -16,7 +17,7 @@ public class FunctionBodyToken extends VarargOperatorToken { } @Override - public ASTNode generateNode() { + public ASTNode generateNode() throws InterpreterException { FunctionBodyNode node = new FunctionBodyNode(this); List<ASTNode> statements = new ArrayList<>(); for (int i = 0; i < args.size() - 1; i++) { diff --git a/main/core/tokenizer/token/types/FunctionDefineToken.java b/main/core/tokenizer/token/types/FunctionDefineToken.java index 6bbfd84..116d3db 100644 --- a/main/core/tokenizer/token/types/FunctionDefineToken.java +++ b/main/core/tokenizer/token/types/FunctionDefineToken.java @@ -3,6 +3,7 @@ package com.jantuomi.interpreter.main.core.tokenizer.token.types; import com.jantuomi.interpreter.main.core.parser.ast.ASTNode; import com.jantuomi.interpreter.main.core.parser.ast.FunctionBodyNode; import com.jantuomi.interpreter.main.core.parser.ast.FunctionDefineNode; +import com.jantuomi.interpreter.main.exception.InterpreterException; import java.util.ArrayList; import java.util.List; @@ -16,7 +17,7 @@ public class FunctionDefineToken extends VarargOperatorToken { } @Override - public ASTNode generateNode() { + public ASTNode generateNode() throws InterpreterException { FunctionDefineNode node = new FunctionDefineNode(this); node.setName(args.get(0).getText()); diff --git a/main/core/tokenizer/token/types/OpenParenToken.java b/main/core/tokenizer/token/types/OpenParenToken.java index 07385c9..80b507c 100644 --- a/main/core/tokenizer/token/types/OpenParenToken.java +++ b/main/core/tokenizer/token/types/OpenParenToken.java @@ -3,6 +3,7 @@ package com.jantuomi.interpreter.main.core.tokenizer.token.types; import com.jantuomi.interpreter.main.core.parser.ast.ASTNode; import com.jantuomi.interpreter.main.core.parser.ast.ParameterListNode; import com.jantuomi.interpreter.main.core.tokenizer.token.Token; +import com.jantuomi.interpreter.main.exception.InterpreterException; /** * Created by jan on 19.6.2016. @@ -13,7 +14,7 @@ public class OpenParenToken extends VarargOperatorToken { } @Override - public ASTNode generateNode() { + public ASTNode generateNode() throws InterpreterException { ParameterListNode node = new ParameterListNode(this); for (Token token : args) { diff --git a/main/core/tokenizer/token/types/SubtractionToken.java b/main/core/tokenizer/token/types/SubtractionToken.java index a1b9a83..9f7ff10 100644 --- a/main/core/tokenizer/token/types/SubtractionToken.java +++ b/main/core/tokenizer/token/types/SubtractionToken.java @@ -2,6 +2,7 @@ package com.jantuomi.interpreter.main.core.tokenizer.token.types; import com.jantuomi.interpreter.main.core.parser.ast.ASTNode; import com.jantuomi.interpreter.main.core.parser.ast.SubtractionNode; +import com.jantuomi.interpreter.main.exception.InterpreterException; /** * Created by jan on 16.6.2016. @@ -12,7 +13,7 @@ public class SubtractionToken extends BinaryOperatorToken { } @Override - public ASTNode generateNode() { + public ASTNode generateNode() throws InterpreterException { return new SubtractionNode(this, lhs.generateNode(), rhs.generateNode() diff --git a/main/core/tokenizer/token/types/SymbolToken.java b/main/core/tokenizer/token/types/SymbolToken.java index b091ac9..d750921 100644 --- a/main/core/tokenizer/token/types/SymbolToken.java +++ b/main/core/tokenizer/token/types/SymbolToken.java @@ -4,6 +4,7 @@ import com.jantuomi.interpreter.main.core.parser.ast.ASTNode; import com.jantuomi.interpreter.main.core.parser.ast.ParameterListNode; import com.jantuomi.interpreter.main.core.parser.ast.SymbolNode; import com.jantuomi.interpreter.main.core.tokenizer.token.Token; +import com.jantuomi.interpreter.main.exception.InterpreterException; import java.util.Arrays; import java.util.List; @@ -24,7 +25,7 @@ public class SymbolToken extends Token { } @Override - public ASTNode generateNode() { + public ASTNode generateNode() throws InterpreterException { SymbolNode node = new SymbolNode(this); node.setName(this.getText()); if (callArgumentList != null) { diff --git a/main/core/tokenizer/token/types/VariableDeclareToken.java b/main/core/tokenizer/token/types/VariableDeclareToken.java new file mode 100644 index 0000000..1ec0826 --- /dev/null +++ b/main/core/tokenizer/token/types/VariableDeclareToken.java @@ -0,0 +1,42 @@ +package com.jantuomi.interpreter.main.core.tokenizer.token.types; + +import com.jantuomi.interpreter.main.core.parser.ast.ASTNode; +import com.jantuomi.interpreter.main.core.parser.ast.SymbolNode; +import com.jantuomi.interpreter.main.core.parser.ast.VariableDeclareNode; +import com.jantuomi.interpreter.main.core.tokenizer.token.Token; +import com.jantuomi.interpreter.main.exception.InterpreterException; + +import java.util.Arrays; +import java.util.List; + +/** + * Created by jan on 20.6.2016. + */ +public class VariableDeclareToken extends Token { + + private SymbolToken variable; + + public VariableDeclareToken() { + super(Type.DeclarationToken, "decl"); + } + + @Override + public ASTNode generateNode() throws InterpreterException { + VariableDeclareNode node = new VariableDeclareNode(this, + (SymbolNode) variable.generateNode()); + return node; + } + + @Override + public Token setArguments(List<Token> args) { + if (args.size() > 0) { + this.variable = (SymbolToken) args.get(0); + } + return this; + } + + @Override + public List<Token> getChildren() { + return Arrays.asList(variable); + } +} diff --git a/main/exception/ExceptionManager.java b/main/exception/ExceptionManager.java index 2dd46f5..7eabe14 100644 --- a/main/exception/ExceptionManager.java +++ b/main/exception/ExceptionManager.java @@ -18,6 +18,4 @@ public class ExceptionManager { InterpreterException e = new InterpreterException(ex, line, args); throw e; } - - } diff --git a/main/exception/InterpreterException.java b/main/exception/InterpreterException.java index 1565df9..8421edc 100644 --- a/main/exception/InterpreterException.java +++ b/main/exception/InterpreterException.java @@ -14,7 +14,8 @@ public class InterpreterException extends Exception { UnknownOperatorError, SyntaxError, TypeError, - ArgumentError + ArgumentError, + UndeclaredSymbolError } public static Map<ExceptionType, String> errorTexts = new HashMap<>(); @@ -25,6 +26,7 @@ public class InterpreterException extends Exception { errorTexts.put(ExceptionType.SyntaxError, "Unexpected %s."); errorTexts.put(ExceptionType.TypeError, "Incompatible types %s and %s."); errorTexts.put(ExceptionType.ArgumentError, "Function %s requires %s arguments."); + errorTexts.put(ExceptionType.UndeclaredSymbolError, "No symbol %s defined."); } private ExceptionType exceptionType; |
