Example #1
0
        /// <summary>
        /// Executes the the specified token on the specified scope
        /// </summary>
        /// <param name="token"></param>
        /// <param name="scope"></param>
        public static void ExecuteInScope(Token token, Scope scope)
        {
            // create properties
            ConFileObject currentObj;

            switch (token.Kind)
            {
                case TokenType.ObjectStart:
                case TokenType.ActiveSwitch:
                    // Fetch our object
                    if (token.Kind == TokenType.ActiveSwitch)
                    {
                        // Fetch the object and Set as the active object
                        currentObj = scope.GetObject(token);
                        scope.SetActiveObject(currentObj);
                    }
                    else
                    {
                        // Get our method
                        var Method = token.TokenArgs.ReferenceType.GetMethod(
                            token.TokenArgs.PropertyName
                        );

                        // Fetch our new working object.
                        currentObj = Method.Invoke(token);
                        scope.AddObject(currentObj, token);
                    }

                    // Add file entry?
                    if (token.File != null)
                    {
                        // see if the object exists in file
                        if (token.File.Entries.Contains(currentObj))
                            token.File.AddEntry(currentObj, token);
                    }
                    break;
                case TokenType.ObjectProperty:
                    // Get the last used object
                    ReferenceType type = token.TokenArgs.ReferenceType;
                    currentObj = scope.GetActiveObject(type);

                    // Make sure we have an object to work with and the object
                    // reference matches our current working object
                    if (currentObj == null)
                    {
                        // If we are here, we have an issue...
                        string error = $"Failed to set property \"{token.TokenArgs.ReferenceType.Name}.\""
                            + $"{token.TokenArgs.PropertyName}. No object reference set!";
                        Logger.Error(error, token.File, token.Position);
                        throw new ParseException(error, token);
                    }

                    // Let the object parse its own lines...
                    try
                    {
                        currentObj.Parse(token);
                    }
                    catch (Exception e)
                    {
                        Logger.Error(e.Message, token.File, token.Position, e);
                        throw;
                    }
                    break;
                case TokenType.RemComment:
                case TokenType.BeginRem:
                case TokenType.IfStart:
                case TokenType.Run:
                case TokenType.Include:
                    break;
                case TokenType.Constant:
                case TokenType.Variable:
                    Expression exp = new Expression(token);
                    scope.Expressions[exp.Name] = exp;
                    break;
                case TokenType.None:
                    // Throw error if the line is not empty
                    if (!String.IsNullOrWhiteSpace(token.Value))
                    {
                        string message = $"Unable to parse file entry \"{token.Value}\" on line {token.Position}";
                        Logger.Error(message, token.File, token.Position);
                        throw new ParseException(message, token);
                    }
                    break;
            }
        }
