示例#1
0
 /// <summary>
 /// Compiles an individual token
 /// </summary>
 /// <param name="token"></param>
 public static bool CompileToken(string token, CompiledStatement parent)
 {
     if (CompileAsValue(parent, token))
     {
         return(true);
     }
     else if (CompileAsVariable(parent, token))
     {
         return(true);
     }
     else if (CompileAsFlowControl(parent, token))
     {
         return(true);
     }
     else if (CompileAsKeyword(parent, token))
     {
         return(true);
     }
     else if (CompileAsOperator(parent, token))
     {
         return(true);
     }
     else
     {
         Debug.Fail("Unrecognised token " + token);
         return(false);
     }
 }
示例#2
0
        /// <summary>
        /// Create an instance of the inputted compiled statement
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="type"></param>
        private static void Create <T>(CompiledStatement parent, string token, Type type) where T : CompiledStatement
        {
            // Create an instance of our keyword
            T statement = (T)Activator.CreateInstance(type);

            statement.Compile(parent, token, Tokens, Lines);
        }
示例#3
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            Delimiter.InlineToken = scriptToken;

            // Now check that there is another element after our keyword that we can use as the variable name
            Debug.Assert(tokens.Count > 0, "No value found for the right hand side of keyword: " + token);

            if (tokens.First.Value == FunctionKeyword.scriptToken)
            {
                // If we have a function after this, we do nothing - functions by default are added to the current local scope
                Delimiter.InlineToken = "";
                return;
            }

            // Get the next token that appears on the right hand side of this operator - this will be our variable name
            string rhsOfKeyword = CelesteCompiler.PopToken();

            Debug.Assert(!CelesteStack.CurrentScope.VariableExists(rhsOfKeyword), "Variable with the same name already exists in this scope");

            // Creates a new variable, but does not call Compile - Compile for variable assigns a reference from the stored variable in CelesteStack
            Variable variable = CelesteStack.CurrentScope.CreateLocalVariable <Variable>(rhsOfKeyword);

            // If we still have unparsed tokens, then add this variable to the tree
            // Otherwise, do not - we do not need to push an object onto the stack for no reason
            if (tokens.Count > 0)
            {
                // Add our variable underneath our parent - this keyword will do nothing at run time so do not add it to the tree
                parent.Add(variable);
            }
        }
示例#4
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            // Find the first occurrence of the delimiter and split the string at that index
            int delimiterIndex = token.IndexOf(scriptTokenChar);

            Debug.Assert(delimiterIndex > 0);   // Must exist and cannot be the first element in a string

            // Split the token into two strings - the lhs of the first delimiter and the remaining rhs after the delimiter
            string lhsOfDelimiter = token.Substring(0, delimiterIndex);
            string rhsOfDelimiter = token.Substring(delimiterIndex + 1);

            // We add these in the reverse order so that they appear as LHS, INLINE, RHS (the tokens list is basically a stack)

            if (!string.IsNullOrEmpty(rhsOfDelimiter))
            {
                // Add anything leftover on the rhs
                tokens.AddFirst(rhsOfDelimiter);
            }

            if (!string.IsNullOrEmpty(InlineToken))
            {
                // Add our inlined token if it is not empty
                // If it is empty, then it was merely acting as a separator
                tokens.AddFirst(InlineToken);
            }

            // Add the lhs of delimiter - this cannot be empty
            Debug.Assert(!string.IsNullOrEmpty(lhsOfDelimiter));
            tokens.AddFirst(lhsOfDelimiter);
        }
示例#5
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            Debug.Assert(parent.ChildCount > 0, "No value found for the left hand side of operator: " + token);

            // Take the previous statement and add it as a sub statement of the newly created operator - we will check for validity in the Compile function
            parent.MoveChildAtIndex(parent.ChildCount - 1, this);

            // Add this operator to the tree
            parent.Add(this);

            // Now check that there is another element after our operator that we can act on
            Debug.Assert(tokens.Count > 0, "No value found for the right hand side of operator: " + token);

            // Get the next token that appears on the right hand side of this operator
            string rhsOfOperatorToken = CelesteCompiler.PopToken();

            // Parse the next token which we will act on
            if (CelesteCompiler.CompileToken(rhsOfOperatorToken, parent))
            {
                // Take the value that has been added to the root and add it under this operator instead
                parent.MoveChildAtIndex(parent.ChildCount - 1, this);
            }
            else
            {
                // Error message if we cannot parse the next token
                Debug.Fail("Could not compile token: " + token + " in operator " + token);
            }
        }
