Example #1
0
        /// <summary>
        /// Takes an array of string values, and converts it to the proper value type for
        /// this instance's Generic Type
        /// </summary>
        /// <param name="ValueParams">The string value's to convert, and set the
        /// Value of this instance to.
        /// </param>
        public override void SetValue(Token token, int objectLevel = 0)
        {
            Type PropertyType = typeof(T);

            // ===
            // DONOT use this ObjectProperties TOKEN! breaks collections!
            TokenArgs tokenArgs = token.TokenArgs;

            // ===

            // Check for ConFileObjects
            if (typeof(ConFileObject).IsAssignableFrom(PropertyType))
            {
                // define vars
                ConFileObject obj = (ConFileObject)(object)Value;

                // Load a new object if we are undefined
                if (obj == null)
                {
                    // Is this a defined object?
                    string name = tokenArgs.Arguments.Last();
                    //var type = ScriptEngine.GetTemplateType(PropertyType);

                    // Check for the object in this properties owner's Scope
                    if (Token.File.Scope.ContainsObject(name, PropertyType))
                    {
                        obj      = Token.File.Scope.GetObject(name, PropertyType, Token);
                        Argument = new ValueInfo <T>((T)(object)obj);
                    }
                    else
                    {
                        string error = $"ObjectProperty \"{Name}\" requires an existing object that is not defined!";
                        throw new Exception(error);
                    }
                }
                else
                {
                    // Let the child class parse itself
                    obj.Parse(token, ++objectLevel);
                    Argument = new ValueInfo <T>((T)(object)obj);
                }
            }
            else if (PropertyType.IsGenericType)
            {
                // Check for Generic types, we don't support these!
                throw new Exception($"Invalid Generic Type found \"{PropertyType}\"");
            }
            else
            {
                // Since we are not an array property, make sure we didnt get
                // an array passed in the con file
                if (tokenArgs.Arguments.Length > 1)
                {
                    throw new Exception($"Expecting single value, but got an Array for \"{Name}\"");
                }

                // Since we are not an array, extract our only value
                Argument = new ValueInfo <T>(ConvertValue <T>(tokenArgs.Arguments[0], PropertyType));
            }
        }
Example #2
0
 /// <summary>
 /// Creates a new instance of <see cref="ObjectProperty{T}"/>
 /// </summary>
 /// <param name="name">the property name</param>
 /// <param name="token">the token information</param>
 /// <param name="property">The PropertyInfo object for this instance</param>
 /// <param name="owner">the ConFileObject that owns this property instance</param>
 public ObjectProperty(string name, Token token, PropertyInfo property, ConFileObject owner)
 {
     Name     = name;
     Token    = token;
     Property = property;
     Owner    = owner;
 }
Example #3
0
        /// <summary>
        /// Sets the active object in this scope, of its base template type
        /// </summary>
        /// <remarks>The object DOES NOT need to exist in this scope, but must in a parent scope</remarks>
        /// <param name="obj">The object we are activating</param>
        public void SetActiveObject(ConFileObject obj)
        {
            // Ensure that we aren't passing peoples problems
            CheckObjectToken(obj);
            ReferenceType type = obj.Token.TokenArgs.ReferenceType;

            ActiveObjects[type] = obj;
        }
Example #4
0
        /// <summary>
        /// Determines whether the specified object (not reference) exists in this scope.
        /// </summary>
        /// <param name="obj">The object we are searching for</param>
        /// <returns>true if the object exists in this scope, otherwise false</returns>
        public bool ContainsObject(ConFileObject obj)
        {
            // Ensure that we aren't passing peoples problems
            CheckObjectToken(obj);

            // Check for object existance
            var type = obj.Token.TokenArgs.ReferenceType;
            var key  = new Tuple <string, ReferenceType>(obj.Name, type);

            return(ContainsObject(key));
        }
Example #5
0
 /// <summary>
 /// Ensures that our token is valid
 /// </summary>
 /// <param name="obj"></param>
 private void CheckObjectToken(ConFileObject obj)
 {
     // Ensure that we aren't passing peoples problems
     if (obj?.Token?.TokenArgs == null)
     {
         throw new ArgumentNullException(
                   "obj.Token.TokenArgs",
                   $"TokenArgs are not defined on \"{obj.Name}\"!"
                   );
     }
     else if (obj.Token.TokenArgs.ReferenceType == null)
     {
         throw new ArgumentNullException(
                   "obj.Token.TokenArgs.ReferenceType",
                   $"ReferenceType is not defined on \"{obj.Name}\"!"
                   );
     }
 }
Example #6
0
        /// <summary>
        /// Adds a <see cref="ConFileObject"/> to this Scope
        /// </summary>
        /// <remarks>
        /// Used by the script engine to add objects, and set them as active
        /// </remarks>
        /// <param name="obj"></param>
        /// <param name="token"></param>
        internal void AddObject(ConFileObject obj, Token token)
        {
            // Ensure that we aren't passing peoples problems
            CheckObjectToken(obj);

            // Generate key
            var type = obj.Token.TokenArgs.ReferenceType;
            var key  = new Tuple <string, ReferenceType>(obj.Name, type);

            // If object exists, then we fetch the existing reference
            if (ContainsObject(key))
            {
                // Log warning
                string err = $"Object \"{obj.Name}\" is already defined, Setting existing one as active";
                Logger.Warning(err, token.File, token.Position);

                // Get existing reference
                obj = GetObject(key, token);
            }
            else
            {
                // Add object
                Objects.Add(key, obj);

                // Register object?
                if (ParentScope != null && RegisterObjects)
                {
                    if (ScopeType == ScopeType.Attached)
                    {
                        ParentScope.AddObject(obj, token);
                    }
                    else
                    {
                        ParentScope.AddObject(obj.Clone(), token);
                    }
                }
            }

            // Set object as active
            SetActiveObject(obj);
        }
Example #7
0
        /// <summary>
        /// Adds a <see cref="ConFileObject"/> to this Scope
        /// </summary>
        /// <param name="obj">The object reference to add</param>
        /// <param name="setActive">
        /// Set this as the active object of its <see cref="ReferenceType"/>?
        /// </param>
        public void AddObject(ConFileObject obj, bool setActive = true)
        {
            // Ensure that we aren't passing peoples problems
            CheckObjectToken(obj);

            // Generate key
            var type = obj.Token.TokenArgs.ReferenceType;
            var key  = new Tuple <string, ReferenceType>(obj.Name, type);

            // If object exists, throw exception
            if (ContainsObject(key))
            {
                throw new Exception("Object is already defined in this scope!");
            }

            // Do we set as the active object?
            if (setActive)
            {
                SetActiveObject(obj);
            }

            // Register object?
            if (ParentScope != null && RegisterObjects)
            {
                if (ScopeType == ScopeType.Attached)
                {
                    ParentScope.AddObject(obj, setActive);
                }
                else
                {
                    ParentScope.AddObject(obj.Clone(), setActive);
                }
            }

            // Add object
            Objects.Add(key, obj);
        }
Example #8
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();
        }