/// <summary> /// Evaluates a single function call particle, and returns the result as a value (NOT using particle manager). /// </summary> public override object VisitFunctionCall_particle([NotNull] algoParser.FunctionCall_particleContext context) { //Set up an old scope. AlgoScopeCollection oldScope = null; //Get the previous particle output. var current = Particles.GetParticleResult(); //Right length of parameters? var paramCtx = context.literal_params(); int givenNumParams = 0; if (paramCtx != null) { givenNumParams = paramCtx.expr().Length; } else if (current.Type == AlgoValueType.EmulatedFunction) { var func = ((AlgoPluginFunction)current.Value); int paramNum = func.ParameterCount; if (givenNumParams != paramNum) { Error.Fatal(context, "Invalid number of parameters for function '" + func.Name + "' (Expected " + func.ParameterCount + ", got " + givenNumParams + ")."); return(null); } } else if (current.Type == AlgoValueType.Function) { var func = ((AlgoFunction)current.Value); int paramNum = func.Parameters.Count; if (givenNumParams != paramNum) { Error.Fatal(context, "Invalid number of parameters for function '" + func.Name + "' (Expected " + func.Parameters.Count + ", got " + givenNumParams + ")."); return(null); } } //Evaluate all the parameters, in the paramScope if necessary. if (Particles.funcArgumentScopes != null) { oldScope = Scopes; Scopes = Particles.funcArgumentScopes; } List <AlgoValue> params_ = new List <AlgoValue>(); if (paramCtx != null) { foreach (var paramToEval in paramCtx.expr()) { params_.Add((AlgoValue)VisitExpr(paramToEval)); } } //Switch back scopes. if (Particles.funcArgumentScopes != null) { Scopes = oldScope; } //Depending on the type of function, execute. if (current.Type == AlgoValueType.Function) { //STANDARD FUNCTION var func = (AlgoFunction)current.Value; //Create a new scope, add the parameters to it. Scopes.AddScope(); for (int i = 0; i < params_.Count; i++) { Scopes.AddVariable(func.Parameters[i], params_[i], context); } //Running the function's body. foreach (var statement in func.Body) { AlgoValue returned = (AlgoValue)VisitStatement(statement); if (returned != null) { //Normal function, remove scope and return. Scopes.RemoveScope(); return(returned); } } //Remove the scope. Scopes.RemoveScope(); //Return nothing, no result. return(null); } else if (current.Type == AlgoValueType.EmulatedFunction) { //EMULATED FUNCTION var func = (AlgoPluginFunction)current.Value; //Attempt to evaluate, and return result. AlgoValue returned = null; try { returned = func.Function(context, params_.ToArray()); } catch (Exception e) { Error.Fatal(context, "External function returned an error, " + e.Message); return(null); } return(returned); } else { //Unsupported uncaught function type. Error.Internal("Unsupported uncaught function type detected (" + current.Type.ToString() + "), cannot execute."); return(null); } }
//An "if" statement. public override object VisitStat_if([NotNull] algoParser.Stat_ifContext context) { //Evaluate the check. AlgoValue checkReturned = (AlgoValue)VisitCheck(context.check()); bool mainCheck = AlgoComparators.GetBooleanValue(checkReturned, context); //Did it pass? If so, eval the if. if (mainCheck) { //Create scope. Scopes.AddScope(); //Evaluate the main statement body. foreach (var statement in context.statement()) { AlgoValue returned = (AlgoValue)VisitStatement(statement); if (returned != null) { Scopes.RemoveScope(); return(returned); } } //Delete scope. Scopes.RemoveScope(); //Return. return(null); } //Maincheck failed, complete all the "else if" checks if they exist. if (context.stat_elif().Length != 0) { foreach (var elseifblock in context.stat_elif()) { //Does the check pass? var checkContext = elseifblock.check(); AlgoValue elifCheckReturned = (AlgoValue)VisitCheck(checkContext); bool elseifCheck = AlgoComparators.GetBooleanValue(elifCheckReturned, context); if (elseifCheck) { //Create scope. Scopes.AddScope(); //Evaluate statements. foreach (var statement in elseifblock.statement()) { AlgoValue returned = (AlgoValue)VisitStatement(statement); if (returned != null) { Scopes.RemoveScope(); return(returned); } } //Remove scope. Scopes.RemoveScope(); //Return. return(null); } } } //Is there an else? if (context.stat_else() != null) { //Create a scope. Scopes.AddScope(); //Evaluate statements. foreach (var statement in context.stat_else().statement()) { AlgoValue returned = (AlgoValue)VisitStatement(statement); if (returned != null) { Scopes.RemoveScope(); return(returned); } } //Deleting scope. Scopes.RemoveScope(); } //Returning. return(null); }
//When a try/catch block is executed. public override object VisitStat_try_catch([NotNull] algoParser.Stat_try_catchContext context) { //Turn on execution catch mode. AlgoRuntimeInformation.CatchExceptions = true; //Loop over the statements, execute all. bool foundError = false; string errorMessage = ""; Scopes.AddScope(); foreach (var statement in context.block()[0].statement()) { //Execute statement. AlgoValue returned = null; try { returned = (AlgoValue)VisitStatement(statement); } catch (Exception e) { //C# error somewhere up the heirarchy, 90% means an error has been thrown. foundError = true; errorMessage = "Internal Language Error: " + e.Message; } //Check if an error has been found. if (AlgoRuntimeInformation.ExceptionCaught()) { //Yep, break out to the catch block. foundError = true; errorMessage = AlgoRuntimeInformation.GetExceptionMessage(); AlgoRuntimeInformation.CatchExceptions = false; break; } //If something was actually returned, return it up. if (returned != null) { AlgoRuntimeInformation.CatchExceptions = false; Scopes.RemoveScope(); return(returned); } } Scopes.RemoveScope(); //Turn off error catching. AlgoRuntimeInformation.CatchExceptions = false; //Done executing try statements, did an error come back? if (!foundError) { return(null); } //Yep, get the identifier to use for the error message, check it doesn't exist. if (Scopes.VariableExists(context.IDENTIFIER().GetText())) { Error.Fatal(context, "A variable already exists named '" + context.IDENTIFIER().GetText() + "', cannot use for catch parameter."); return(null); } //Create it, assign it the caught value. Scopes.AddScope(); Scopes.AddVariable(context.IDENTIFIER().GetText(), new AlgoValue() { Type = AlgoValueType.String, Value = errorMessage }, context); //Execute what's in the catch scope. foreach (var statement in context.block()[1].statement()) { AlgoValue returned = (AlgoValue)VisitStatement(statement); if (returned != null) { Scopes.RemoveScope(); return(returned); } } //Finished! return(null); }