示例#6
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            // We know the token will at least start with the start delimiter
            if (token.Length > 1)
            {
                // In here if the start delimiter and another token are smushed together with no space
                // Split the start delimiter and the rest of the token and add the rest of the token to the start of our tokens list
                string rest = token.Remove(0, 1);
                tokens.AddFirst(rest);
            }

            // We keep parsing until we find a closing character for our list
            bool foundClosing = false;

            while (!foundClosing)
            {
                Debug.Assert(tokens.Count > 0 || lines.Count > 0, "List requires a closing " + endDelimiter);

                // Create a new set of tokens if we have run out for this line
                if (tokens.Count == 0)
                {
                    CelesteCompiler.TokenizeNextLine();
                }

                string nextToken = CelesteCompiler.PopToken();
                if (nextToken.EndsWith(endDelimiter) && nextToken.Length > 1)
                {
                    // Our token has the end delimiter squashed at the end of it, so we split the token in two and add the delimiter to the tokens list
                    // This will mean we still compile this token and finish our list the next iteration round
                    nextToken = nextToken.Remove(nextToken.Length - 1);
                    tokens.AddFirst(endDelimiter);
                }

                if (nextToken == endDelimiter)
                {
                    foundClosing = true;
                }
                else if (CelesteCompiler.CompileToken(nextToken, parent))
                {
                    // Take the value that has been created from compiling this token and add it to our list
                    // Then remove the compiled statement - we do not want objects in our list pushed onto the stack
                    CompiledStatement valueCreated = parent.ChildCompiledStatements[parent.ChildCount - 1];
                    parent.RemoveAt(parent.ChildCount - 1);

                    // The value we created MUST be a value
                    Debug.Assert(valueCreated is Value);
                    ListRef.Add((valueCreated as Value)._Value);
                }
                else
                {
                    // Error message if we cannot parse the next token
                    Debug.Fail("Error parsing token: " + token + " in list");
                }
            }
        }
示例#7
0
        /// <summary>
        /// Removes a child from this compile statement's children and returns it for adding somewhere else
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public CompiledStatement RemoveAt(int index)
        {
            Debug.Assert(ChildCompiledStatements.Count > index);
            CompiledStatement child = ChildCompiledStatements[index];

            ChildCompiledStatements.RemoveAt(index);

            return(child);
        }
示例#8
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            bool result;

            bool.TryParse(token, out result);
            _Value = result;
        }
示例#9
0
        /// <summary>
        /// Division should take precedence over Assignment
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="token"></param>
        /// <param name="tokens"></param>
        /// <param name="lines"></param>
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            if (ChildCompiledStatements[0] is AssignmentOperator)
            {
                SwapWithChildBinaryOperator(parent);
            }
        }
示例#10
0
        /// <summary>
        /// Call compile when you wish to implement the function.
        /// Process the actual variable names that have been passed into the function using the token.
        /// Create a variable underneath this for each variable we are passing in.
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="token"></param>
        /// <param name="tokens"></param>
        /// <param name="lines"></param>
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            // We have invoked this function because we have parentheses
            if (tokens.Count > 0 && tokens.First.Value == OpenParenthesis.scriptToken)
            {
                // Group our inputs under this object so that we can store them underneath this function
                CompiledStatement thisCallsParams = new CompiledStatement();
                if (ParameterNames.Count > 0)
                {
                    // Only add our parameters if we have any.
                    // Otherwise this will just strip away the start and end parentheses
                    Add(thisCallsParams);
                }

                string openingParenthesis = CelesteCompiler.PopToken();
                Debug.Assert(openingParenthesis == OpenParenthesis.scriptToken, "No opening parenthesis found for function " + Name);

                string parameter = CelesteCompiler.PopToken();

                CompiledStatement tempContainer = new CompiledStatement();
                while (parameter != CloseParenthesis.scriptToken)
                {
                    Debug.Assert(CelesteCompiler.CompileToken(parameter, tempContainer),
                                 "Failed to compile input parameter " + parameter);
                    parameter = CelesteCompiler.PopToken();
                }

                // Add null references first for all of the parameters we are missing
                for (int i = tempContainer.ChildCount; i < ParameterNames.Count; i++)
                {
                    // This will push null onto the stack for every parameter we have not provided an input for
                    Reference refToNull = new Reference(null);
                    refToNull.Compile(thisCallsParams, "null", tokens, lines);
                }

                // Then add the actual parameters we have inputted
                for (int i = tempContainer.ChildCount - 1; i >= 0; i--)
                {
                    // Add our parameters in reverse order, so they get added to the stack in reverse order
                    tempContainer.MoveChildAtIndex(i, thisCallsParams);
                }

                // Add a reference to this function in our compile tree after we have added all of the inputs
                base.Compile(parent, token, tokens, lines);
            }
            else
            {
                // If we have no brackets, we are trying to compile the function as a reference rather than as a call (for use in equality for example)
                Reference funcRef = new Reference(this);
                funcRef.Compile(parent, Name, tokens, lines);
            }

            // Any local variable that is not set will be null
            // Any extra parameters will be added, but because we add them in reverse order, if they are not needed they will just be thrown away on the stack
        }
