Esempio n. 1
0
        //Checks whether a variable exists.
        public bool VariableExists(string varname)
        {
            if (varname.Contains('.'))
            {
                //Validate it by fake value grabbing.
                List <string> parts      = varname.Split('.').ToList();
                AlgoValue     partParent = GetVariable(parts[0]);
                if (partParent == null || (partParent.Type != AlgoValueType.Object && parts.Count > 1))
                {
                    return(false);
                }

                //If the variable is known to exist and no points, this is just a sanity check to make sure nothing slips through.
                if (parts.Count == 1)
                {
                    return(true);
                }

                //Iterate through children recursively to check they all exist.
                AlgoObject currentObj = (AlgoObject)partParent.Value;
                parts.RemoveAt(0);
                string childString = string.Join(".", parts.ToArray());

                //Recursive return.
                return(currentObj.ObjectScopes.VariableExists(childString));
            }
            return(GetVariable(varname) != null);
        }
Esempio n. 2
0
        //Returns the value of a referenced object within an object string.
        private AlgoValue GetValueFromObjectString(string objString)
        {
            //Splitting the string by "." to get individual variable parts.
            string[] objParts = objString.Split('.');
            if (objParts.Length == 1)
            {
                if (!VariableExists(objString))
                {
                    return(null);
                }

                return(GetVariable(objString));
            }

            //Loop and get value.
            if (!VariableExists(objParts[0]))
            {
                return(null);
            }

            //Get the first parent object.
            AlgoValue currentObjValue = GetVariable(objParts[0]);

            if (currentObjValue.Type != AlgoValueType.Object)
            {
                return(null);
            }

            //Getting the deepest scope.
            AlgoObject currentObj = (AlgoObject)currentObjValue.Value;

            for (int i = 1; i < objParts.Length - 1; i++)
            {
                //Attempt to get the child.
                if (!currentObj.ObjectScopes.VariableExists(objParts[i]))
                {
                    return(null);
                }
                currentObjValue = currentObj.ObjectScopes.GetVariable(objParts[i]);

                //Check if it's an object.
                if (currentObjValue.Type != AlgoValueType.Object)
                {
                    return(null);
                }

                //Set current object.
                currentObj = (AlgoObject)currentObjValue.Value;
            }

            //Getting the variable referenced at the deepest scope.
            if (!currentObj.ObjectScopes.VariableExists(objParts[objParts.Length - 1]))
            {
                return(null);
            }

            //Returning it.
            return(currentObj.ObjectScopes.GetVariable(objParts[objParts.Length - 1]));
        }
Esempio n. 3
0
        //Add a variable to the scope.
        public void AddVariable(string name, AlgoValue value, ParserRuleContext context = null)
        {
            //Is it an object member?
            if (!name.Contains("."))
            {
                //Check if a variable with this name already exists.
                if (VariableExistsLowest(name))
                {
                    Error.Fatal(context, "A variable with this name already exists, cannot create one.");
                    return;
                }

                //Nope, add it to the lowest scope.
                Scopes[Scopes.Count - 1].Add(name, value);
            }
            else
            {
                //Object member, a more complicated procedure.
                //Get the parent object that the member is being assigned to.
                string        objTxt   = name;
                List <string> objParts = objTxt.Split('.').ToList();
                string        final    = objParts.Last();
                objParts.RemoveAt(objParts.Count - 1);
                objTxt = string.Join(".", objParts.ToArray());

                if (!VariableExists(objTxt))
                {
                    Error.Fatal(context, "Cannot create an object member for nonexistant object '" + objTxt + "'.");
                }

                //Check if the variable is an object.
                AlgoValue objVal = GetVariable(objTxt);
                if (objVal.Type != AlgoValueType.Object)
                {
                    Error.Fatal(context, "Cannot create an object member of non-object value '" + objTxt + "'.");
                }
                AlgoObject obj = (AlgoObject)objVal.Value;

                //Check if the variable has the new member already defined.
                if (obj.ObjectScopes.VariableExists(final))
                {
                    Error.Fatal(context, "An object member with that name already exists.");
                }

                //Create the variable.
                obj.ObjectScopes.AddVariable(final, value);

                //Set the object parent.
                SetVariable(objTxt, new AlgoValue()
                {
                    Type  = AlgoValueType.Object,
                    Value = obj
                });
            }
        }