Example #2
0
        /// <summary>
        /// Parses the contents of a .con or .ai file, and converts the contents into C# objects
        /// </summary>
        /// <param name="fileContents">A dictionary of file contents [LineNumber => LineContents]</param>
        /// <param name="workingFile">A reference to the ConFile that contains the contents</param>
        internal static async Task ParseFileLines(
            Dictionary<int, string> fileContents, 
            ConFile workingFile, 
            ExecuteInstruction run)
        {
            // ============
            // First we convert our confile lines into parsed tokens
            // ============
            Token[] fileTokens = Tokenizer.Tokenize(workingFile, ref fileContents);
            TokenArgs tokenArgs;
            Scope currentScope = workingFile.Scope;

            // ============
            // Now we create an object reference of all objects in the Confile
            // before parsing the object properties, which **can** reference an object
            // in the same file before its defined
            // NOTE: Do not create object references for .Active and .safeActive
            // ============
            foreach (Token token in fileTokens.Where(x => x.Kind == TokenType.ObjectStart).OrderBy(x => x.Position))
            {
                // Create the object
                var Method = token.TokenArgs.ReferenceType.GetMethod(token.TokenArgs.PropertyName);
                ConFileObject template = Method.Invoke(token);

                // Finally, register the object with the ObjectManager
                currentScope.AddObject(template, token);
                Logger.Info($"Created {token.TokenArgs.ReferenceType} \"{template.Name}\"", workingFile, token.Position);
            }

            // ============
            // Finally, we load all of the object properties, and assign them to their 
            // respective objects
            // ============

            // Create our needed objects
            RemComment comment = null;
            ConFileObject currentObj = null;
            ReferenceType type;
            var builder = new StringBuilder();

            // We use a for loop here so we can skip rem blocks and statements
            for (int i = 0; i < fileTokens.Length; i++)
            {
                // Grab token value
                Token token = fileTokens[i];
                try
                {
                    switch (token.Kind)
                    {
                        case TokenType.ObjectStart:
                        case TokenType.ActiveSwitch:
                            // NOTE: the object was created before this loop!
                            currentObj = currentScope.GetObject(token);
                            currentScope.SetActiveObject(currentObj);

                            // === Objects are already added to the working file before hand === //
                            // Add object reference to file
                            workingFile.AddEntry(currentObj, token);

                            // Reset comment
                            comment = null;

                            // Log
                            Logger.Info($"Loading object properties for \"{currentObj.Name}\"",
                                workingFile, token.Position
                            );
                            break;
                        case TokenType.ObjectProperty:
                            // Convert args to an object
                            tokenArgs = token.TokenArgs;

                            // Get the last used object
                            type = tokenArgs.ReferenceType;
                            currentObj = currentScope.GetActiveObject(type);

                            // Make sure we have an object to work with and the object
                            // reference matches our current working object
                            if (currentObj == null)
                            {
                                // If we are here, we have an issue...
                                string error = $"Failed to set property \"{token.TokenArgs.ReferenceType.Name}.\""
                                    + $"{token.TokenArgs.PropertyName}. No object reference set!";
                                throw new ParseException(error, token);
                            }

                            // Let the object parse its own lines...
                            try
                            {
                                currentObj.Parse(token);

                                // Ensure comment is null
                                comment = null;
                            }
                            catch (Exception e)
                            {
                                Logger.Error(e.Message, workingFile, token.Position, e);
                                throw;
                            }
                            break;
                        case TokenType.RemComment:
                            // Create a new comment if we need to
                            if (comment == null)
                            {
                                comment = new RemComment(token);
                            }

                            // Add comment to the current string
                            comment.AppendLine(token.Value);
                            break;
                        case TokenType.BeginRem:
                            RemComment rem = new RemComment(token);
                            rem.IsRemBlock = true;

                            // Skip every line until we get to the endRem
                            builder.AppendLine(token.Value);
                            i = ScopeUntil(TokenType.EndRem, fileTokens, i, builder);

                            // Set rem value
                            rem.Value = builder.ToString().TrimEnd();
                            workingFile.AddEntry(rem, rem.Token);

                            // Clear the string builder
                            builder.Clear();
                            break;
                        case TokenType.IfStart:
                            Statement statement = new Statement(token);
                            if (token.Kind == TokenType.IfStart)
                            {
                                // Skip every line until we get to the endIf
                                builder.AppendLine(token.Value);
                                i = ScopeUntil(TokenType.EndIf, fileTokens, i, builder);

                                // Clear the string builder
                                statement.Token.Value = builder.ToString().TrimEnd();
                                builder.Clear();
                            }

                            // Add entry
                            workingFile.AddEntry(statement, statement.Token);
                            break;
                        case TokenType.Run:
                        case TokenType.Include:
                            // Just add to as a string
                            RunStatement stmt = new RunStatement(token);
                            workingFile.AddEntry(stmt, stmt.Token);

                            // Do we execute the statement?
                            if (run == ExecuteInstruction.Skip)
                                continue;

                            // Create new scope for execution
                            Scope runScope = currentScope;

                            // Are we executing in a new scope?
                            if (run == ExecuteInstruction.ExecuteInNewScope)
                            {
                                // For now, we just inherit the parent scope type
                                runScope = new Scope(currentScope, currentScope.ScopeType);
                                runScope.MissingObjectHandling = MissingObjectHandling.CheckParent;
                            }

                            // Get the filepath
                            string filePath = Path.GetDirectoryName(workingFile.FilePath);
                            string fileName = Path.Combine(filePath, stmt.FileName);

                            // Define file arguments
                            runScope.SetArguments(stmt.Arguments);

                            // Load the file
                            try
                            {
                                ConFile include = await LoadFileAsync(fileName, runScope, run);
                                workingFile.ExecutedIncludes.Add(include);
                            }
                            catch (FileNotFoundException) // Only acceptable exception
                            {
                                fileName = Path.GetFileName(fileName);
                                Logger.Warning($"Failed to run file \"{fileName}\". File Not Found", 
                                    workingFile, token.Position);
                            }
                            break;
                        case TokenType.Constant:
                        case TokenType.Variable:
                            // Set the new expression reference in Scope
                            Expression exp = new Expression(token);
                            currentScope.Expressions[exp.Name] = exp;

                            // Add expression to the confile as well
                            workingFile.AddEntry(exp, exp.Token);
                            break;
                        case TokenType.None:
                            // Dont attach comment to a property if we have an empty line here
                            if (comment != null)
                            {
                                workingFile.AddEntry(comment, comment.Token);
                                comment = null;
                            }

                            // Throw error if the line is not empty
                            if (!String.IsNullOrWhiteSpace(token.Value))
                            {
                                string message = $"Unable to parse file entry \"{token.Value}\" on line {token.Position}";
                                throw new ParseException(message, token);
                            }
                            break;
                    }
                }
                catch (Exception e)
                {
                    Logger.Error(e.Message, token.File, token.Position, e);
                    throw;
                }
            }

            // Finalize this confile
            workingFile.Finish();
        }