示例#11
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            // If we have a child assignment operator (it can only be in the first position, we swap it with this operator - this should act first
            // This means we have an expression of the form:    A = B - C
            if (ChildCompiledStatements[0] is AssignmentOperator)
            {
                SwapWithChildBinaryOperator(parent);
            }
        }
示例#12
0
        /// <summary>
        /// See if we have referenced a local variable that exists and if so, create a reference object to it in our expression tree.
        /// This will push a reference onto the stack
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        private static bool CompileAsVariable(CompiledStatement parent, string token)
        {
            if (!CelesteStack.CurrentScope.VariableExists(token, ScopeSearchOption.kUpwardsRecursive))
            {
                return(false);
            }

            // Call compile on our variable we created - this will push a reference to it onto the stack
            CelesteStack.CurrentScope.GetLocalVariable(token).Compile(parent, token, Tokens, Lines);

            return(true);
        }
示例#13
0
        /// <summary>
        /// Runs through each keyword to see if we have a valid keyword our token fits
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        private static bool CompileAsKeyword(CompiledStatement parent, string token)
        {
            if (!RegisteredKeywords.ContainsKey(token))
            {
                return(false);
            }

            // Create an instance of our keyword
            Create <Keyword>(parent, token, RegisteredKeywords[token]);

            return(true);
        }
示例#14
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            Debug.Assert(parent.ChildCount > 0, "No object on the left hand side of the 'null' keyword");

            // Create a value object with null as the stored value - it will be moved under the equality operator when we call nullValue.Compile
            // This will push null onto the stack when run
            Value nullValue = new Value(null);

            nullValue.Compile(parent, token, tokens, lines);
        }
示例#15
0
        /// <summary>
        /// Attempt to parse the inputted token as an operator.
        /// Will rearrange the values to act on underneath the operator in our compiled tree.
        /// </summary>
        /// <param name="token"></param>
        /// <param name="statements"></param>
        /// <returns></returns>
        private static bool CompileAsOperator(CompiledStatement parent, string token)
        {
            foreach (KeyValuePair <MethodInfo, Type> pair in RegisteredOperators)
            {
                if ((bool)pair.Key.Invoke(null, new object[] { token }))
                {
                    Create <Operator>(parent, token, pair.Value);

                    return(true);
                }
            }

            return(false);
        }
示例#16
0
        /// <summary>
        /// Runs through each type to see if we have a valid value our token fits
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private static bool CompileAsValue(CompiledStatement parent, string token)
        {
            foreach (KeyValuePair <MethodInfo, Type> pair in RegisteredValues)
            {
                // Invoke the method we have picked up from reflection for seeing if this token is a valid value
                if ((bool)pair.Key.Invoke(null, new object[] { token }))
                {
                    Create <Value>(parent, token, pair.Value);

                    return(true);
                }
            }

            return(false);
        }
示例#17
0
        /// <summary>
        /// Adds a not unary operator with the next token's compiled object to the parent
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="token"></param>
        /// <param name="tokens"></param>
        /// <param name="lines"></param>
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            // Now check that there is an element after our keyword that we can use as the variable name
            Debug.Assert(tokens.Count > 0, "No value found for the right hand side of the 'not' keyword");

            string rhsToken = CelesteCompiler.PopToken();

            // Create a not operator and compile - this will do all the work of moving statements around in the parent
            // It will also add itself to the parent tree
            NotOperator notOperator = new NotOperator();

            notOperator.Compile(parent, NotOperator.scriptToken + rhsToken, tokens, lines);
        }