Esempio n. 4
0
        //When an enum is first defined.
        public override object VisitStat_enumDef([NotNull] algoParser.Stat_enumDefContext context)
        {
            //Check if the variable already exists at local scope.
            if (Scopes.VariableExistsLowest(context.IDENTIFIER().GetText()))
            {
                Error.Fatal(context, "A variable with the name '" + context.IDENTIFIER().GetText() + "'already exists, cannot create a duplicate.");
                return(null);
            }

            //Create an object for the enum.
            AlgoObject enumObj = new AlgoObject();

            //For each enum member, create a child in the object with an integer value.
            BigInteger enumIndex = 0;

            if (context.abstract_params() != null)
            {
                foreach (var id in context.abstract_params().IDENTIFIER())
                {
                    //Does a member with this name already exist?
                    if (enumObj.ObjectScopes.VariableExists(id.GetText()))
                    {
                        Error.Fatal(context, "An enum member with the name '" + id.GetText() + "' already exists.");
                        return(null);
                    }

                    //Add member.
                    enumObj.ObjectScopes.AddVariable(id.GetText(), new AlgoValue()
                    {
                        Type  = AlgoValueType.Integer,
                        Value = enumIndex
                    });

                    enumIndex++;
                }
            }

            //Create an enum variable with this name.
            Scopes.AddVariable(context.IDENTIFIER().GetText(), new AlgoValue()
            {
                Type  = AlgoValueType.Object,
                Value = enumObj
            });

            return(null);
        }
Esempio n. 5
0
        //Remove a variable from the scope.
        public void RemoveVariable(string name)
        {
            //Check if a variable with this name exists.
            if (!VariableExists(name))
            {
                Error.FatalNoContext("No variable with this name exists, so can't destroy it.");
                return;
            }

            //If the name contains a '.', got to go to deepest scope recursively.
            if (name.Contains('.'))
            {
                //Get the parent.
                List <string> parts      = name.Split('.').ToList();
                AlgoValue     partParent = GetVariable(parts[0]);

                //Checking if it's an object.
                if (partParent.Type != AlgoValueType.Object)
                {
                    Error.FatalNoContext("The value given is not an object, so cannot remove children.");
                    return;
                }

                //Remove variable from this scope recursively.
                parts.RemoveAt(0);
                string     newPartString = string.Join(".", parts.ToList());
                AlgoObject partObj       = (AlgoObject)partParent.Value;
                partObj.ObjectScopes.RemoveVariable(newPartString);
            }
            else
            {
                //Literal variable in this scope, check through all scopes (from deepest) and delete.
                for (int i = Scopes.Count - 1; i >= 0; i--)
                {
                    if (Scopes[i].ContainsKey(name))
                    {
                        Scopes[i].Remove(name);
                        return;
                    }
                }
            }

            //Could not find.
            Error.FatalNoContext("Could not find variable to delete, despite the fact it exists.");
        }
