Beispiel #1
0
 public void SetFunctionOwner(SkryptObject function, SkryptObject owner)
 {
     if (function.GetType() == typeof(UserFunction))
     {
         ((UserFunction)function).Class = owner;
     }
 }
Beispiel #2
0
        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()));
        }
Beispiel #3
0
        /// <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);
        }
Beispiel #4
0
            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);
            }
Beispiel #5
0
        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);
        }
Beispiel #6
0
        /// <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);
        }