示例#18
0
        /// <summary>
        /// Adds an and binary operator with the previous compiled statement and next token's compiled object to the parent
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="token"></param>
        /// <param name="tokens"></param>
        /// <param name="lines"></param>
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            Debug.Assert(parent.ChildCount > 0, "Must have an object on the left side of the 'and' keyword");

            // Now check that there is another element after our keyword that we can use as the variable name
            Debug.Assert(tokens.Count > 0, "No value found for the right hand side of the 'and' keyword");

            // Create an and operator and compile - this will do all the work of moving statements around in the parent
            // It will also add itself to the parent tree
            AndOperator andOperator = new AndOperator();

            andOperator.Compile(parent, AndOperator.scriptToken, tokens, lines);
        }
示例#19
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;
        }
示例#20
0
        /// <summary>
        /// Reads in the condition for the while loop and then the body to perform while the condition is true.
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="token"></param>
        /// <param name="tokens"></param>
        /// <param name="lines"></param>
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            KeyValuePair <CompiledStatement, CompiledStatement> whileCondBody = new KeyValuePair <CompiledStatement, CompiledStatement>(new CompiledStatement(), new CompiledStatement());

            ConditionsAndBodies.Add(whileCondBody);

            Debug.Assert(tokens.Count > 0, "Tokens required for while condition");
            while (tokens.Count > 0)
            {
                CelesteCompiler.CompileToken(CelesteCompiler.PopToken(), whileCondBody.Key);
            }

            // We keep parsing until we find the closing keyword for our while control
            bool foundClosing = false;

            while (!foundClosing)
            {
                Debug.Assert(tokens.Count > 0 || lines.Count > 0, "Function requires a closing " + endDelimiter);

                // Create a new set of tokens if we have run out for this line
                if (tokens.Count == 0)
                {
                    CelesteCompiler.TokenizeNextLine();
                }

                string nextToken = CelesteCompiler.PopToken();
                if (nextToken == endDelimiter)
                {
                    foundClosing = true;
                }
                else if (CelesteCompiler.CompileToken(nextToken, whileCondBody.Value))
                {
                }
                else
                {
                    // Error message if we cannot parse the next token
                    Debug.Fail("Operator invalid on token: " + token);
                }
            }

            // Close the scope that is automatically opened in our constructor
            CelesteStack.CurrentScope = FlowScope.ParentScope;
        }
示例#21
0
        /// <summary>
        /// Compiles the parsed file down into a statement tree
        /// </summary>
        /// <param name="parsedFile"></param>
        private static Tuple <bool, CompiledStatement> CompileScript(List <string> parsedFile)
        {
            RootStatement = new CompiledStatement();
            Tokens        = new LinkedList <string>();
            Lines         = new LinkedList <string>(parsedFile);

            while (Lines.Count > 0)
            {
                // As soon as we detect an error, we stop parsing the script and return a tuple with a false flag and a null compile tree
                if (!CompileLine())
                {
                    Debug.Fail("Error compiling script");
                    return(new Tuple <bool, CompiledStatement>(false, null));
                }
            }

            return(new Tuple <bool, CompiledStatement>(true, RootStatement));
        }
示例#22
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            // Now check that there is another element after our keyword that we can use as the variable name
            Debug.Assert(tokens.Count > 0, "No value found for the right hand side of keyword: " + token);

            // Get the next token that appears on the right hand side of this operator - this will be our variable name
            string rhsOfKeyword = CelesteCompiler.PopToken();

            if (rhsOfKeyword == FunctionKeyword.scriptToken)
            {
                Debug.Assert(tokens.Count > 0, "Function name must exist");
                string functionName = tokens.First.Value;
                functionName = functionName.Remove(functionName.IndexOf(OpenParenthesis.scriptToken));

                if (CelesteCompiler.CompileToken(rhsOfKeyword, parent))
                {
                    // If we have compiled our global function, we need to remove it from the current scope it is added to by default and move it to the global scope
                    Debug.Assert(CelesteStack.CurrentScope.VariableExists(functionName));
                    Variable function = CelesteStack.CurrentScope.RemoveLocalVariable(functionName);
                    CelesteStack.GlobalScope.AddLocalVariable(function);
                }
                else
                {
                    Debug.Fail("Error parsing global function");
                }

                return;
            }

            Debug.Assert(!CelesteStack.GlobalScope.VariableExists(rhsOfKeyword), "Variable with the same name already exists in this scope");

            // Creates a new variable, but does not call Compile - Compile for variable assigns a reference from the stored variable in CelesteStack
            Variable variable = CelesteStack.GlobalScope.CreateLocalVariable <Variable>(rhsOfKeyword);

            // If we still have unparsed tokens, then add this variable to the tree
            // Otherwise, do not - we do not need to push an object onto the stack for no reason
            if (tokens.Count > 0)
            {
                // Add our variable underneath our parent - this keyword will do nothing at run time so do not add it to the tree
                parent.Add(variable);
            }
        }