Esempio n. 6
0
        //When a single value is visited in Algo.
        public override object VisitValue([NotNull] algoParser.ValueContext context)
        {
            //Check what type the value is.
            if (context.INTEGER() != null)
            {
                //INTEGER
                return(new AlgoValue()
                {
                    Type = AlgoValueType.Integer,
                    Value = BigInteger.Parse(context.INTEGER().GetText()),
                });
            }
            else if (context.FLOAT() != null)
            {
                //FLOAT
                return(new AlgoValue()
                {
                    Type = AlgoValueType.Float,
                    Value = BigFloat.Parse(context.FLOAT().GetText()),
                });
            }
            else if (context.STRING() != null)
            {
                //STRING
                return(new AlgoValue()
                {
                    Type = AlgoValueType.String,
                    Value = context.STRING().GetText().Substring(1, context.STRING().GetText().Length - 2)
                            //text escape codes
                            .Replace("\\n", "\n")
                            .Replace("\\t", "\t")
                            .Replace("\\r", "\r")
                            .Replace("\\q", "\"")
                });
            }
            else if (context.RATIONAL() != null)
            {
                //RATIONAL
                //Get the two integer halves from the rational.
                string[] halves      = context.RATIONAL().GetText().Split('/');
                string   numerator   = halves[0];
                string   denominator = halves[1];

                return(new AlgoValue()
                {
                    Type = AlgoValueType.Rational,
                    Value = new BigRational(BigInteger.Zero, new Fraction(BigInteger.Parse(numerator), BigInteger.Parse(denominator))),
                });
            }
            else if (context.BOOLEAN() != null)
            {
                //BOOLEAN
                return(new AlgoValue()
                {
                    Type = AlgoValueType.Boolean,
                    Value = (context.BOOLEAN().GetText() == "true"),
                });
            }
            else if (context.HEX() != null)
            {
                //BYTES
                return(new AlgoValue()
                {
                    Type = AlgoValueType.Bytes,
                    Value = context.HEX().GetText().ToByteArray()
                });
            }
            else if (context.NULL() != null)
            {
                //NULL VALUE
                return(new AlgoValue()
                {
                    Type = AlgoValueType.Null,
                    Value = null,
                });
            }
            else if (context.IDENTIFIER() != null)
            {
                //VARIABLE/OBJECT
                return(Particles.ParseParticleBlock(this, context, context.IDENTIFIER(), context.particle()));
            }
            else if (context.stat_functionCall() != null)
            {
                //FUNCTION CALL
                AlgoValue value = (AlgoValue)VisitStat_functionCall(context.stat_functionCall());
                if (value != null)
                {
                    return(value);
                }
                else
                {
                    //Return a null value.
                    return(new AlgoValue()
                    {
                        Type = AlgoValueType.Null,
                        Value = null,
                    });
                }
            }
            else if (context.array() != null)
            {
                //LIST.

                //Evaluate all list items as expressions.
                List <AlgoValue> list = new List <AlgoValue>();
                foreach (var item in context.array().value())
                {
                    list.Add((AlgoValue)VisitValue(item));
                }

                //Return as a single value.
                return(new AlgoValue()
                {
                    Type = AlgoValueType.List,
                    Value = list
                });
            }
            else if (context.@object() != null)
            {
                //OBJECT DEFINITION

                //Create a new object.
                AlgoObject toReturn = new AlgoObject();

                //Anything to enumerate?
                if (context.@object().obj_child_definitions() == null)
                {
                    //Nope.
                    return(new AlgoValue()
                    {
                        Type = AlgoValueType.Object,
                        Value = toReturn
                    });
                }

                //Enumerate through all the define statements and evaluate their values.
                foreach (var value in context.@object().obj_child_definitions().obj_vardefine())
                {
                    //Check if the variable already exists.
                    if (toReturn.ObjectScopes.VariableExists(value.IDENTIFIER().GetText()))
                    {
                        Error.Fatal(context, "The variable with name '" + value.IDENTIFIER().GetText() + "' is defined twice or more in an object.");
                        return(null);
                    }

                    //Evaluate the value on the right.
                    AlgoValue evaluated = (AlgoValue)VisitExpr(value.expr());

                    //Add the variable to scope.
                    toReturn.ObjectScopes.AddVariable(value.IDENTIFIER().GetText(), evaluated);
                }

                //Enumerate through all functions and define them.
                foreach (var value in context.@object().obj_child_definitions().obj_funcdefine())
                {
                    //Check if the variable already exists.
                    if (toReturn.ObjectScopes.VariableExists(value.IDENTIFIER().GetText()))
                    {
                        Error.Fatal(context, "The variable with name '" + value.IDENTIFIER().GetText() + "' is defined twice or more in an object.");
                        return(null);
                    }

                    //Create a list of parameters.
                    List <string> params_ = new List <string>();
                    if (value.abstract_params() != null)
                    {
                        foreach (var param in value.abstract_params().IDENTIFIER())
                        {
                            //Check if param already exists.
                            if (params_.Contains(param.GetText()))
                            {
                                Error.Fatal(context, "The parameter with name '" + param.GetText() + "' is already defined in the function.");
                                return(null);
                            }

                            params_.Add(param.GetText());
                        }
                    }

                    //Create a function, push.
                    AlgoFunction func      = new AlgoFunction(value.statement().ToList(), params_, value.IDENTIFIER().GetText());
                    AlgoValue    funcValue = new AlgoValue()
                    {
                        Type  = AlgoValueType.Function,
                        Value = func,
                    };

                    toReturn.ObjectScopes.AddVariable(value.IDENTIFIER().GetText(), funcValue);
                }

                //Enumerate all external functions defined.
                foreach (var ext in context.@object().obj_child_definitions().obj_externdefine())
                {
                    //Get the value of the function.
                    var       loadFuncStat = ext.stat_loadFuncExt();
                    AlgoValue func         = Plugins.GetEmulatedFuncValue(loadFuncStat);

                    //Check if a variable with this name already exists.
                    if (toReturn.ObjectScopes.VariableExists(loadFuncStat.IDENTIFIER()[0].GetText()))
                    {
                        Error.Fatal(context, "A variable with the name '" + loadFuncStat.IDENTIFIER()[0].GetText() + "' already exists in this object. Cannot duplicate.");
                        return(null);
                    }

                    //Add that function to the return object.
                    toReturn.ObjectScopes.AddVariable(loadFuncStat.IDENTIFIER()[0].GetText(), func);
                }

                //Return the object.
                return(new AlgoValue()
                {
                    Type = AlgoValueType.Object,
                    Value = toReturn
                });
            }
            else
            {
                //No proper detected value type.
                Error.Fatal(context, "Unknown or invalid type given for value.");
                return(new AlgoValue()
                {
                    Type = AlgoValueType.Null,
                    Value = null
                });
            }
        }
