//When a variable is first defined. public override object VisitStat_define([NotNull] algoParser.Stat_defineContext context) { //Get the name of the identifier/objtext. string name = Particles.StitchVariableName(context, context.IDENTIFIER().GetText(), context.particle()); //Evaluate the expression on the right side of the define. AlgoValue value = (AlgoValue)VisitExpr(context.expr()); //Create the variable at the current scope. Scopes.AddVariable(name, value); return(null); }
//When an external or internal plugin library function is loaded. public override object VisitStat_loadFuncExt([NotNull] algoParser.Stat_loadFuncExtContext context) { //Get the value of the function. AlgoValue func = Plugins.GetEmulatedFuncValue(context); //Check if a variable with the supplied name already exists in scope. if (Scopes.VariableExists(context.IDENTIFIER()[0].GetText())) { Error.Fatal(context, "A variable with the name '" + context.IDENTIFIER()[0].GetText() + "' already exists, can't redefine it."); return(null); } //Add to scope. Scopes.AddVariable(context.IDENTIFIER()[0].GetText(), func); return(null); }
//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); }
//When a function is defined. public override object VisitStat_functionDef([NotNull] algoParser.Stat_functionDefContext context) { //Does a variable with this name already exist? if (Scopes.VariableExistsLowest(context.IDENTIFIER().GetText())) { Error.Fatal(context, "A variable with this name already exists, cannot create function with this name."); return(null); } //Getting parameters. List <string> params_ = new List <string>(); if (context.abstract_params() != null) { foreach (var param in context.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()); } } //No, it doesn't exist. Define it. AlgoFunction func = new AlgoFunction(context.statement().ToList(), params_, context.IDENTIFIER().GetText()); AlgoValue funcValue = new AlgoValue() { Type = AlgoValueType.Function, Value = func }; //Add to scope. Scopes.AddVariable(context.IDENTIFIER().GetText(), funcValue); return(null); }
/// <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); } }
//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); }