示例#23
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            parent.Add(this);

            while (tokens.Count > 0)
            {
                // Get the next token that appears on the right hand side of this operator
                // This will be the name of the local variables we wish to return
                string rhsOfKeyword = CelesteCompiler.PopToken();
                if (rhsOfKeyword.EndsWith(returnParameterDelimiter))
                {
                    // Return the parameter delimiter after each return parameter if it exists
                    rhsOfKeyword = rhsOfKeyword.Remove(rhsOfKeyword.Length - 1);
                }
                Debug.Assert(CelesteCompiler.CompileToken(rhsOfKeyword, this), "Error compiling return parameter");
            }
        }
示例#24
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            // Unary operators act on other variables/values and so they must be included in the same token as another token (e.g. !var for example)
            // We remove the script token for the operator and split the other token out
            Debug.Assert(token.Length > 1);
            string rest = token.Remove(0, 1); // Removing wrong thing here

            // Add this operator to the tree
            parent.Add(this);

            // Parse the rest of the token which we will act on
            if (CelesteCompiler.CompileToken(rest, parent))
            {
                // Take the value that has been added to the root and add it under this operator instead
                parent.MoveChildAtIndex(parent.ChildCount - 1, this);
            }
            else
            {
                // Error message if we cannot parse the next token
                Debug.Fail("Could not compile token: " + token + " in operator " + token);
            }
        }
示例#25
0
        /// <summary>
        /// Extracts the script token from the inputted token and pushes the remaining token back into the tokens list followed by the script token.
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="token"></param>
        /// <param name="tokens"></param>
        /// <param name="lines"></param>
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            // For now we will just take the parenthesis and add it as a separate token along with the rest of the token
            // Need to do actual implementation stuff though
            int    index     = token.IndexOf(scriptToken);
            string lhsString = token.Substring(0, index);
            string rhsString = token.Substring(index + 1);

            // Split the string with the parenthesis but maintain the order of the tokens in the list from left to right, first to last

            if (!string.IsNullOrEmpty(rhsString))
            {
                tokens.AddFirst(rhsString);
            }

            tokens.AddFirst(scriptToken);

            if (!string.IsNullOrEmpty(lhsString))
            {
                tokens.AddFirst(lhsString);
            }
        }
示例#26
0
        /// <summary>
        /// If our first child is a binary operator, we swap it with this binary operator.
        /// This has the effect of evaluating this before the child operator.
        /// Useful when you wish to evaluate this operator before an assignment operator for example.
        /// </summary>
        protected void SwapWithChildBinaryOperator(CompiledStatement parent)
        {
            Debug.Assert(ChildCount > 0);
            Debug.Assert(ChildCompiledStatements[0] is AssignmentOperator);

            CompiledStatement child = ChildCompiledStatements[0];

            // We start with:
            //
            //              parent
            //             /
            //          this
            //         /    \
            //      child    C
            //     /     \
            //    A       B

            MoveChildAtIndex(0, parent);
            // Move the child to the parent - we now have:
            //
            //         parent
            //        /    \
            //     this      child
            //    /         /     \
            //   C         A       B

            Debug.Assert(parent.ChildCompiledStatements[parent.ChildCount - 2] == this);
            parent.MoveChildAtIndex(parent.ChildCount - 2, child);
            // Move this to be underneath the child operator - we now have:
            //
            //         parent
            //             \
            //              child
            //             /  |   \
            //            A   B    this
            //                         \
            //                           C

            Debug.Assert(child.ChildCount == 3);
            child.MoveChildAtIndex(1, this);
            // Move the B to under this - we now have:
            //
            //         parent
            //             \
            //              child
            //             /     \
            //            A       this
            //                   /    \
            //                  C      B

            Debug.Assert(ChildCount == 2);
            MoveChildAtIndex(0, this);
            // Extract and then reinsert C into this - this swaps C and B to give:
            //
            //         parent
            //             \
            //              child
            //             /     \
            //            A       this
            //                   /    \
            //                  B      C
        }
