public void SetFunctionOwner(SkryptObject function, SkryptObject owner) { if (function.GetType() == typeof(UserFunction)) { ((UserFunction)function).Class = owner; } }
public SkryptObject ExecuteIndex(Node node, ScopeContext scopeContext) { List <SkryptObject> Arguments = new List <SkryptObject>(); foreach (Node subNode in node.SubNodes[1].SubNodes) { SkryptObject Result = ExecuteExpression(subNode, scopeContext); if (Result.Name == "void") { engine.throwError("Can't pass void into arguments!", node.SubNodes[0].Token); } Arguments.Add(Result); } SkryptObject Object = ExecuteExpression(node.SubNodes[0].SubNodes[0], scopeContext); dynamic Left = Convert.ChangeType(Object, Object.GetType()); Operation OpLeft = Left.GetOperation("index", Object.GetType(), Arguments[0].GetType(), Left.Operations); OperationDelegate Operation = null; if (OpLeft != null) { Operation = OpLeft.operation; } else { engine.throwError("No such operation as index " + Left.Name + "!", node.SubNodes[0].Token); } var inputArray = new List <SkryptObject>(Arguments); inputArray.Insert(0, Object); //SkryptProperty property = new SkryptProperty { // Value = Operation(inputArray.ToArray()) //}; return(Operation(inputArray.ToArray())); }
/// <summary> /// Evaluates a binary operation. /// </summary> public SkryptObject Eval(Operator operation, SkryptObject leftObject, SkryptObject rightObject, Node node = null) { dynamic left = Convert.ChangeType(leftObject, leftObject.GetType()); dynamic right = Convert.ChangeType(rightObject, rightObject.GetType()); Operation opLeft = SkryptObject.GetOperation( operation.Type, leftObject.GetType(), rightObject.GetType(), left.Operations ); Operation opRight = SkryptObject.GetOperation( operation.Type, leftObject.GetType(), rightObject.GetType(), right.Operations ); OperationDelegate operationDel = null; if (opLeft != null) { operationDel = opLeft.OperationDelegate; } if (opRight != null) { operationDel = opRight.OperationDelegate; } if (operationDel == null) { ThrowError("No such operation as " + left.Name + " " + operation.Operation + " " + right.Name, node.Token); } var result = (SkryptType)operationDel(new[] { leftObject, rightObject }, this); result.GetPropertiesFrom(Executor.GetType(result.TypeName, GlobalScope)); return(result); }
private static int IndexFromObject(SkryptObject Object) { var index = 0; if (Object.GetType() == typeof(String)) { index = ((String)Object).Value.GetHashCode(); } else { index = Convert.ToInt32((Numeric)Object); } return(index); }
public SkryptObject ExecuteExpression(Node node, ScopeContext scopeContext) { Operator op = Operator.AllOperators.Find(o => o.OperationName == node.Body || o.Operation == node.Body); if (op != null) { if (op.OperationName == "return") { if (!scopeContext.subContext.InMethod) { engine.throwError("Can't use return operator outside method!", node.SubNodes[0].Token); } SkryptObject result = null; if (node.SubNodes.Count == 1) { result = ExecuteExpression(node.SubNodes[0], scopeContext); } else { result = new Library.Native.System.Void(); } scopeContext.subContext.ReturnObject = result; return(result); } if (op.OperationName == "access") { SkryptObject Target = ExecuteExpression(node.SubNodes[1], scopeContext); SkryptObject Result = ExecuteAccess(Target, node.SubNodes[0], scopeContext).Value; return(Result); } if (op.OperationName == "assign") { SkryptObject result = ExecuteExpression(node.SubNodes[1], scopeContext); if (node.SubNodes[0].SubNodes.Count == 0 && node.SubNodes[0].TokenType == "Identifier") { Variable Variable = getVariable(node.SubNodes[0].Body, scopeContext); if (Variable != null) { Variable.Value = result; } else { scopeContext.Variables[node.SubNodes[0].Body] = new Variable { Name = node.SubNodes[0].Body, Value = result, Scope = scopeContext }; } } else if (node.SubNodes[0].Body == "access") { SkryptObject Target = ExecuteExpression(node.SubNodes[0].SubNodes[1], scopeContext); SkryptProperty AccessResult = ExecuteAccess(Target, node.SubNodes[0].SubNodes[0], scopeContext); AccessResult.Value = result; } else if (node.SubNodes[0].Body == "Index") { ExecuteIndexSet(result, node.SubNodes[0], scopeContext); } else { engine.throwError("Left hand side needs to be a variable or property!", node.SubNodes[0].Token); } return(result); } if (op.Members == 2) { SkryptObject LeftResult = ExecuteExpression(node.SubNodes[0], scopeContext); SkryptObject RightResult = ExecuteExpression(node.SubNodes[1], scopeContext); dynamic Left = Convert.ChangeType(LeftResult, LeftResult.GetType()); dynamic Right = Convert.ChangeType(RightResult, RightResult.GetType()); Operation OpLeft = Left.GetOperation(op.OperationName, LeftResult.GetType(), RightResult.GetType(), Left.Operations); Operation OpRight = Right.GetOperation(op.OperationName, LeftResult.GetType(), RightResult.GetType(), Right.Operations); OperationDelegate Operation = null; if (OpLeft != null) { Operation = OpLeft.operation; } else if (OpRight != null) { Operation = OpRight.operation; } else { engine.throwError("No such operation as " + Left.Name + " " + op.Operation + " " + Right.Name, node.SubNodes[0].Token); } return(Operation(new SkryptObject[] { LeftResult, RightResult })); } else if (op.Members == 1) { SkryptObject LeftResult = ExecuteExpression(node.SubNodes[0], scopeContext); dynamic Left = Convert.ChangeType(LeftResult, LeftResult.GetType()); Operation OpLeft = Left.GetOperation(op.OperationName, LeftResult.GetType(), null, Left.Operations); OperationDelegate Operation = null; if (OpLeft != null) { Operation = OpLeft.operation; } else { engine.throwError("No such operation as " + Left.Name + " " + op.Operation, node.SubNodes[0].Token); } return(Operation(new SkryptObject[] { LeftResult })); } } else if (node.TokenType == "ArrayLiteral") { Library.Native.System.Array array = new Library.Native.System.Array(); for (int i = 0; i < node.SubNodes.Count; i++) { Node subNode = node.SubNodes[i]; SkryptObject Result = ExecuteExpression(subNode, scopeContext); if (Result.Name == "void") { engine.throwError("Can't add void to array!", node.SubNodes[0].Token); } array.value["" + i] = Result; } return(array); } else if (node.SubNodes.Count == 0) { switch (node.TokenType) { case "NumericLiteral": return(new Library.Native.System.Numeric(Double.Parse(node.Body))); case "StringLiteral": return(new Library.Native.System.String(node.Body)); case "BooleanLiteral": return(new Library.Native.System.Boolean(node.Body == "true" ? true : false)); case "NullLiteral": return(new Library.Native.System.Null()); } } else if (node.TokenType == "FunctionLiteral") { UserMethod result = new UserMethod(); result.Name = "method"; result.Signature = node.Body; result.BlockNode = node.SubNodes[0]; result.CallName = node.Body.Split('_')[0]; foreach (Node snode in node.SubNodes[1].SubNodes) { result.Parameters.Add(snode.Body); } return(result); } if (node.TokenType == "Identifier") { if (engine.Constants.ContainsKey(node.Body)) { return(engine.Constants[node.Body]); } Variable foundVariable = getVariable(node.Body, scopeContext); if (foundVariable != null) { return(foundVariable.Value); } else { engine.throwError("Variable '" + node.Body + "' does not exist in the current context!", node.Token); } } if (node.TokenType == "Index") { return(ExecuteIndex(node, scopeContext)); } if (node.TokenType == "Call") { List <SkryptObject> Arguments = new List <SkryptObject>(); ScopeContext methodContext = new ScopeContext { ParentScope = scopeContext }; foreach (Node subNode in node.SubNodes[1].SubNodes) { SkryptObject Result = ExecuteExpression(subNode, scopeContext); if (Result.Name == "void") { engine.throwError("Can't pass void into arguments!", node.SubNodes[0].Token); } Arguments.Add(Result); } SkryptObject Method = ExecuteExpression(node.SubNodes[0].SubNodes[0], scopeContext); if (Method.GetType() != typeof(SharpMethod)) { var Find = Method.Properties.Find((x) => x.Name == "Constructor"); if (Find != null) { Method = Find.Value; } } if (Method.GetType() == typeof(UserMethod)) { UserMethod method = (UserMethod)Method; for (int i = 0; i < method.Parameters.Count; i++) { string parName = method.Parameters[i]; SkryptObject input; if (i < Arguments.Count) { input = Arguments[i]; } else { input = new Library.Native.System.Null(); } methodContext.Variables[parName] = new Variable { Name = parName, Value = input, Scope = methodContext }; } SkryptObject MethodResult = method.Execute(engine, Arguments.ToArray(), methodContext); return(MethodResult); } else if (Method.GetType() == typeof(SharpMethod)) { SkryptObject MethodResult = ((SharpMethod)Method).Execute(engine, Arguments.ToArray(), methodContext); return(MethodResult); } else { engine.throwError("Cannot call value, as it is not a function!", node.SubNodes[0].SubNodes[0].Token); } } return(null); }
/// <summary> /// Executes an expression. /// </summary> public SkryptObject ExecuteExpression(Node node, ScopeContext scopeContext) { _engine.CurrentNode = node; var op = Operator.AllOperators.Find(o => o.OperationName == node.Body); if (op != null) { // Do return operation. if (op.OperationName == "return") { if ((scopeContext.Properties & ScopeProperties.InMethod) == 0) { _engine.ThrowError("Can't use return operator outside method", node.Token); } // Return null if no value was given. SkryptObject result = node.Nodes.Count == 1 ? ExecuteExpression(node.Nodes[0], scopeContext) : new Library.Native.System.Null(); scopeContext.ReturnObject = result; return(null); } // Do break operation. if (op.OperationName == "break") { if ((scopeContext.Properties & ScopeProperties.InLoop) == 0) { _engine.ThrowError("Can't use break operator outside loop", node.Token); } scopeContext.Properties |= ScopeProperties.BrokeLoop; return(null); } // Do continue operation. if (op.OperationName == "continue") { if ((scopeContext.Properties & ScopeProperties.InLoop) == 0) { _engine.ThrowError("Can't use continue operator outside loop", node.Token); } scopeContext.Properties |= ScopeProperties.SkippedLoop; return(null); } // Do access operation. if (op.OperationName == "access") { var target = ExecuteExpression(node.Nodes[0], scopeContext); var result = ExecuteAccess(target, node.Nodes[1], scopeContext); scopeContext.Caller = result.Owner; // Execute result as method if its a getter property. if (result.Property.Value.GetType() == typeof(GetMethod)) { var ex = ((GetMethod)result.Property.Value).Execute(_engine, result.Owner, new SkryptObject[0], new ScopeContext { ParentScope = scopeContext }); return(ex.ReturnObject); } else { return(result.Property.Value); } } // Do assignment operation. if (op.OperationName == "assign") { // Solve right side. var result = ExecuteExpression(node.Nodes[1], scopeContext); // Copy value of results like numbers, string etc, so variables that // are assigned to eachother don't edit eachothers values. if (typeof(SkryptType).IsAssignableFrom(result.GetType())) { if (((SkryptType)result).CreateCopyOnAssignment) { result = result.Clone(); } } // Left side is an identifier. if (node.Nodes[0].Nodes.Count == 0 && node.Nodes[0].Type == TokenTypes.Identifier) { if (GeneralParser.Keywords.Contains(node.Nodes[0].Body)) { _engine.ThrowError("Setting variable names to keywords is disallowed"); } var variable = GetVariable(node.Nodes[0].Body, scopeContext); if (variable != null && !scopeContext.StrictlyLocal) { if ((variable.Modifiers & Modifier.Const) != 0) { _engine.ThrowError("Variable is marked as constant and can thus not be modified.", node.Nodes[0].Token); } if ((variable.Modifiers & Modifier.Strong) != 0) { if (variable.Value.Name != result.Name) { _engine.ThrowError($"Can't set strong variable of type {variable.Value.Name} to {result.Name}", node.Nodes[0].Token); } } variable.Value = result; } else { scopeContext.SetVariable(node.Nodes[0].Body, result, node.Modifiers); } } // Left side is an expression. else if (node.Nodes[0].Body == "access") { var target = ExecuteExpression(node.Nodes[0].Nodes[0], scopeContext); var accessResult = ExecuteAccess(target, node.Nodes[0].Nodes[1], scopeContext, true); if ((accessResult.Property.Modifiers & Modifier.Const) != 0) { _engine.ThrowError("Property is marked as constant and can thus not be modified.", node.Nodes[0].Nodes[1].Token); } if ((accessResult.Property.Modifiers & Modifier.Strong) != 0) { if (accessResult.Property.Value.Name != result.Name) { _engine.ThrowError($"Can't set strong property of type {accessResult.Property.Value.Name} to {result.Name}", node.Nodes[0].Nodes[1].Token); } } if (accessResult.Property.IsSetter) { ((SetMethod)accessResult.Property.Value).Execute(_engine, target, result, new ScopeContext { ParentScope = scopeContext }); } else { accessResult.Property.Value = result; } //SetFunctionOwner(result, target); } // Left side is an expression. else if (node.Nodes[0].Body == "Index") { ExecuteIndexSet(result, (IndexNode)node.Nodes[0], scopeContext); } else { _engine.ThrowError("Left hand side needs to be a variable or property!", node.Nodes[0].Token); } return(result); } // Evaluate node as binary expression. if (op.Members == 2) { var leftResult = ExecuteExpression(node.Nodes[0], scopeContext); var rightResult = ExecuteExpression(node.Nodes[1], scopeContext); return(_engine.Eval(op, leftResult, rightResult, node)); } // Evaluate node as unary expression. if (op.Members == 1) { var leftResult = ExecuteExpression(node.Nodes[0], scopeContext); return(_engine.Eval(op, leftResult, node));; } } // Create array literal instance. else if (node.Type == TokenTypes.ArrayLiteral) { var arrayNode = (ArrayNode)node; var array = _engine.Create <Library.Native.System.Array>(); // Solve all expressions within the array and add the resulting values. for (var i = 0; i < arrayNode.Values.Count; i++) { var subNode = arrayNode.Values[i]; var result = ExecuteExpression(subNode, scopeContext); array.List.Add(result); } return(array); } // Create function literal instance. else if (node.Type == TokenTypes.FunctionLiteral) { var result = new UserFunction { Name = "method", Signature = node.Body, BlockNode = node.Nodes[0], CallName = node.Body.Split('_')[0], Path = _engine.CurrentExecutingFile }; foreach (var snode in node.Nodes[1].Nodes) { result.Parameters.Add(snode.Body); } return(result); } else if (node.Type == TokenTypes.Conditional) { var conditionNode = (ConditionalNode)node; var conditionBool = ExecuteExpression(conditionNode.Condition, scopeContext); if (conditionBool.ToBoolean()) { return(ExecuteExpression(conditionNode.Pass, scopeContext)); } else { return(ExecuteExpression(conditionNode.Fail, scopeContext)); } } else { switch (node.Type) { case TokenTypes.NumericLiteral: return(_engine.Create <Library.Native.System.Numeric>(((NumericNode)node).Value)); case TokenTypes.StringLiteral: return(_engine.Create <Library.Native.System.String>(((StringNode)node).Value)); case TokenTypes.BooleanLiteral: return(_engine.Create <Library.Native.System.Boolean>(((BooleanNode)node).Value)); case TokenTypes.NullLiteral: return(_engine.Create <Library.Native.System.Null>()); } } // Get variable if (node.Type == TokenTypes.Identifier) { var foundVariable = GetVariable(node.Body, scopeContext); if (foundVariable != null) { return(foundVariable.Value); } _engine.ThrowError("Variable '" + node.Body + "' does not exist in the current context!", node.Token); } // Do index operation if (node.Type == TokenTypes.Index) { return(ExecuteIndex((IndexNode)node, scopeContext)); } // Do function call operation. if (node.Type == TokenTypes.Call) { var callNode = (CallNode)node; var arguments = new List <SkryptObject>(); // Solve argument expressions. foreach (var subNode in callNode.Arguments) { var result = ExecuteExpression(subNode, scopeContext); arguments.Add(result); } // Get the value that's being called. var foundFunction = ExecuteExpression(callNode.Getter, scopeContext); var caller = scopeContext.Caller; SkryptObject BaseType = null; bool isConstructor = false; bool validConstructor = true; // Check if we're creating a new instance of a type. if (!typeof(SkryptMethod).IsAssignableFrom(foundFunction.GetType())) { var find = foundFunction.GetProperty("Constructor"); var typeName = foundFunction.GetProperty("TypeName").ToString(); validConstructor = foundFunction.GetType() == typeof(SkryptObject); foundFunction = find ?? new SkryptMethod { Name = "Constructor" }; BaseType = GetType(typeName, scopeContext); // Create new instance of type and set that as the caller. caller = (SkryptType)Activator.CreateInstance(BaseType.GetType()); caller.ScopeContext = _engine.CurrentScope; caller.Engine = _engine; caller.Name = typeName; caller.GetPropertiesFrom(BaseType); isConstructor = true; } // Create new scope to use within the function. var methodContext = new ScopeContext { ParentScope = scopeContext, // Create new call stack for method. CallStack = new CallStack(((SkryptMethod)foundFunction).Name, callNode.Getter.Token, scopeContext.CallStack, ""), Properties = scopeContext.Properties | ScopeProperties.InMethod }; _engine.CurrentStack = methodContext.CallStack; ScopeContext methodScopeResult = null; // Function is defined in Skrypt. if (foundFunction.GetType() == typeof(UserFunction)) { UserFunction function = (UserFunction)foundFunction; // Create variables for each parameter based on the given arguments. for (var i = 0; i < function.Parameters.Count; i++) { var parName = function.Parameters[i]; SkryptObject input; // Set to null if there's no argument. input = i < arguments.Count ? arguments[i] : new Library.Native.System.Null(); methodContext.Variables[parName] = new Variable { Name = parName, Value = input, Scope = methodContext }; } methodContext.CallStack.Path = _engine.CurrentExecutingFile; _engine.CurrentExecutingFile = function.Path; methodScopeResult = function.Execute(_engine, caller, arguments.ToArray(), methodContext); } // Function is defined in C#. else if (foundFunction.GetType() == typeof(SharpMethod)) { methodScopeResult = ((SharpMethod)foundFunction).Execute(_engine, caller, arguments.ToArray(), methodContext); } else if (!validConstructor) { _engine.ThrowError("Cannot call value, as it is not a function!", callNode.Getter.Token); } if (isConstructor) { caller.ScopeContext = _engine.CurrentScope; caller.Engine = _engine; return(caller); } else { return(methodScopeResult.ReturnObject); } } return(null); }