Ejemplo n.º 1
0
        /// <summary>
        /// Iterates through the list of conditions and performs each one in turn.  Checks the top element of the stack to see
        /// if a true value has been pushed on.  If it has it performs the corresponding compiled statement in that KVP.
        /// </summary>
        public override void PerformOperation()
        {
            base.PerformOperation();

            CelesteStack.CurrentScope = FlowScope;

            Debug.Assert(ConditionsAndBodies.Count > 0, "No conditions or functions specified for flow control");
            foreach (KeyValuePair <CompiledStatement, CompiledStatement> condBody in ConditionsAndBodies)
            {
                condBody.Key.PerformOperation();

                Debug.Assert(CelesteStack.StackSize > 0, "No true or false value pushed onto stack");
                CelesteObject celObject = CelesteStack.Pop();

                if (celObject.IsBool())
                {
                    if (celObject.As <bool>())
                    {
                        condBody.Value.PerformOperation();
                        break;
                    }
                }
                else
                {
                    Debug.Fail("Condition must be evaluatable to a bool value");
                }
            }

            CelesteStack.Scopes.Remove(FlowScope);
            CelesteStack.CurrentScope = FlowScope.ParentScope;
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Assigns the expression on the right to the local variable on the left
        /// </summary>
        public override void PerformOperation()
        {
            base.PerformOperation();

            // If we have fewer than 2 objects on the stack we cannot perform this operator
            Debug.Assert(CelesteStack.StackSize >= 2, "Not enough elements on the stack for equality operator");

            Scope scope = CelesteStack.CurrentScope;

            CelesteObject rhs = CelesteStack.Pop();
            CelesteObject lhs = CelesteStack.Pop();

            Debug.Assert(lhs.IsReference());
            // All functions are references so check this condition first
            if (rhs.IsFunction())
            {
                Debug.Assert(lhs.IsFunction(), "A function can only be assigned to another function");
                Function lhsFunc = lhs.AsFunction();
                Function rhsFunc = rhs.AsFunction();

                Debug.Assert(CelesteStack.CurrentScope != lhsFunc.FunctionScope, "Cannot reassign functions inside their own scope");
                lhsFunc.FunctionScope  = rhsFunc.FunctionScope;
                lhsFunc.ParameterNames = rhsFunc.ParameterNames;
                lhsFunc.Ref            = rhsFunc.Ref; // This is equivalent to setting their implementation to be the same
            }
            else if (rhs.IsReference())
            {
                lhs.Value = rhs.Value;
            }
            else
            {
                lhs.AsReference().Value = rhs.Value;
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Removes the two objects at the top of the stack and divides them together.
        /// Then, pushes the result on to the top of the stack.
        /// </summary>
        public override void PerformOperation()
        {
            base.PerformOperation();

            // If we have fewer than 2 objects on the stack we cannot do this
            Debug.Assert(CelesteStack.StackSize >= 2, "Not enough elements on the stack for divide operator");

            CelesteObject rhs = CelesteStack.Pop();
            CelesteObject lhs = CelesteStack.Pop();

            // The stack will wrap our division result in a CelesteObject, so just push the actual value of the division
            if (lhs.IsNumber() && rhs.IsNumber())
            {
                float rhsAsFloat = rhs.As <float>();
                if (rhsAsFloat != 0)
                {
                    CelesteStack.Push(lhs.As <float>() / rhsAsFloat);
                }
                else
                {
                    Debug.Fail("Division by zero");
                }
            }
            else
            {
                Debug.Fail("Invalid parameters to add operation.");
            }
        }
Ejemplo n.º 4
0
        public override void PerformOperation()
        {
            // Set up our parameters if required
            if (ParameterNames.Count > 0)
            {
                Debug.Assert(ChildCount > 0, "Fatal error in function call - no arguments to process");
                CompiledStatement thisCallsParams = ChildCompiledStatements[0];
                ChildCompiledStatements.RemoveAt(0);

                // This will run through each stored parameter and add them to the stack
                thisCallsParams.PerformOperation();
            }

            // Set up our parameters - read them off the stack with the first parameter at the top
            for (int i = 0; i < ParameterNames.Count; i++)
            {
                Debug.Assert(CelesteStack.StackSize > 0, "Insufficient parameters to function");
                CelesteObject input = CelesteStack.Pop();

                Variable functionParameter = FunctionScope.GetLocalVariable(ParameterNames[i], ScopeSearchOption.kThisScope);

                if (input.IsReference())
                {
                    functionParameter.Value = input.ValueImpl;
                }
                else
                {
                    (functionParameter.Value as Reference).Value = input.Value;
                }
            }

            CelesteStack.CurrentScope = FunctionScope;

            // Performs all the operators on the children first
            foreach (CompiledStatement statement in FuncImpl.ChildCompiledStatements)
            {
                statement.PerformOperation();
                if (statement is ReturnKeyword)
                {
                    // Stop iterating through if we have hit a ReturnKeyword in our function
                    break;
                }
            }

            CelesteStack.Scopes.Remove(FunctionScope);
            CelesteStack.CurrentScope = FunctionScope.ParentScope;
        }
        /// <summary>
        /// Removes the two objects at the top of the stack and performs logical operations them.
        /// Then, pushes the result of the operation on to the top of the stack.
        /// </summary>
        public sealed override void PerformOperation()
        {
            base.PerformOperation();

            // If we have fewer than 2 objects on the stack we cannot perform this operation
            Debug.Assert(CelesteStack.StackSize >= 2, "Not enough elements on the stack for the equality operator");

            CelesteObject rhs = CelesteStack.Pop();
            CelesteObject lhs = CelesteStack.Pop();

            // The stack will wrap our result in a CelesteObject, so just push the actual result of the operation
            bool      result = false;
            Reference lhsRef = lhs.AsReference();
            Reference rhsRef = rhs.AsReference();

            // Check to see whether our lhs is a reference
            if (lhsRef != null)
            {
                if (rhsRef != null)
                {
                    // If the rhs is a reference too, we compare references
                    result = ReferenceReferenceOperation(lhsRef, rhsRef);
                }
                else
                {
                    // Otherwise we compare the value of the rhs with the value of the lhs' referenced object
                    result = ReferenceValueOperation(lhsRef, rhs.Value);
                }
            }
            else
            {
                if (rhsRef != null)
                {
                    // If the rhs is a reference, we compare the value of the rhs' referenced object with the value of the lhs
                    result = ReferenceValueOperation(rhsRef, lhs.Value);
                }
                else
                {
                    // Otherwise we compare the value of the rhs with the value of the lhs - they are both values
                    result = ValueValueOperation(lhs.Value, rhs.Value);
                }
            }

            // We then finally push the result of the equality test onto the stack
            CelesteStack.Push(result);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Removes the two objects at the top of the stack and multiplies them together.
        /// Then, pushes the result on to the top of the stack.
        /// </summary>
        public override void PerformOperation()
        {
            base.PerformOperation();

            // If we have fewer than 2 objects on the stack we are el-bonerino-ed
            Debug.Assert(CelesteStack.StackSize >= 2, "Not enough elements on the stack for multiply operator");

            CelesteObject rhs = CelesteStack.Pop();
            CelesteObject lhs = CelesteStack.Pop();

            // The stack will wrap our multiplication result in a CelesteObject, so just push the actual value of the multiplication
            if (lhs.IsNumber() && rhs.IsNumber())
            {
                CelesteStack.Push(lhs.As <float>() * rhs.As <float>());
            }
            else
            {
                Debug.Fail("Invalid parameters to add operation.");
            }
        }
Ejemplo n.º 7
0
        // When we compile we need to check which end the increment is on and then check for a variable name accordingly

        /// <summary>
        /// Pops the first element on the top of the stack and checks to see if it is a reference to a number.
        /// If it is, it increments the number and then pushes the object back onto the stack.
        /// </summary>
        public override void PerformOperation()
        {
            base.PerformOperation();

            Debug.Assert(CelesteStack.StackSize > 0, "Must be an object on the stack for the increment operator");

            CelesteObject rhs = CelesteStack.Pop();

            if (rhs.IsNumber())
            {
                float newFloat = rhs.As <float>();
                newFloat++;
                rhs.Value = newFloat;
            }
            else
            {
                Debug.Fail("Increment operator can only be applied to a variable with a numerical value");
            }

            CelesteStack.Push(rhs);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Removes the two objects at the top of the stack and subtracts the top most object on the stack from the other.
        /// Then, pushes the result on to the top of the stack.
        /// </summary>
        public override void PerformOperation()
        {
            base.PerformOperation();

            // If we have fewer than 2 objects on the stack we are el-bonerino-ed
            Debug.Assert(CelesteStack.StackSize >= 2, "Not enough elements on the stack for subtract operator");

            CelesteObject rhs = CelesteStack.Pop();
            CelesteObject lhs = CelesteStack.Pop();

            // The stack will wrap our subtraction result in a CelesteObject, so just push the actual value of the subtraction
            if (lhs.IsNumber() && rhs.IsNumber())
            {
                CelesteStack.Push(lhs.As <float>() - rhs.As <float>());
            }
            else if (lhs.IsString() && rhs.IsString())
            {
                string lhsAsString = lhs.As <string>();
                string rhsAsString = rhs.As <string>();

                if (lhsAsString.Contains(rhsAsString))
                {
                    // Push the lhs string having removed the rhs string
                    CelesteStack.Push(lhsAsString.Remove(lhsAsString.IndexOf(rhsAsString), rhsAsString.Length));
                }
                else
                {
                    // If our lhs does not contain our rhs, we just push the original unaltered lhs string
                    CelesteStack.Push(lhsAsString);
                }
            }
            else if (lhs.IsList() && rhs.IsList())
            {
                // The subtract operator for lists removes all elements in the first list who are equal to an element in the second, either by reference or value
                List <object> lhsList = lhs.AsList <object>();
                List <object> rhsList = rhs.AsList <object>();

                // Remove ALL occurrences in the list of any object in the rhs list - otherwise there is non-deterministic behaviour in which instance to remove
                lhsList.RemoveAll(x => rhsList.Exists(y => y.Equals(x) || y.ValueEquals(x)));
                CelesteStack.Push(lhs);
            }
            else if (lhs.IsTable() && rhs.IsList())
            {
                // Subtraction of tables does not make sense
                // What does make sense, is subtracting elements in a table using a list of keys
                // Subtracting a list from a table will remove any elements in the table with a matching key as an element in our list

                Dictionary <object, object> lhsTable = lhs.AsTable();
                List <object> rhsList = rhs.AsList <object>();

                foreach (object obj in rhsList)
                {
                    if (lhsTable.Contains(new KeyValuePair <object, object>(obj, null), new TableKeyComparer()))
                    {
                        lhsTable.Remove(lhsTable.First(x => x.Key.Equals(obj) || x.Key.ValueEquals(obj)));
                    }
                }

                CelesteStack.Push(lhs);
            }
            else
            {
                Debug.Fail("Invalid parameters to subtract operation.");
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Removes the two objects at the top of the stack and adds them together.
        /// Then, pushes the result on to the top of the stack.
        /// </summary>
        public override void PerformOperation()
        {
            base.PerformOperation();

            // If we have fewer than 2 objects on the stack we are el-bonerino-ed
            Debug.Assert(CelesteStack.StackSize >= 2, "Not enough elements on the stack for add operator");

            CelesteObject rhs = CelesteStack.Pop();
            CelesteObject lhs = CelesteStack.Pop();

            // The stack will wrap our addition result in a CelesteObject, so just push the actual value of the addition
            if (lhs.IsNumber() && rhs.IsNumber())
            {
                CelesteStack.Push(lhs.As <float>() + rhs.As <float>());
            }
            else if (lhs.IsString() && rhs.IsString())
            {
                CelesteStack.Push(lhs.As <string>() + rhs.As <string>());
            }
            else if (lhs.IsList() && rhs.IsList())
            {
                lhs.AsList <object>().AddRange(rhs.AsList <object>());
                CelesteStack.Push(lhs);
            }
            else if (lhs.IsTable() && rhs.IsTable())
            {
                Dictionary <object, object> lhsTable = lhs.AsTable();
                Dictionary <object, object> rhsTable = rhs.AsTable();

                // Tables can be added, but only if they are all indexed by number or string completely
                // No other way can be used because the reference type of 'object' makes value equality difficult
                // These two types of adding are the only two we can realistically support

                // Check whether our lhs table has all number keys
                if (lhsTable.Keys.Count(x => x is float) == lhsTable.Keys.Count)
                {
                    // If it does, check the rhs table too
                    if (rhsTable.Keys.Count(x => x is float) == rhsTable.Keys.Count)
                    {
                        // We now go through and see if any keys overlap in the two tables
                        if (lhsTable.Intersect(rhsTable, new TableKeyComparer()).Count() == 0)
                        {
                            foreach (KeyValuePair <object, object> pair in rhsTable)
                            {
                                lhsTable.Add((float)pair.Key, pair.Value);
                            }
                        }
                        else
                        {
                            Debug.Fail("Invalid parameters to add operation.  Right hand side table has at least one key the same as the left hand side table");
                        }
                    }
                    else
                    {
                        Debug.Fail("Invalid parameters to add operation.  Right hand side table has inconsistent key types (should be numbers)");
                    }
                }
                // Check whether our lhs table has all string keys
                else if (lhsTable.Keys.Count(x => x is string) == lhsTable.Keys.Count)
                {
                    // If it does, check the rhs table too
                    if (rhsTable.Keys.Count(x => x is string) == rhsTable.Keys.Count)
                    {
                        // We now go through and see if any keys overlap in the two tables
                        if (lhsTable.Intersect(rhsTable, new TableKeyComparer()).Count() == 0)
                        {
                            foreach (KeyValuePair <object, object> pair in rhsTable)
                            {
                                lhsTable.Add((string)pair.Key, pair.Value);
                            }
                        }
                        else
                        {
                            Debug.Fail("Invalid parameters to add operation.  Right hand side table has at least one key the same as the left hand side table");
                        }
                    }
                    else
                    {
                        Debug.Fail("Invalid parameters to add operation.  Right hand side table has inconsistent key types (should be strings)");
                    }
                }
                else
                {
                    Debug.Fail("Invalid parameters to add operation.  Left hand side table has inconsistent key types (should be numbers or strings)");
                }

                CelesteStack.Push(lhs);
            }
            else
            {
                Debug.Fail("Invalid parameters to add operation.");
            }
        }