示例#27
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            string fullString = "";

            // If our token is of the form "something" we have our full string
            if (token.EndsWith(endDelimiter))
            {
                // Remove the '"' from the start and the end
                fullString = token.Substring(1, token.Length - 2);
            }
            else
            {
                // Our full string is going to be split over many tokens - we need to keep adding tokens until we hit our second '"'
                // Remove the '"' from the first token
                fullString = token.Remove(0, 1);

                // Need more tokens left over to make our full string
                Debug.Assert(tokens.Count > 0, "No \" found to end the string: " + fullString);
                string currentToken;

                // We are going to keep removing elements, so need to check whether we still have tokens left to check
                while (tokens.Count > 0)
                {
                    currentToken = CelesteCompiler.PopToken();

                    if (!string.IsNullOrEmpty(currentToken))
                    {
                        // If the next token we are moving through contains '"' we are done finding our full string
                        if (currentToken.Contains(endDelimiter))
                        {
                            // Add the substring without the end string character to our full string
                            int index = currentToken.IndexOf(endDelimiter);
                            if (index > 0)
                            {
                                // Concatenate the contents of this token if it was more than just the end delimiter
                                fullString += " " + currentToken.Substring(0, index);
                            }

                            if (index < currentToken.Length - 1)
                            {
                                // The end delimiter was in the middle of the token and we have other stuff that should be popped back into the tokens list
                                // index + 1 because we don't want to add the end delimiter
                                tokens.AddFirst(currentToken.Substring(index + 1));
                            }

                            break;
                        }
                        else
                        {
                            fullString += " " + currentToken;
                        }
                    }

                    // We should only ever get here if we have tokens left
                    // If this assert triggers, it means that we have run out of tokens, but not found a close to our string
                    Debug.Assert(tokens.Count > 0, "No \" found to end the string: " + fullString);
                }
            }

            _Value = fullString;
        }
示例#28
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            parent.Add(this);
        }
示例#29
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            // We know the token will at least start with the start delimiter
            if (token.Length > 1)
            {
                // In here if the start delimiter and another token are smushed together with no space
                // Split the start delimiter and the rest of the token and add the rest of the token to the start of our tokens list
                string rest = token.Remove(0, 1);
                tokens.AddFirst(rest);
            }

            // We keep parsing until we find a closing character for our list
            bool foundClosing = false;

            while (!foundClosing)
            {
                Debug.Assert(tokens.Count > 0 || lines.Count > 0, "Table requires a closing " + endDelimiter);

                // Create a new set of tokens if we have run out for this line
                if (tokens.Count == 0)
                {
                    CelesteCompiler.TokenizeNextLine();
                }

                string nextToken = CelesteCompiler.PopToken();
                if (nextToken == AssignmentOperator.scriptToken)
                {
                    string valueToken = tokens.First.Value;
                    if (valueToken.EndsWith(endDelimiter) && valueToken.Length > 1)
                    {
                        valueToken         = valueToken.Remove(valueToken.Length - 1, 1);
                        tokens.First.Value = valueToken;
                        foundClosing       = true;
                    }
                }

                if (nextToken == endDelimiter)
                {
                    foundClosing = true;
                }
                else if (CelesteCompiler.CompileToken(nextToken, parent))
                {
                    CompiledStatement compiledStatement = parent.ChildCompiledStatements[parent.ChildCount - 1];

                    if (!gotKey)
                    {
                        // The statement we created for our key MUST be a value type
                        Debug.Assert(compiledStatement is Value, "Key in table must be a valid value type");
                        gotKey = true;
                    }
                    else if (!gotEquality)
                    {
                        // The statement we created after our key MUST be the equality operator
                        Debug.Assert(compiledStatement is AssignmentOperator, "Equality expected after key");
                        gotEquality = true;
                        gotValue    = compiledStatement.ChildCount == 2;
                    }

                    if (gotValue)
                    {
                        // We have an equals parented under the 'parent' parameter (along with this table), with the key and value parented under that
                        // We insert the key and value into our dictionary, discard the equals statement and adjust our flags
                        Debug.Assert(parent.ChildCount >= 2);
                        Debug.Assert(parent.ChildCompiledStatements[parent.ChildCount - 1].ChildCount == 2);
                        Debug.Assert(parent.ChildCompiledStatements[parent.ChildCount - 1] is AssignmentOperator);

                        AssignmentOperator equals = parent.ChildCompiledStatements[parent.ChildCount - 1] as AssignmentOperator;
                        Debug.Assert(equals.ChildCompiledStatements[0] is Value);
                        Debug.Assert(equals.ChildCompiledStatements[1] is Value);

                        DictionaryRef.Add((equals.ChildCompiledStatements[0] as Value)._Value, (equals.ChildCompiledStatements[1] as Value)._Value);
                        parent.ChildCompiledStatements.RemoveAt(parent.ChildCount - 1);

                        gotKey      = false;
                        gotEquality = false;
                        gotValue    = false;
                    }
                }
                else
                {
                    // Error message if we cannot parse the next token
                    Debug.Fail("Operator invalid on token: " + token);
                }
            }

            Debug.Assert(!gotKey && !gotEquality && !gotValue, "Incomplete key value pair in table");
        }