Esempio n. 7
0
        //Set a variable within the scopes.
        //Start from deepest depth.
        public void SetVariable(string varname, AlgoValue value, ParserRuleContext context = null)
        {
            //Is it a normal variable or an object?
            if (!varname.Contains('.'))
            {
                //Finding and setting.
                for (int i = Scopes.Count - 1; i >= 0; i--)
                {
                    if (Scopes[i].Keys.Contains(varname))
                    {
                        Scopes[i][varname] = value;
                        return;
                    }
                }

                //Uncaught missing variable.
                Error.Fatal(context, "No variable found with name '" + varname + "' to set.");
            }
            else
            {
                string[] objParts = varname.Split('.');

                //Loop and get value.
                if (!VariableExists(objParts[0]))
                {
                    Error.Fatal(context, "No parent variable '" + objParts[0] + "' exists.");
                }

                AlgoValue currentObjValue = GetVariable(objParts[0]);
                if (currentObjValue.Type != AlgoValueType.Object)
                {
                    Error.Fatal(context, "Parent variable is not an object, so cannot access children.");
                }

                //Getting the deepest scope.
                AlgoObject currentObj = (AlgoObject)currentObjValue.Value;
                for (int i = 1; i < objParts.Length - 1; i++)
                {
                    //Attempt to get the child.
                    if (!currentObj.ObjectScopes.VariableExists(objParts[i]))
                    {
                        Error.Fatal(context, "A child property '" + objParts[i] + "' does not exist.");
                    }
                    currentObjValue = currentObj.ObjectScopes.GetVariable(objParts[i]);

                    //Check if it's an object.
                    if (currentObjValue.Type != AlgoValueType.Object)
                    {
                        Error.Fatal(context, "A child property '" + objParts[i] + "' is not an object, so can't access further children.");
                    }

                    //Set current object.
                    currentObj = (AlgoObject)currentObjValue.Value;
                }

                //Getting the variable referenced at the deepest scope.
                if (!currentObj.ObjectScopes.VariableExists(objParts[objParts.Length - 1]))
                {
                    Error.Fatal(context, "No variable exists at the deepest scope with name '" + objParts[objParts.Length - 1] + "'.");
                }

                //Set value of variable.
                currentObj.ObjectScopes.SetVariable(objParts[objParts.Length - 1], value);
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Evaluates a given particle, and returns the result.
        /// </summary>
        public override object VisitParticle([NotNull] algoParser.ParticleContext context)
        {
            //Get the last result of the particle before this.
            AlgoValue current = Particles.GetParticleResult();

            if (current == null)
            {
                Error.Internal("Particle chain started without setting an initial value.");
                return(null);
            }

            //Prepare an "old" scope for swapping.
            AlgoScopeCollection oldScope = null;

            //What type of particle is it?

            //CHILD VARIABLE
            if (context.IDENTIFIER() != null)
            {
                //Sub-variable. Attempt to get from the object.
                if (current.Type != AlgoValueType.Object)
                {
                    Error.Fatal(context, "Cannot access children when given variable is not an object, and has no children to access.");
                    return(null);
                }

                //Does the sub-variable exist?
                AlgoObject curObj = (AlgoObject)current.Value;
                AlgoValue  newObj = curObj.ObjectScopes.GetVariable(context.IDENTIFIER().GetText());
                if (newObj == null)
                {
                    Error.Fatal(context, "No child of the given object exists with name '" + context.IDENTIFIER().GetText() + "'.");
                    return(null);
                }

                //Yes, set result and return.
                Particles.SetParticleInput(newObj);
                return(null);
            }

            //ARRAY ACCESS
            else if (context.array_access_particle() != null)
            {
                var aap = context.array_access_particle();

                //Indexing.
                //For each index, iterate over.
                AlgoValue currentLV = current;
                foreach (var index in aap.literal_params().expr())
                {
                    //Is the current list value a list?
                    if (currentLV.Type != AlgoValueType.List)
                    {
                        Error.Fatal(context, "Cannot index into variable that is not a list or indexable object.");
                        return(null);
                    }

                    //Need to switch scopes for evaluating indexes?
                    if (Particles.funcArgumentScopes != null)
                    {
                        oldScope = Scopes;
                        Scopes   = Particles.funcArgumentScopes;
                    }

                    //Evaluate the expression.
                    AlgoValue indexVal = (AlgoValue)VisitExpr(index);

                    //Back to normal.
                    if (Particles.funcArgumentScopes != null)
                    {
                        Scopes = oldScope;
                    }

                    //Valid?
                    if (indexVal.Type != AlgoValueType.Integer)
                    {
                        Error.Fatal(context, "Index value provided is not an integer. Indexes must be whole integer values.");
                        return(null);
                    }

                    //Is the index outside of the bounds of the array?
                    if (((List <AlgoValue>)currentLV.Value).Count <= (BigInteger)indexVal.Value)
                    {
                        Error.Fatal(context, "Index provided is outside the bounds of the array.");
                        return(null);
                    }

                    //Index into it, set the current value.
                    currentLV = ((List <AlgoValue>)currentLV.Value)[(int)((BigInteger)indexVal.Value)];
                }

                //Set result.
                Particles.SetParticleInput(currentLV);
                return(null);
            }

            //CHILD FUNCTION
            else if (context.functionCall_particle() != null)
            {
                //Function call.
                if (current.Type != AlgoValueType.Object)
                {
                    Error.Fatal(context, "Cannot call a child function on a value with no children (given value was not an object).");
                    return(null);
                }

                //Get the child, see if it's a function.
                AlgoObject thisObj   = current.Value as AlgoObject;
                string     funcName  = context.functionCall_particle().IDENTIFIER().GetText();
                AlgoValue  childFunc = thisObj.ObjectScopes.GetVariable(funcName);
                if (childFunc == null || (childFunc.Type != AlgoValueType.Function && childFunc.Type != AlgoValueType.EmulatedFunction))
                {
                    Error.Fatal(context, "No child function exists with name '" + funcName + "'.");
                    return(null);
                }

                //Set the particle result as the function value, call the function call particle.
                Particles.SetParticleInput(childFunc);
                var result = VisitFunctionCall_particle(context.functionCall_particle());
                if (result == null)
                {
                    Particles.ResetParticleInput(); //Returned no result.
                }
                else
                {
                    //A result came back, set input for the next particle.
                    Particles.SetParticleInput((AlgoValue)result);
                }

                return(null);
            }
            else
            {
                //Unrecognized!
                Error.Internal("Unrecognized particle type to parse, implementation either unfinished or incorrect.");
                return(null);
            }
        }
Esempio n. 9
0
        //When a function is called.
        public override object VisitStat_functionCall([NotNull] algoParser.Stat_functionCallContext context)
        {
            //If there are particles, get the last value.
            AlgoValue currentVal = null; bool isLibraryTopLevelCall = false;

            if (context.IDENTIFIER() != null)
            {
                //Is the identifier a library and has no particles?
                if (!Scopes.VariableExists(context.IDENTIFIER().GetText()) &&
                    Scopes.LibraryExists(context.IDENTIFIER().GetText()) &&
                    (context.particle() == null || context.particle().Length == 0))
                {
                    //Library top level call, so don't evaluate like normal particles.
                    isLibraryTopLevelCall = true;

                    //Just get the very last function like a normal variable, but from the library.
                    string libName = context.IDENTIFIER().GetText();
                    string name    = context.functionCall_particle().IDENTIFIER().GetText();
                    var    lib     = Scopes.GetLibrary(libName);

                    if (!lib.VariableExists(name))
                    {
                        Error.Fatal(context, "No variable named '" + name + "' exists in library '" + libName + "'.");
                        return(null);
                    }

                    currentVal = lib.GetVariable(name);
                }
                else
                {
                    //Not a library top level call, so execute like a normal particle block.
                    currentVal = Particles.ParseParticleBlock(this, context, context.IDENTIFIER(), context.particle());
                }
            }
            else
            {
                //No particles, just grab the value as an identifier.
                string name = context.functionCall_particle().IDENTIFIER().GetText();
                if (!Scopes.VariableExists(name))
                {
                    Error.Fatal(context, "No function exists with name '" + name + "'.");
                    return(null);
                }

                currentVal = Scopes.GetVariable(name);
            }

            //Attempt to execute the final function on the result.
            if (context.IDENTIFIER() == null || isLibraryTopLevelCall)
            {
                //Visit and execute THIS value, not a child value (this was a straight normal call).
                Particles.SetParticleInput(currentVal);
                return(VisitFunctionCall_particle(context.functionCall_particle()));
            }
            else
            {
                //There were particles, visit and execute CHILD value.
                if (currentVal.Type != AlgoValueType.Object)
                {
                    Error.Fatal(context, "Cannot call a child function on a value with no children (given value was not an object).");
                    return(null);
                }

                //Get the child, see if it's a function.
                AlgoObject thisObj   = currentVal.Value as AlgoObject;
                string     funcName  = context.IDENTIFIER().GetText();
                AlgoValue  childFunc = thisObj.ObjectScopes.GetVariable(funcName);
                if (childFunc == null || (childFunc.Type != AlgoValueType.Function && childFunc.Type != AlgoValueType.EmulatedFunction))
                {
                    Error.Fatal(context, "No child function exists with name '" + funcName + "'.");
                    return(null);
                }

                //Set the particle result as the function value, call the function call particle.
                Particles.SetParticleInput(childFunc);
                return(VisitFunctionCall_particle(context.functionCall_particle()));
            }
        }