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"); } } }
/// <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; }
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"); }
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; }