diff --git a/BuiltinFunctions/Print.cs b/BuiltinFunctions/Print.cs index d242453..1185dc6 100644 --- a/BuiltinFunctions/Print.cs +++ b/BuiltinFunctions/Print.cs @@ -1,5 +1,5 @@ using System.Text; -using Interpreter.Tokens; +using Interpreter.Tokens.Operators.N_Ary; using Interpreter.Types.Function; using Object = Interpreter.Types.Object; using TrieDictionary; @@ -7,9 +7,9 @@ namespace Interpreter.BuiltinFunctions; public class Print : FunctionBody { - public Print(Token[] expressions) : base(expressions) { } + public Print(MultilineStatementOperator expressions) : base(expressions) { } - public override Object Execute(Object[] args, TrieDictionary vars) { + public override Object Execute(Object[] args, TrieDictionary vars, List> topScopeVars) { StringBuilder sb = new StringBuilder(); foreach (Object o in args) sb.Append(o.ToString()).Append(" "); diff --git a/Lexer.cs b/Lexer.cs index 7ecc676..678b691 100644 --- a/Lexer.cs +++ b/Lexer.cs @@ -4,5 +4,5 @@ namespace Interpreter; public class Lexer { // Regex matching all valid strings, with the least complicated in the back so that e.g. == gets matched as == and not as =, = - public static CheckedString[] Lex(string line, int lineNo) => Regex.Matches(line, "([a-zA-Z0-9]+|==|!=|\\|\\||&&|>=|<=|[\\^*/%+-=(){}#<>!])").ToList().Select(match => new CheckedString {Str = match.Value.Trim(), Line = lineNo}).ToArray(); + public static CheckedString[] Lex(string line, int lineNo) => Regex.Matches(line, "([a-zA-Z0-9]+|==|!=|\\|\\||&&|>=|<=|[\\^*/%+-=(){}#<>!,])").ToList().Select(match => new CheckedString {Str = match.Value.Trim(), Line = lineNo}).ToArray(); } \ No newline at end of file diff --git a/Parser.cs b/Parser.cs index b01369c..7b5e71d 100644 --- a/Parser.cs +++ b/Parser.cs @@ -4,7 +4,9 @@ using Interpreter.Tokens.Operators.Binary.Boolean; using Interpreter.Tokens.Operators.N_Ary; using Interpreter.Tokens.Operators.Unary; -using Interpreter.Tokens.Statements; +using Interpreter.Tokens.Separators; +using Interpreter.Tokens.Statements.Binary; +using Interpreter.Tokens.Statements.Unary; using TrieDictionary; using Object = Interpreter.Types.Object; @@ -12,9 +14,9 @@ namespace Interpreter; public class Parser { public static int GetTopElementIndex(Token[] line, int startIndex, bool isRightBound) { - if (line[startIndex] is Statement) + if (line[startIndex] is BinaryStatement) return startIndex; - + int highestPriorityNum = -1; int index = -1; for (int i = startIndex; i < line.Length && i >= 0; i += isRightBound ? 1 : -1) { @@ -62,7 +64,7 @@ public static CheckedString[] CheckComment(CheckedString[] line) { /** * This now practically just parses everything, so maybe some refactoring is needed */ - private static Token SymmetricBinaryOperatorParse(Token[] line, int i, List> vars, string[] lines, ref int lineNo, int depth, bool isRightBound) { + private static Token SymmetricBinaryOperatorParse(Token[] line, int i, string[] lines, ref int lineNo, int depth, bool isRightBound) { int startIndex = i + (isRightBound ? 1 : -1); int j = GetTopElementIndex(line, startIndex, isRightBound); if (j == startIndex && !isRightBound) { @@ -80,94 +82,76 @@ private static Token SymmetricBinaryOperatorParse(Token[] line, int i, List> vars, string[] lines, ref int lineNo, int depth, bool isRightBound) { - int startIndex = -1; - int highestPriorityNum = -1; - int index = -1; - Token[] subLine = {}; - int numBrackets = 1; - for (int j = i + (isRightBound ? 1 : -1); numBrackets > 0; j += isRightBound ? 1 : -1) { - // Go until paired bracket is found - if (line[j].Str == ")") - numBrackets += isRightBound ? -1 : 1; - else if (line[j].Str == "(") - numBrackets += isRightBound ? 1 : -1; - - if (numBrackets == 0) - break; - - // If there is a nested set of brackets, add that entire set immediately, because otherwise something goes wrong - if (isRightBound ? line[j].Str == "(" : line[j].Str == ")") { - while (numBrackets > 1) { - if (isRightBound && subLine.Length == 0) - startIndex = j; - subLine = isRightBound ? subLine.Append(line[j]).ToArray() : subLine.Prepend(line[j]).ToArray(); - j += isRightBound ? 1 : -1; - if (line[j].Str == "(") - numBrackets += isRightBound ? 1 : -1; - else if (line[j].Str == ")") - numBrackets += isRightBound ? -1 : 1; - } + private static Token[] ParenthesesParse(Token[] line, int i, string[] lines, ref int lineNo, int depth, bool isRightBound) { + List arguments = new List(); + List subLine = new List(); + int numBrackets = 0; + for (int j = i + (isRightBound ? 1 : -1); line[j].Str != (isRightBound ? ")" : "("); j += isRightBound ? 1 : -1) { + if (line[j].Str == "(") + numBrackets++; + else if (line[j].Str == ")") + numBrackets--; + + while (numBrackets != 0) { + if (isRightBound) + subLine.Add(line[j]); + else + subLine = subLine.Prepend(line[j]).ToList(); + + j += isRightBound ? 1 : -1; + + if (line[j].Str == "(") + numBrackets++; + else if (line[j].Str == ")") + numBrackets--; } - if (isRightBound) { - if (subLine.Length == 0) - startIndex = j; - subLine = subLine.Append(line[j]).ToArray(); - } else { - startIndex = j; - subLine = subLine.Prepend(line[j]).ToArray(); + // When a comma is found, add the current buffer as an argument and start on a new argument + if (line[j] is CommaSeparator) { + if (isRightBound) + arguments.Add(subLine.ToArray()); + else + arguments = arguments.Prepend(subLine.ToArray()).ToList(); + subLine = new List(); + continue; } - // Get the index of the operator with the lowest priority (highest number) to make sure that gets parsed first - // This should really go through GetTopElementIndex - int priority = -1; - try { - priority = Program.priorities[line[j].Str]; - } catch (KeyNotFoundException) { } - - if (line[j] is BinaryOperator && priority != -1) { - if (isRightBound ? priority >= highestPriorityNum : priority > highestPriorityNum) { - highestPriorityNum = priority; - index = j; - } - } + if (isRightBound) + subLine.Add(line[j]); + else + subLine = subLine.Prepend(line[j]).ToList(); } - - if (index == -1) - index = startIndex; // This makes sure index-startIndex is 0, because the first and only element should be parsed - if (startIndex == -1) { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Error in bracket parsing"); - Console.ResetColor(); - } + if (subLine.Count > 0) + if (isRightBound) + arguments.Add(subLine.ToArray()); + else + arguments = arguments.Prepend(subLine.ToArray()).ToList(); - // Parse the data in the brackets, where index is the index of the head of the tree in line, so index-i - // (i being the starting point of subLine in line) will be the index in subLine plus one - return Parse(subLine, index - startIndex, vars, lines, ref lineNo, depth + 1); + // Parse each element in the brackets and put it in a new list + List properArguments = new List(); + for (int j = 0; j < arguments.Count; j++) + properArguments.Add(Parse(arguments[j], GetTopElementIndex(arguments[j].ToArray(), 0, isRightBound), lines, ref lineNo, depth + 1)); + + return properArguments.ToArray(); } /** * Note that this is a bad implementation with too strict constraints, but for now, only functionality is important */ - private static MultiLineStatementOperator CurlyBracketsParse(string[] lines, ref int i, List> vars, int depth) { + private static MultilineStatementOperator CurlyBracketsParse(Token[] line, string[] lines, ref int i, int depth) { // Get copy of vars so that it doesn't get affected by method calls lower in the recursion tree - List> properVars = new List>(vars); - properVars.Add(new TrieDictionary()); - - MultiLineStatementOperator mso = new MultiLineStatementOperator(); List tokens = new List(); int initialIndex = i++; // immediately increment i so that this function doesn't try to parse itself, but instead the next line int numBrackets = 1; @@ -178,10 +162,10 @@ private static MultiLineStatementOperator CurlyBracketsParse(string[] lines, ref if (lexedLine.Length == 0) continue; - Token[] tokenizedLine = Tokenizer.Tokenize(lexedLine, properVars); + Token[] tokenizedLine = Tokenizer.Tokenize(lexedLine); int before = i; - tokens.Add(Parse(tokenizedLine, GetTopElementIndex(tokenizedLine, 0, true), properVars, lines, ref i, depth + 1)); + tokens.Add(Parse(tokenizedLine, GetTopElementIndex(tokenizedLine, 0, true), lines, ref i, depth + 1)); if (i != before) continue; @@ -199,12 +183,12 @@ private static MultiLineStatementOperator CurlyBracketsParse(string[] lines, ref if (i >= lines.Length) throw new FormatException("no matched bracket for bracket on line " + initialIndex); - mso.Children = tokens.ToArray(); + ((MultilineStatementOperator) line[^1]).Children = tokens.ToArray(); - return mso; + return (MultilineStatementOperator) line[^1]; } - public static Token Parse(Token[] line, int i, List> vars, string[] lines, ref int lineNo, int depth) { + public static Token Parse(Token[] line, int i, string[] lines, ref int lineNo, int depth) { Token t = line[i]; // Check which lowest level class (i.e. most abstract), which can be parsed uniformly, the object is an instance of @@ -212,34 +196,35 @@ public static Token Parse(Token[] line, int i, List> vars line[i].IsDone = true; // Parse only the appropriate section (i.e. Left should only parse to the left and Right only to the right, that's what the array slicing does) - ((BinaryOperator) t).Left = SymmetricBinaryOperatorParse(line.Take(i+1).ToArray(), i, vars, lines, ref lineNo, depth + 1, false); - ((BinaryOperator) t).Right = SymmetricBinaryOperatorParse(new ArraySegment(line, i, line.Length - i).ToArray(), 0, vars, lines, ref lineNo, depth + 1, true); + ((BinaryOperator) t).Left = SymmetricBinaryOperatorParse(line.Take(i+1).ToArray(), i, lines, ref lineNo, depth + 1, false); + ((BinaryOperator) t).Right = SymmetricBinaryOperatorParse(new ArraySegment(line, i, line.Length - i).ToArray(), 0, lines, ref lineNo, depth + 1, true); } else if (t is DeclarationOperator decOp) { - decOp.SetVars(vars); - decOp.Left = Parse(line, i + 1, vars, lines, ref lineNo, depth+1); + decOp.Left = Parse(line, i + 1, lines, ref lineNo, depth+1); if (i + 2 < line.Length) // Only Parse right hand side if it exists - decOp.Right = Parse(line, i + 2, vars, lines, ref lineNo, depth + 1); + decOp.Right = Parse(line, i + 2, lines, ref lineNo, depth + 1); } else if (t is AssignmentOperator assOp) { assOp.IsDone = true; - assOp.SetVars(vars); - assOp.Left = Parse(line, i - 1, vars, lines, ref lineNo, depth+1); + assOp.Left = Parse(line, i - 1, lines, ref lineNo, depth+1); Token[] subLine = new ArraySegment(line, i, line.Length - i).ToArray(); - assOp.Right = Parse(subLine, GetTopElementIndex(subLine, 1, true), vars, lines, ref lineNo, depth+1); + assOp.Right = Parse(subLine, GetTopElementIndex(subLine, 1, true), lines, ref lineNo, depth+1); } else if (t is ParenthesesOperator parOp) { - parOp.Child = ParenthesesParse(line, i, vars, lines, ref lineNo, depth + 1, line[i].Str == "("); - } else if (t is MinusUnaryOperator minUnOp) { - minUnOp.Child = Parse(line, i + 1, vars, lines, ref lineNo, depth + 1); - } else if (t is NotUnaryOperator notUnOp) { - notUnOp.Child = Parse(line, i + 1, vars, lines, ref lineNo, depth + 1); - } else if (t is VariableToken vt) { // TODO: make sure multiple arguments get parsed properly + parOp.Children = ParenthesesParse(line, i, lines, ref lineNo, depth + 1, line[i].Str == "("); + } else if (t is UnaryOperator unOp) { + unOp.Child = Parse(line, i + 1, lines, ref lineNo, depth + 1); + } else if (t is VariableToken vt) { if (i + 1 < line.Length && line[i+1] is ParenthesesOperator) - vt.Args = Parse(line, i + 1, vars, lines, ref lineNo, depth + 1); - } else if (t is Statement statement) { - Token left = Parse(line, i + 1, vars, lines, ref lineNo, depth + 1); + vt.Args = Parse(line, i + 1, lines, ref lineNo, depth + 1); + } else if (t is BinaryStatement statement) { + int addition = 1; + if (t is FunctionStatement fs) { + addition = 2; + fs.Name = line[i + 1].Str; + } + Token left = Parse(line, i + addition, lines, ref lineNo, depth + 1); if (left is not ParenthesesOperator po) - throw new FormatException("statement condition on line " + left.Line + " is missing parentheses"); + throw new FormatException("statement condition/parameter declaration on line " + left.Line + " is missing parentheses"); statement.Left = po; @@ -254,7 +239,13 @@ public static Token Parse(Token[] line, int i, List> vars j++; } while (numBrackets != 0); - statement.Right = CurlyBracketsParse(lines, ref lineNo, vars, depth + 1); + statement.Right = CurlyBracketsParse(line, lines, ref lineNo, depth + 1); + } else if (t is UnaryStatement unStat) { + Token child = Parse(line, i + 1, lines, ref lineNo, depth + 1); + if (child is not ParenthesesOperator po) + throw new FormatException("statement argument on line " + child.Line + " is missing parentheses"); + + unStat.Child = po; } t.Line = line[i].Line; diff --git a/Program.cs b/Program.cs index 8f03977..399c684 100644 --- a/Program.cs +++ b/Program.cs @@ -4,12 +4,14 @@ using Interpreter.Tokens.Operators.Binary.Arithmetic; using Interpreter.Tokens.Operators.Binary.Boolean; using Interpreter.Tokens.Operators.Unary; -using Interpreter.Tokens.Statements; using Interpreter.Types.Function; using Boolean = Interpreter.Types.Comparable.Boolean; using Object = Interpreter.Types.Object; using TrieDictionary; using Interpreter.Tokens.Operators.N_Ary; +using Interpreter.Tokens.Separators; +using Interpreter.Tokens.Statements.Binary; +using Interpreter.Tokens.Statements.Unary; namespace Interpreter; @@ -34,8 +36,8 @@ public static void Main(string[] args) { // Brackets bindings.Insert("(", typeof(ParenthesesOperator)); bindings.Insert(")", typeof(ParenthesesOperator)); - bindings.Insert("{", typeof(MultiLineStatementOperator)); - bindings.Insert("}", typeof(MultiLineStatementOperator)); + bindings.Insert("{", typeof(MultilineStatementOperator)); + bindings.Insert("}", typeof(MultilineStatementOperator)); // Boolean logic bindings.Insert("&&", typeof(AndBinaryOperator)); @@ -53,6 +55,11 @@ public static void Main(string[] args) { // Statements bindings.Insert("on", typeof(OnStatement)); bindings.Insert("while", typeof(WhileLoop)); + bindings.Insert("function", typeof(FunctionStatement)); + bindings.Insert("return", typeof(ReturnStatement)); + + // Separators + bindings.Insert(",", typeof(CommaSeparator)); // Low number for priority means a higher priority priorities.Insert("(", 0); @@ -92,17 +99,17 @@ public static void Main(string[] args) { if (lexedLine.Length == 0) continue; - Token[] tokenizedLine = Tokenizer.Tokenize(lexedLine, new [] {vars}.ToList()); + Token[] tokenizedLine = Tokenizer.Tokenize(lexedLine); // Console.Write("["); // foreach (Token t in tokenizedLine) // Console.Write("{0}, ", t.GetType()); // Console.WriteLine("]"); - Token tree = Parser.Parse(tokenizedLine, Parser.GetTopElementIndex(tokenizedLine, 0, true), new [] {vars}.ToList(), lines, ref i, 0); + Token tree = Parser.Parse(tokenizedLine, Parser.GetTopElementIndex(tokenizedLine, 0, true), lines, ref i, 0); // Console.WriteLine(tree.ToString(0)); - tree.Evaluate(); + tree.Evaluate(new List> {vars}); } } } diff --git a/README.md b/README.md index b0e11f9..10aa608 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,16 @@ This repository contains the official interpreter for GSL (General Scripting Language).
+### Installation +#### Prerequisites +- dotnet SDK + +#### Dependencies +Run `dotnet restore` in the project directory to install the dependencies. + +#### Execution +Run `dotnet run ` to build the project and run your input file. Of course, `` should be replaced with the name of the GSL file you want to run. + ### Simplicity with understanding GSL is designed as a simple language, which is supposed to make complicated tasks easier without losing the knowledge of what the programmer is doing.
diff --git a/Tokenizer.cs b/Tokenizer.cs index bddc87c..bc03054 100644 --- a/Tokenizer.cs +++ b/Tokenizer.cs @@ -3,13 +3,11 @@ using Interpreter.Tokens; using Interpreter.Tokens.Operators.Unary; using Interpreter.Types.Comparable; -using TrieDictionary; -using Object = Interpreter.Types.Object; namespace Interpreter; public class Tokenizer { - public static Token[] Tokenize(CheckedString[] line, List> vars) { + public static Token[] Tokenize(CheckedString[] line) { Token[] res = new Token[line.Length]; for (int i = 0; i < line.Length; i++) { @@ -34,7 +32,7 @@ public static Token[] Tokenize(CheckedString[] line, List if (tokenType != null!) { // Check if string is a keyword/operator res[i] = (Token) Activator.CreateInstance(tokenType)!; // Instantiate the corresponding class } else if (Regex.Matches(line[i].Str, "^[a-zA-Z]\\w*$").Count == 1) { - VariableToken vt = new VariableToken(vars); + VariableToken vt = new VariableToken(); vt.Name = line[i].Str; res[i] = vt; } else if (Regex.Matches(line[i].Str, "(\\s|^)-?\\d+(\\s|$)").Count == 1) { @@ -44,8 +42,7 @@ public static Token[] Tokenize(CheckedString[] line, List } else { throw new InvalidExpressionException("Line " + line[i].Line + ": " + line[i].Str + " is not a valid expression"); } - - + res[i].Str = line[i].Str; res[i].Line = line[i].Line; } diff --git a/Tokens/NumberToken.cs b/Tokens/NumberToken.cs index 5f96fb6..fbd4146 100644 --- a/Tokens/NumberToken.cs +++ b/Tokens/NumberToken.cs @@ -1,5 +1,6 @@ using System.Text; using Interpreter.Types.Comparable; +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens; @@ -20,9 +21,7 @@ public override string ToString(int indent) { return sb.ToString(); } - public override Object Evaluate() { - return Num; - } + public override Object Evaluate(List> vars) => Num; public override int Size() => 1; } \ No newline at end of file diff --git a/Tokens/Operators/Binary/Arithmetic/DivisionBinaryOperator.cs b/Tokens/Operators/Binary/Arithmetic/DivisionBinaryOperator.cs index f5ec5e1..9b42648 100644 --- a/Tokens/Operators/Binary/Arithmetic/DivisionBinaryOperator.cs +++ b/Tokens/Operators/Binary/Arithmetic/DivisionBinaryOperator.cs @@ -1,5 +1,6 @@ using Interpreter.Types.Comparable; using Object = Interpreter.Types.Object; +using TrieDictionary; namespace Interpreter.Tokens.Operators.Binary.Arithmetic; @@ -8,5 +9,5 @@ public DivisionBinaryOperator() { Symbol = "/"; } - public override Object Evaluate() => new Integer(((Integer) Left.Evaluate()).Int / ((Integer) Right.Evaluate()).Int); + public override Object Evaluate(List> vars) => new Integer(((Integer) Left.Evaluate(vars)).Int / ((Integer) Right.Evaluate(vars)).Int); } \ No newline at end of file diff --git a/Tokens/Operators/Binary/Arithmetic/MinusBinaryOperator.cs b/Tokens/Operators/Binary/Arithmetic/MinusBinaryOperator.cs index 182860b..2e0745a 100644 --- a/Tokens/Operators/Binary/Arithmetic/MinusBinaryOperator.cs +++ b/Tokens/Operators/Binary/Arithmetic/MinusBinaryOperator.cs @@ -1,4 +1,5 @@ using Interpreter.Types.Comparable; +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens.Operators.Binary.Arithmetic; @@ -8,5 +9,5 @@ public MinusBinaryOperator() { Symbol = "-"; } - public override Object Evaluate() => new Integer(((Integer) Left.Evaluate()).Int - ((Integer) Right.Evaluate()).Int); + public override Object Evaluate(List> vars) => new Integer(((Integer) Left.Evaluate(vars)).Int - ((Integer) Right.Evaluate(vars)).Int); } \ No newline at end of file diff --git a/Tokens/Operators/Binary/Arithmetic/ModulusBinaryOperator.cs b/Tokens/Operators/Binary/Arithmetic/ModulusBinaryOperator.cs index 4da22b7..4ab7193 100644 --- a/Tokens/Operators/Binary/Arithmetic/ModulusBinaryOperator.cs +++ b/Tokens/Operators/Binary/Arithmetic/ModulusBinaryOperator.cs @@ -1,4 +1,5 @@ using Interpreter.Types.Comparable; +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens.Operators.Binary.Arithmetic; @@ -17,5 +18,5 @@ private static int ProperModulus(int a, int b) { return a - div*b; } - public override Object Evaluate() => new Integer(ProperModulus(((Integer) Left.Evaluate()).Int, ((Integer) Right.Evaluate()).Int)); + public override Object Evaluate(List> vars) => new Integer(ProperModulus(((Integer) Left.Evaluate(vars)).Int, ((Integer) Right.Evaluate(vars)).Int)); } \ No newline at end of file diff --git a/Tokens/Operators/Binary/Arithmetic/MultiplicationBinaryOperator.cs b/Tokens/Operators/Binary/Arithmetic/MultiplicationBinaryOperator.cs index 9d88e9e..16f609c 100644 --- a/Tokens/Operators/Binary/Arithmetic/MultiplicationBinaryOperator.cs +++ b/Tokens/Operators/Binary/Arithmetic/MultiplicationBinaryOperator.cs @@ -1,4 +1,5 @@ using Interpreter.Types.Comparable; +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens.Operators.Binary.Arithmetic; @@ -8,5 +9,5 @@ public MultiplicationBinaryOperator() { Symbol = "*"; } - public override Object Evaluate() => new Integer(((Integer) Left.Evaluate()).Int * ((Integer) Right.Evaluate()).Int); + public override Object Evaluate(List> vars) => new Integer(((Integer) Left.Evaluate(vars)).Int * ((Integer) Right.Evaluate(vars)).Int); } \ No newline at end of file diff --git a/Tokens/Operators/Binary/Arithmetic/PlusBinaryOperator.cs b/Tokens/Operators/Binary/Arithmetic/PlusBinaryOperator.cs index 6469b91..c5b3624 100644 --- a/Tokens/Operators/Binary/Arithmetic/PlusBinaryOperator.cs +++ b/Tokens/Operators/Binary/Arithmetic/PlusBinaryOperator.cs @@ -1,4 +1,5 @@ using Interpreter.Types.Comparable; +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens.Operators.Binary.Arithmetic; @@ -8,5 +9,5 @@ public PlusBinaryOperator() { Symbol = "+"; } - public override Object Evaluate() => new Integer(((Integer) Left.Evaluate()).Int + ((Integer) Right.Evaluate()).Int); + public override Object Evaluate(List> vars) => new Integer(((Integer) Left.Evaluate(vars)).Int + ((Integer) Right.Evaluate(vars)).Int); } \ No newline at end of file diff --git a/Tokens/Operators/Binary/Arithmetic/PowerBinaryOperator.cs b/Tokens/Operators/Binary/Arithmetic/PowerBinaryOperator.cs index 9a67a48..5a583fa 100644 --- a/Tokens/Operators/Binary/Arithmetic/PowerBinaryOperator.cs +++ b/Tokens/Operators/Binary/Arithmetic/PowerBinaryOperator.cs @@ -1,4 +1,5 @@ using Interpreter.Types.Comparable; +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens.Operators.Binary.Arithmetic; @@ -8,5 +9,5 @@ public PowerBinaryOperator() { Symbol = "^"; } - public override Object Evaluate() => new Integer((int) Math.Pow(((Integer) Left.Evaluate()).Int, ((Integer) Right.Evaluate()).Int)); + public override Object Evaluate(List> vars) => new Integer((int) Math.Pow(((Integer) Left.Evaluate(vars)).Int, ((Integer) Right.Evaluate(vars)).Int)); } \ No newline at end of file diff --git a/Tokens/Operators/Binary/AssignmentOperator.cs b/Tokens/Operators/Binary/AssignmentOperator.cs index 1695876..92c000c 100644 --- a/Tokens/Operators/Binary/AssignmentOperator.cs +++ b/Tokens/Operators/Binary/AssignmentOperator.cs @@ -4,17 +4,11 @@ namespace Interpreter.Tokens.Operators.Binary; public class AssignmentOperator : BinaryOperator { - private List> vars = null!; - public AssignmentOperator() { Symbol = "="; } - public void SetVars(List> vars) { - this.vars = vars; - } - - public override Object Evaluate() { + public override Object Evaluate(List> vars) { Object leftCheck = null!; int scopeIndex; for (scopeIndex = vars.Count - 1; scopeIndex >= 0; scopeIndex--) try { @@ -25,8 +19,7 @@ public override Object Evaluate() { if (leftCheck == null!) throw new KeyNotFoundException("Line " + Line + ": Variable " + ((VariableToken) Left).Name + " does not exist"); - Object res = Right.Evaluate(); - vars[scopeIndex].Remove(((VariableToken) Left).Name); + Object res = Right.Evaluate(vars); vars[scopeIndex][((VariableToken) Left).Name] = res; return res; diff --git a/Tokens/Operators/Binary/Boolean/AndBinaryOperator.cs b/Tokens/Operators/Binary/Boolean/AndBinaryOperator.cs index 888e8fd..ec43969 100644 --- a/Tokens/Operators/Binary/Boolean/AndBinaryOperator.cs +++ b/Tokens/Operators/Binary/Boolean/AndBinaryOperator.cs @@ -1,3 +1,4 @@ +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens.Operators.Binary.Boolean; @@ -7,7 +8,5 @@ public AndBinaryOperator() { Symbol = "&&/and"; } - public override Object Evaluate() { - return new Types.Comparable.Boolean(((Types.Comparable.Boolean) Left.Evaluate()).Bool && ((Types.Comparable.Boolean) Right.Evaluate()).Bool); - } + public override Object Evaluate(List> vars) => new Types.Comparable.Boolean(((Types.Comparable.Boolean) Left.Evaluate(vars)).Bool && ((Types.Comparable.Boolean) Right.Evaluate(vars)).Bool); } \ No newline at end of file diff --git a/Tokens/Operators/Binary/Boolean/EqualityBinaryOperator.cs b/Tokens/Operators/Binary/Boolean/EqualityBinaryOperator.cs index beb66c3..10f874f 100644 --- a/Tokens/Operators/Binary/Boolean/EqualityBinaryOperator.cs +++ b/Tokens/Operators/Binary/Boolean/EqualityBinaryOperator.cs @@ -1,5 +1,6 @@ using Interpreter.Types.Comparable; using Object = Interpreter.Types.Object; +using TrieDictionary; namespace Interpreter.Tokens.Operators.Binary.Boolean; @@ -8,8 +9,8 @@ public EqualityBinaryOperator() { Symbol = "=="; } - public override Object Evaluate() { - Object leftObj = Left.Evaluate(), rightObj = Right.Evaluate(); + public override Object Evaluate(List> vars) { + Object leftObj = Left.Evaluate(vars), rightObj = Right.Evaluate(vars); if (leftObj is not Comparable c1) throw new IncomparableException("trying to compare incomparable type " + leftObj.GetType()); diff --git a/Tokens/Operators/Binary/Boolean/InequalityBinaryOperator.cs b/Tokens/Operators/Binary/Boolean/InequalityBinaryOperator.cs index 2250ec1..2404e00 100644 --- a/Tokens/Operators/Binary/Boolean/InequalityBinaryOperator.cs +++ b/Tokens/Operators/Binary/Boolean/InequalityBinaryOperator.cs @@ -1,4 +1,5 @@ using Interpreter.Types.Comparable; +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens.Operators.Binary.Boolean; @@ -8,8 +9,8 @@ public InequalityBinaryOperator() { Symbol = "!="; } - public override Object Evaluate() { - Object leftObj = Left.Evaluate(), rightObj = Right.Evaluate(); + public override Object Evaluate(List> vars) { + Object leftObj = Left.Evaluate(vars), rightObj = Right.Evaluate(vars); if (leftObj is not Comparable c1) throw new IncomparableException("trying to compare incomparable type " + leftObj.GetType()); diff --git a/Tokens/Operators/Binary/Boolean/LargerBinaryOperator.cs b/Tokens/Operators/Binary/Boolean/LargerBinaryOperator.cs index ebf1644..ed0bdae 100644 --- a/Tokens/Operators/Binary/Boolean/LargerBinaryOperator.cs +++ b/Tokens/Operators/Binary/Boolean/LargerBinaryOperator.cs @@ -1,4 +1,5 @@ using Interpreter.Types.Comparable; +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens.Operators.Binary.Boolean; @@ -8,7 +9,5 @@ public LargerBinaryOperator() { Symbol = ">"; } - public override Object Evaluate() { - return new Types.Comparable.Boolean(((Integer) Left.Evaluate()).Int > ((Integer) Right.Evaluate()).Int); - } + public override Object Evaluate(List> vars) => new Types.Comparable.Boolean(((Integer) Left.Evaluate(vars)).Int > ((Integer) Right.Evaluate(vars)).Int); } \ No newline at end of file diff --git a/Tokens/Operators/Binary/Boolean/LargerEqualBinaryOperator.cs b/Tokens/Operators/Binary/Boolean/LargerEqualBinaryOperator.cs index ca1a695..5d1f2d3 100644 --- a/Tokens/Operators/Binary/Boolean/LargerEqualBinaryOperator.cs +++ b/Tokens/Operators/Binary/Boolean/LargerEqualBinaryOperator.cs @@ -1,4 +1,5 @@ using Interpreter.Types.Comparable; +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens.Operators.Binary.Boolean; @@ -8,7 +9,5 @@ public LargerEqualBinaryOperator() { Symbol = ">="; } - public override Object Evaluate() { - return new Types.Comparable.Boolean(((Integer) Left.Evaluate()).Int >= ((Integer) Right.Evaluate()).Int); - } + public override Object Evaluate(List> vars) => new Types.Comparable.Boolean(((Integer) Left.Evaluate(vars)).Int >= ((Integer) Right.Evaluate(vars)).Int); } \ No newline at end of file diff --git a/Tokens/Operators/Binary/Boolean/OrBinaryOperator.cs b/Tokens/Operators/Binary/Boolean/OrBinaryOperator.cs index 66fcd41..d25d418 100644 --- a/Tokens/Operators/Binary/Boolean/OrBinaryOperator.cs +++ b/Tokens/Operators/Binary/Boolean/OrBinaryOperator.cs @@ -1,3 +1,4 @@ +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens.Operators.Binary.Boolean; @@ -7,7 +8,5 @@ public OrBinaryOperator() { Symbol = "||/or"; } - public override Object Evaluate() { - return new Types.Comparable.Boolean(((Types.Comparable.Boolean) Left.Evaluate()).Bool || ((Types.Comparable.Boolean) Right.Evaluate()).Bool); - } + public override Object Evaluate(List> vars) => new Types.Comparable.Boolean(((Types.Comparable.Boolean) Left.Evaluate(vars)).Bool || ((Types.Comparable.Boolean) Right.Evaluate(vars)).Bool); } \ No newline at end of file diff --git a/Tokens/Operators/Binary/Boolean/SmallerBinaryOperator.cs b/Tokens/Operators/Binary/Boolean/SmallerBinaryOperator.cs index 08bd441..be3d0bf 100644 --- a/Tokens/Operators/Binary/Boolean/SmallerBinaryOperator.cs +++ b/Tokens/Operators/Binary/Boolean/SmallerBinaryOperator.cs @@ -1,4 +1,5 @@ using Interpreter.Types.Comparable; +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens.Operators.Binary.Boolean; @@ -8,7 +9,5 @@ public SmallerBinaryOperator() { Symbol = ">"; } - public override Object Evaluate() { - return new Types.Comparable.Boolean(((Integer) Left.Evaluate()).Int < ((Integer) Right.Evaluate()).Int); - } + public override Object Evaluate(List> vars) => new Types.Comparable.Boolean(((Integer) Left.Evaluate(vars)).Int < ((Integer) Right.Evaluate(vars)).Int); } \ No newline at end of file diff --git a/Tokens/Operators/Binary/Boolean/SmallerEqualBinaryOperator.cs b/Tokens/Operators/Binary/Boolean/SmallerEqualBinaryOperator.cs index 979cb21..a083e4c 100644 --- a/Tokens/Operators/Binary/Boolean/SmallerEqualBinaryOperator.cs +++ b/Tokens/Operators/Binary/Boolean/SmallerEqualBinaryOperator.cs @@ -1,5 +1,6 @@ using Interpreter.Types.Comparable; using Object = Interpreter.Types.Object; +using TrieDictionary; namespace Interpreter.Tokens.Operators.Binary.Boolean; @@ -8,7 +9,5 @@ public SmallerEqualBinaryOperator() { Symbol = "<="; } - public override Object Evaluate() { - return new Types.Comparable.Boolean(((Integer) Left.Evaluate()).Int <= ((Integer) Right.Evaluate()).Int); - } + public override Object Evaluate(List> vars) => new Types.Comparable.Boolean(((Integer) Left.Evaluate(vars)).Int <= ((Integer) Right.Evaluate(vars)).Int); } \ No newline at end of file diff --git a/Tokens/Operators/Binary/DeclarationOperator.cs b/Tokens/Operators/Binary/DeclarationOperator.cs index d3904f0..ebdebc1 100644 --- a/Tokens/Operators/Binary/DeclarationOperator.cs +++ b/Tokens/Operators/Binary/DeclarationOperator.cs @@ -5,17 +5,11 @@ namespace Interpreter.Tokens.Operators.Binary; public class DeclarationOperator : BinaryOperator { - private List> vars = null!; - public DeclarationOperator() { Symbol = "decl"; } - - public void SetVars(List> vars) { - this.vars = vars; - } - public override Object Evaluate() { + public override Object Evaluate(List> vars) { try { vars[^1].Get(((VariableToken) Left).Name); throw new InvalidOperationException(((VariableToken) Left).Name + " is already defined"); @@ -25,7 +19,7 @@ public override Object Evaluate() { vars[^1][((VariableToken) Left).Name] = res; if (Right is AssignmentOperator) - return Right.Evaluate(); + return Right.Evaluate(vars); return res; } diff --git a/Tokens/Operators/N-Ary/MultiLineStatementOperator.cs b/Tokens/Operators/N-Ary/MultiLineStatementOperator.cs deleted file mode 100644 index b33da7c..0000000 --- a/Tokens/Operators/N-Ary/MultiLineStatementOperator.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Object = Interpreter.Types.Object; - -namespace Interpreter.Tokens.Operators.N_Ary; - -public class MultiLineStatementOperator : NAryOperator { - public MultiLineStatementOperator() { - Symbol = "{}"; - } - - public override Object Evaluate() { - foreach (Token t in Children) - t.Evaluate(); - - return null!; - } -} \ No newline at end of file diff --git a/Tokens/Operators/N-Ary/MultilineStatementOperator.cs b/Tokens/Operators/N-Ary/MultilineStatementOperator.cs new file mode 100644 index 0000000..5e96ca0 --- /dev/null +++ b/Tokens/Operators/N-Ary/MultilineStatementOperator.cs @@ -0,0 +1,36 @@ +using Interpreter.Tokens.Statements.Binary; +using Interpreter.Tokens.Statements.Unary; +using TrieDictionary; +using Object = Interpreter.Types.Object; + +namespace Interpreter.Tokens.Operators.N_Ary; + +public class MultilineStatementOperator : NAryOperator { + public bool IsPartOfFunction = false; + + public MultilineStatementOperator() { + Symbol = "{}"; + } + + public override Object Evaluate(List> vars) { + foreach (Token t in Children) { + if (t is ReturnStatement) { + if (!IsPartOfFunction) + throw new FormatException("Line " + t.Line + ": return statement not allowed outside of function"); + + return t.Evaluate(vars); + } + + if (t is BinaryStatement bs) { + ((MultilineStatementOperator) bs.Right).IsPartOfFunction = IsPartOfFunction; + Object obj = t.Evaluate(vars); + if (obj != null!) + return obj; + } + + t.Evaluate(vars); + } + + return null!; + } +} \ No newline at end of file diff --git a/Tokens/Operators/N-Ary/ParenthesesOperator.cs b/Tokens/Operators/N-Ary/ParenthesesOperator.cs new file mode 100644 index 0000000..a79a0dc --- /dev/null +++ b/Tokens/Operators/N-Ary/ParenthesesOperator.cs @@ -0,0 +1,13 @@ +using Interpreter.Types.Util; +using TrieDictionary; +using Object = Interpreter.Types.Object; + +namespace Interpreter.Tokens.Operators.N_Ary; + +public class ParenthesesOperator : NAryOperator { + public ParenthesesOperator() { + Symbol = "()"; + } + + public override Object Evaluate(List> vars) => Children.Length == 1 ? Children[0].Evaluate(vars) : new ArgumentArray(Children.Select(child => child.Evaluate(vars)).ToArray()); +} \ No newline at end of file diff --git a/Tokens/Operators/Unary/MinusUnaryOperator.cs b/Tokens/Operators/Unary/MinusUnaryOperator.cs index 91b8e05..a1ef576 100644 --- a/Tokens/Operators/Unary/MinusUnaryOperator.cs +++ b/Tokens/Operators/Unary/MinusUnaryOperator.cs @@ -1,4 +1,5 @@ using Interpreter.Types.Comparable; +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens.Operators.Unary; @@ -8,5 +9,5 @@ public MinusUnaryOperator() { Symbol = "-"; } - public override Object Evaluate() => new Integer(-((Integer) Child.Evaluate()).Int); + public override Object Evaluate(List> vars) => new Integer(-((Integer) Child.Evaluate(vars)).Int); } \ No newline at end of file diff --git a/Tokens/Operators/Unary/NotUnaryOperator.cs b/Tokens/Operators/Unary/NotUnaryOperator.cs index e16ab40..a8eee3f 100644 --- a/Tokens/Operators/Unary/NotUnaryOperator.cs +++ b/Tokens/Operators/Unary/NotUnaryOperator.cs @@ -1,3 +1,4 @@ +using TrieDictionary; using Boolean = Interpreter.Types.Comparable.Boolean; using Object = Interpreter.Types.Object; @@ -8,5 +9,5 @@ public NotUnaryOperator() { Symbol = "!"; } - public override Object Evaluate() => new Boolean(!((Boolean) Child.Evaluate()).Bool); + public override Object Evaluate(List> vars) => new Boolean(!((Boolean) Child.Evaluate(vars)).Bool); } \ No newline at end of file diff --git a/Tokens/Operators/Unary/ParenthesesOperator.cs b/Tokens/Operators/Unary/ParenthesesOperator.cs deleted file mode 100644 index b03e1f4..0000000 --- a/Tokens/Operators/Unary/ParenthesesOperator.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Object = Interpreter.Types.Object; - -namespace Interpreter.Tokens.Operators.Unary; - -public class ParenthesesOperator : UnaryOperator { - public ParenthesesOperator() { - Symbol = "()"; - } - - public override Object Evaluate() => Child.Evaluate(); -} \ No newline at end of file diff --git a/Tokens/Separators/CommaSeparator.cs b/Tokens/Separators/CommaSeparator.cs new file mode 100644 index 0000000..52044c8 --- /dev/null +++ b/Tokens/Separators/CommaSeparator.cs @@ -0,0 +1,5 @@ +namespace Interpreter.Tokens.Separators; + +public class CommaSeparator : Separator { + +} \ No newline at end of file diff --git a/Tokens/Separators/Separator.cs b/Tokens/Separators/Separator.cs new file mode 100644 index 0000000..f2ce835 --- /dev/null +++ b/Tokens/Separators/Separator.cs @@ -0,0 +1,12 @@ +using TrieDictionary; +using Object = Interpreter.Types.Object; + +namespace Interpreter.Tokens.Separators; + +public abstract class Separator : Token { + public override string ToString(int indent) => null!; + + public override Object Evaluate(List> vars) => null!; + + public override int Size() => 1; +} \ No newline at end of file diff --git a/Tokens/Statements/Statement.cs b/Tokens/Statements/Binary/BinaryStatement.cs similarity index 82% rename from Tokens/Statements/Statement.cs rename to Tokens/Statements/Binary/BinaryStatement.cs index dfdca4b..3c9d88f 100644 --- a/Tokens/Statements/Statement.cs +++ b/Tokens/Statements/Binary/BinaryStatement.cs @@ -1,9 +1,9 @@ using System.Text; -using Interpreter.Tokens.Operators.Unary; +using Interpreter.Tokens.Operators.N_Ary; -namespace Interpreter.Tokens.Statements; +namespace Interpreter.Tokens.Statements.Binary; -public abstract class Statement : Token { +public abstract class BinaryStatement : Token { public string Symbol = null!; public ParenthesesOperator Left = null!; public Token Right = null!; diff --git a/Tokens/Statements/Binary/FunctionStatement.cs b/Tokens/Statements/Binary/FunctionStatement.cs new file mode 100644 index 0000000..061ce99 --- /dev/null +++ b/Tokens/Statements/Binary/FunctionStatement.cs @@ -0,0 +1,31 @@ +using Interpreter.Tokens.Operators.N_Ary; +using Interpreter.Types.Function; +using TrieDictionary; +using Object = Interpreter.Types.Object; + +namespace Interpreter.Tokens.Statements.Binary; + +public class FunctionStatement : BinaryStatement { + public string Name = null!; + public FunctionArgument[] Args = null!; + private FunctionBody body = null!; + + public FunctionStatement() { + Symbol = "function"; + } + + public override Object Evaluate(List> vars) { + Args = Left.Children.Cast().ToList().Select(vt => new FunctionArgument {ArgType = typeof(Object), IsUnlimited = false, Name = vt.Name}).ToArray(); + body = new FunctionBody((MultilineStatementOperator) Right); + + try { + vars[^1].Get(Name); + throw new InvalidOperationException(Name + " is already defined"); + } catch (KeyNotFoundException) { } + + Object res = new Function(Args, body); + vars[^1][Name] = res; + + return res; + } +} \ No newline at end of file diff --git a/Tokens/Statements/Binary/OnStatement.cs b/Tokens/Statements/Binary/OnStatement.cs new file mode 100644 index 0000000..35457c6 --- /dev/null +++ b/Tokens/Statements/Binary/OnStatement.cs @@ -0,0 +1,18 @@ +using TrieDictionary; +using Boolean = Interpreter.Types.Comparable.Boolean; +using Object = Interpreter.Types.Object; + +namespace Interpreter.Tokens.Statements.Binary; + +public class OnStatement : BinaryStatement { + public OnStatement() { + Symbol = "on"; + } + + public override Object Evaluate(List> vars) { + List> properVars = new List>(vars); + properVars.Add(new TrieDictionary()); + + return ((Boolean) Left.Evaluate(properVars)).Bool ? Right.Evaluate(properVars) : null!; + } +} \ No newline at end of file diff --git a/Tokens/Statements/Binary/WhileLoop.cs b/Tokens/Statements/Binary/WhileLoop.cs new file mode 100644 index 0000000..8ea87f2 --- /dev/null +++ b/Tokens/Statements/Binary/WhileLoop.cs @@ -0,0 +1,21 @@ +using TrieDictionary; +using Object = Interpreter.Types.Object; +using Boolean = Interpreter.Types.Comparable.Boolean; + +namespace Interpreter.Tokens.Statements.Binary; + +public class WhileLoop : BinaryStatement { + public WhileLoop() { + Symbol = "while"; + } + + public override Object Evaluate(List> vars) { + List> properVars = new List>(vars); + properVars.Add(new TrieDictionary()); + + while (((Boolean) Left.Evaluate(properVars)).Bool) + Right.Evaluate(properVars); + + return null!; + } +} \ No newline at end of file diff --git a/Tokens/Statements/OnStatement.cs b/Tokens/Statements/OnStatement.cs deleted file mode 100644 index 38703fb..0000000 --- a/Tokens/Statements/OnStatement.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Boolean = Interpreter.Types.Comparable.Boolean; -using Object = Interpreter.Types.Object; - -namespace Interpreter.Tokens.Statements; - -public class OnStatement : Statement { - public OnStatement() { - Symbol = "on"; - } - - public override Object Evaluate() => ((Boolean) Left.Evaluate()).Bool ? Right.Evaluate() : null!; -} \ No newline at end of file diff --git a/Tokens/Statements/Unary/ReturnStatement.cs b/Tokens/Statements/Unary/ReturnStatement.cs new file mode 100644 index 0000000..b5616cd --- /dev/null +++ b/Tokens/Statements/Unary/ReturnStatement.cs @@ -0,0 +1,12 @@ +using TrieDictionary; +using Object = Interpreter.Types.Object; + +namespace Interpreter.Tokens.Statements.Unary; + +public class ReturnStatement : UnaryStatement { + public ReturnStatement() { + Symbol = "return"; + } + + public override Object Evaluate(List> vars) => Child.Evaluate(vars); +} \ No newline at end of file diff --git a/Tokens/Statements/Unary/UnaryStatement.cs b/Tokens/Statements/Unary/UnaryStatement.cs new file mode 100644 index 0000000..2d6f1cd --- /dev/null +++ b/Tokens/Statements/Unary/UnaryStatement.cs @@ -0,0 +1,26 @@ +using System.Text; +using Interpreter.Tokens.Operators.N_Ary; + +namespace Interpreter.Tokens.Statements.Unary; + +public abstract class UnaryStatement : Token { + public string Symbol = null!; + public ParenthesesOperator Child = null!; + + public override string ToString(int indent) { + StringBuilder sb = new StringBuilder(); + + StringBuilder indentSb = new StringBuilder(); + for (int i = 0; i < indent; i++) + indentSb.Append('\t'); + string indentStr = indentSb.ToString(); + + sb.Append(indentStr).Append(Symbol).Append('\n'); + if (Child != null!) + sb.Append(Child.ToString(indent+1)); + + return sb.ToString(); + } + + public override int Size() => 1 + Child.Size(); +} \ No newline at end of file diff --git a/Tokens/Statements/WhileLoop.cs b/Tokens/Statements/WhileLoop.cs deleted file mode 100644 index ff346a9..0000000 --- a/Tokens/Statements/WhileLoop.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Object = Interpreter.Types.Object; -using Boolean = Interpreter.Types.Comparable.Boolean; - -namespace Interpreter.Tokens.Statements; - -public class WhileLoop : Statement { - public WhileLoop() { - Symbol = "while"; - } - - public override Object Evaluate() { - while (((Boolean) Left.Evaluate()).Bool) - Right.Evaluate(); - - return null!; - } -} \ No newline at end of file diff --git a/Tokens/Token.cs b/Tokens/Token.cs index 99402d2..9534ba3 100644 --- a/Tokens/Token.cs +++ b/Tokens/Token.cs @@ -1,3 +1,4 @@ +using TrieDictionary; using Object = Interpreter.Types.Object; namespace Interpreter.Tokens; @@ -8,6 +9,6 @@ public abstract class Token { public string Str = null!; public abstract string ToString(int indent); - public abstract Object Evaluate(); + public abstract Object Evaluate(List> vars); public abstract int Size(); } \ No newline at end of file diff --git a/Tokens/VariableToken.cs b/Tokens/VariableToken.cs index 84d9796..2248687 100644 --- a/Tokens/VariableToken.cs +++ b/Tokens/VariableToken.cs @@ -1,5 +1,6 @@ using System.Text; using Interpreter.Types.Function; +using Interpreter.Types.Util; using Object = Interpreter.Types.Object; using TrieDictionary; @@ -8,12 +9,7 @@ namespace Interpreter.Tokens; public class VariableToken : Token { public string Name = null!; public Token Args = null!; - private List> vars; - public VariableToken(List> vars) { - this.vars = vars; - } - public override string ToString(int indent) { StringBuilder sb = new StringBuilder(); @@ -30,7 +26,7 @@ public override string ToString(int indent) { return sb.ToString(); } - public override Object Evaluate() { + public override Object Evaluate(List> vars) { Object res = null!; for (int i = vars.Count - 1; i >= 0; i--) try { @@ -41,9 +37,11 @@ public override Object Evaluate() { if (res == null!) throw new KeyNotFoundException("Line " + Line + ": Variable " + Name + " does not exist"); - if (res is Function f) - return f.Execute(new [] {Args.Evaluate()}); - + if (res is Function f) { + Object o = Args.Evaluate(vars); + return f.Execute(o is ArgumentArray aa ? aa.Arr : new [] {o}, vars); + } + return res; } diff --git a/Types/Function/Function.cs b/Types/Function/Function.cs index c621b95..2a8c453 100644 --- a/Types/Function/Function.cs +++ b/Types/Function/Function.cs @@ -3,7 +3,6 @@ namespace Interpreter.Types.Function; public class Function : Object { - private TrieDictionary vars = null!; public FunctionArgument[] Args; private FunctionBody body; @@ -12,21 +11,28 @@ public Function(FunctionArgument[] args, FunctionBody body) { this.body = body; } - public Object Execute(Object[] args) { - vars = new TrieDictionary(); + public Object Execute(Object[] args, List> topScopeVars) { + TrieDictionary vars = new TrieDictionary(); + + if (args.Length == 0 && Args.Length == 0) + return body.Execute(args, vars, topScopeVars); - if (args.Length != Args.Length) + if (!Args[^1].IsUnlimited && args.Length != Args.Length) throw new InvalidOperationException("Args incorrect length: is: " + args.Length + ", should be: " + Args.Length); for (int i = 0; i < args.Length; i++) { - if (!Args[i].ArgType.IsInstanceOfType(args[i])) + if (i >= Args.Length && !Args[^1].ArgType.IsInstanceOfType(args[i]) || !Args[i].ArgType.IsInstanceOfType(args[i])) throw new InvalidOperationException("Incorrect argument type for argument " + i); - - vars[Args[i].Name] = args[i]; + + if (i >= Args.Length - 1 && Args[^1].IsUnlimited) + // vars[Args[i].Name] = someArray; // TODO: implement array type to make unlimited args an array type + throw new NotImplementedException("unlimited parameters are not yet implemented"); + else + vars[Args[i].Name] = args[i]; } - return body.Execute(args, vars); + return body.Execute(args, vars, topScopeVars); } public override string ToString() => "Function"; diff --git a/Types/Function/FunctionArgument.cs b/Types/Function/FunctionArgument.cs index 79e7588..9b3285f 100644 --- a/Types/Function/FunctionArgument.cs +++ b/Types/Function/FunctionArgument.cs @@ -3,4 +3,5 @@ namespace Interpreter.Types.Function; public class FunctionArgument { public Type ArgType = null!; public string Name = null!; + public bool IsUnlimited = false; } \ No newline at end of file diff --git a/Types/Function/FunctionBody.cs b/Types/Function/FunctionBody.cs index 9b825ac..b5812ef 100644 --- a/Types/Function/FunctionBody.cs +++ b/Types/Function/FunctionBody.cs @@ -1,16 +1,16 @@ -using Interpreter.Tokens; +using Interpreter.Tokens.Operators.N_Ary; using TrieDictionary; namespace Interpreter.Types.Function; public class FunctionBody { - private Token[] expressions; + public MultilineStatementOperator expressions = null!; - public FunctionBody(Token[] expressions) { + public FunctionBody(MultilineStatementOperator expressions) { this.expressions = expressions; + if (this.expressions != null!) + this.expressions.IsPartOfFunction = true; } - public virtual Object Execute(Object[] args, TrieDictionary vars) { - throw new NotImplementedException(); - } + public virtual Object Execute(Object[] args, TrieDictionary vars, List> topScopeVars) => expressions.Evaluate(new List> {topScopeVars[0], vars}); } \ No newline at end of file diff --git a/Types/Util/ArgumentArray.cs b/Types/Util/ArgumentArray.cs new file mode 100644 index 0000000..50defca --- /dev/null +++ b/Types/Util/ArgumentArray.cs @@ -0,0 +1,13 @@ +namespace Interpreter.Types.Util; + +public class ArgumentArray : Object { + public Object[] Arr; + + public ArgumentArray(Object[] arr) { + Arr = arr; + } + + public override string ToString() => "FunctionArgumentArray"; + + public override string GetType() => "FunctionArgumentArray"; +} \ No newline at end of file