示例#30
0
        public override void Compile(CompiledStatement parent, string token, LinkedList <string> tokens, LinkedList <string> lines)
        {
            base.Compile(parent, token, tokens, lines);

            // Now check that there is another element after our keyword that we can use as the function name
            Debug.Assert(tokens.Count > 0 || lines.Count > 0, "No parameters or body found for the keyword: " + token);

            // The first token should be the function name
            string functionName = CelesteCompiler.PopToken();

            Debug.Assert(!CelesteStack.CurrentScope.VariableExists(functionName), "Variable with the same name already exists in this scope");

            // Get the next token - this should be an opening parenthesis
            string openingParenthesis = CelesteCompiler.PopToken();

            Debug.Assert(openingParenthesis == OpenParenthesis.scriptToken, "No opening parenthesis found for function " + functionName);

            // Creates a new function, but does not call Compile - Compile for function assigns a reference from the stored function in CelesteStack
            Function function = CelesteStack.CurrentScope.CreateLocalVariable <Function>(functionName);

            // Obtain the parameter names from the strings/tokens between the brackets
            List <string> paramNames = new List <string>();
            string        parameters = CelesteCompiler.PopToken();

            while (parameters != CloseParenthesis.scriptToken)
            {
                // Clean the parameter array of empty strings and remove any delimiter characters from parameter names
                List <string> parameterList = new List <string>(parameters.Split(Delimiter.scriptTokenChar));
                parameterList.RemoveAll(x => string.IsNullOrEmpty(x));
                parameterList = new List <string>(parameterList.Select(x => x = x.Replace(Delimiter.scriptToken, "")));

                // Add any parameters which are of this form 'param1,param2'
                paramNames.AddRange(parameterList);

                parameters = CelesteCompiler.PopToken();// This algorithm should completely take care of any mix of parameters separated with a space or not
            }

            function.SetParameters(paramNames.ToArray());

            // We keep parsing until we find the closing keyword for our function
            bool foundClosing = false;

            while (!foundClosing)
            {
                Debug.Assert(tokens.Count > 0 || lines.Count > 0, "Function requires a closing " + endDelimiter);

                // Create a new set of tokens if we have run out for this line
                if (tokens.Count == 0)
                {
                    CelesteCompiler.TokenizeNextLine();
                }

                string nextToken = CelesteCompiler.PopToken();
                if (nextToken == endDelimiter)
                {
                    foundClosing = true;
                }
                else if (CelesteCompiler.CompileToken(nextToken, function.FuncImpl))
                {
                }
                else
                {
                    // Error message if we cannot parse the next token
                    Debug.Fail("Operator invalid on token: " + token);
                }
            }

            // Do not add the function - it will be looked up to and called rather than pushed onto the stack (much like a variable)
            // Close the function's scope now - we have added all the appropriate variables to it
            // This scope is automatically opened in the Function constructor
            CelesteStack.CurrentScope = function.FunctionScope.ParentScope;
        }