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