//When a library is defined. public override object VisitStat_library([NotNull] algoParser.Stat_libraryContext context) { //Check if a library with this name already exists. if (Scopes.LibraryExists(context.IDENTIFIER().GetText())) { Error.Warning(context, "A library with the name '" + context.IDENTIFIER().GetText() + "' has already been loaded, so loading was ignored."); } //Switch the current scope out for a new "library" scope. AlgoScopeCollection oldScope = Scopes; Scopes = new AlgoScopeCollection(); //Evaluate the contents of the library. foreach (var statement in context.statement()) { VisitStatement(statement); } //Save the new scope, and switch back to the old one. AlgoScopeCollection libScope = Scopes; Scopes = oldScope; //Add the library scope to the library list. Scopes.AddLibrary(context.IDENTIFIER().GetText(), libScope); return(null); }
//Add a library. public void AddLibrary(string name, AlgoScopeCollection library) { //Checking if library is a dupe. if (Libraries.ContainsKey(name)) { Error.FatalNoContext("A library with the name '" + name + "' already exists in this scope, can't define it again."); return; } //Not a dupe, add it. Libraries.Add(name, library); }
//Runs an Algo script, given a file path. public void RunAlgoScript(string path, string newScopeName = "") { //Read the entire text file into a lexer and tokens. string input = File.ReadAllText(path); var chars = new AntlrInputStream(input); var lexer = new algoLexer(chars); var tokens = new CommonTokenStream(lexer); //Parse the file. var parser = new algoParser(tokens); parser.BuildParseTree = true; var tree = parser.compileUnit(); //Set the currently loaded file. FileInfo fi = new FileInfo(path); string oldFile = AlgoRuntimeInformation.FileLoaded; AlgoRuntimeInformation.FileLoaded = fi.Name; //If this is being placed in a separate scope, switch out now. AlgoScopeCollection oldScope = null; if (newScopeName != "") { oldScope = Scopes; Scopes = new AlgoScopeCollection(); } //Visit this tree, and fully execute. VisitCompileUnit(tree); //Set the currently loaded file back. AlgoRuntimeInformation.FileLoaded = oldFile; //If it was executed in a separate scope, save as a library with this name. if (newScopeName != "") { AlgoScopeCollection importScope = Scopes; Scopes = oldScope; Scopes.AddLibrary(newScopeName, importScope); } }
/// <summary> /// Get a result from this particle block (null if none). /// </summary> public static AlgoValue ParseParticleBlock(algoVisitor visitor, ParserRuleContext ctx, ITerminalNode firstIdentifier, algoParser.ParticleContext[] particleContext) { //Is it a user created variable? if (algoVisitor.Scopes.VariableExists(firstIdentifier.GetText())) { //Yes, get the value and evaluate the particles. var value = algoVisitor.Scopes.GetVariable(firstIdentifier.GetText()); if (particleContext != null) { //Set particle input as the current value. SetParticleInput(value); foreach (var particle in particleContext) { //Evaluate all the particles, get the final result. visitor.VisitParticle(particle); } value = GetParticleResult(); } //Return the value. return(value); } //Is it a library? else if (algoVisitor.Scopes.LibraryExists(firstIdentifier.GetText())) { //If it's a library, you've got to have a particle access. if (particleContext == null || particleContext.Length == 0) { Error.Fatal(ctx, "Cannot use a library directly as a value."); return(null); } //It's a library, prepare for a scope switch. var scopes_local = algoVisitor.Scopes.GetLibrary(firstIdentifier.GetText()); AlgoScopeCollection oldScope = algoVisitor.Scopes; //First, get the first particle to set as the particle input. var toEval = particleContext[0]; AlgoValue particleVal = null; //Is the first particle an identifier? if (toEval.IDENTIFIER() != null) { particleVal = scopes_local.GetVariable(toEval.IDENTIFIER().GetText()); if (particleVal == null) { Error.Fatal(toEval, "No variable exists in library '" + firstIdentifier.GetText() + "' named '" + toEval.IDENTIFIER().GetText() + "'."); return(null); } } else if (toEval.functionCall_particle() != null) { //Not an identifier, a function. Attempt to call with the correct scopes. SetFunctionArgumentScopes(algoVisitor.Scopes); algoVisitor.Scopes = scopes_local; var funcParticle = toEval.functionCall_particle(); //Attempt to get the function from the library. if (!scopes_local.VariableExists(funcParticle.IDENTIFIER().GetText())) { Error.Fatal(funcParticle, "No function exists named '" + funcParticle.IDENTIFIER().GetText() + " in library '" + firstIdentifier.GetText() + "'."); return(null); } //Is it a valid function? var funcVal = scopes_local.GetVariable(funcParticle.IDENTIFIER().GetText()); if (funcVal.Type != AlgoValueType.EmulatedFunction && funcVal.Type != AlgoValueType.Function) { Error.Fatal(funcParticle, "Cannot call a value that is not a function ('" + funcParticle.IDENTIFIER().GetText() + " in library '" + firstIdentifier.GetText() + "')."); return(null); } SetParticleInput(funcVal); var returned = visitor.VisitFunctionCall_particle(toEval.functionCall_particle()); if (returned != null) { particleVal = (AlgoValue)returned; } else { particleVal = null; } //Reset scopes. algoVisitor.Scopes = oldScope; ResetFunctionArgumentScopes(); ResetParticleInput(); } else { //Not a function call or child. Error.Fatal(toEval, "Cannot index directly into a library."); return(null); } //Do more particle values need to be gathered? if (particleContext.Length > 1) { //If particle value is null, throw an error. if (particleVal == null) { Error.Fatal(toEval, "No value returned to perform further operations on."); return(null); } //Swap out the scopes, set the argument evaluation scope. SetFunctionArgumentScopes(algoVisitor.Scopes); SetParticleInput(particleVal); algoVisitor.Scopes = scopes_local; //Execute all the particles past the first one. for (int i = 1; i < particleContext.Length; i++) { visitor.VisitParticle(particleContext[i]); particleVal = GetParticleResult(); } //Switch back to the original scope, reset the arg eval scope. ResetFunctionArgumentScopes(); ResetParticleInput(); algoVisitor.Scopes = oldScope; } return(particleVal); } else { Error.Fatal(ctx, "No variable or library exists with name '" + firstIdentifier.GetText() + "'."); return(null); } }
/// <summary> /// Deletes the scopes to evaluate function arguments for particles (uses current instead). /// </summary> public static void ResetFunctionArgumentScopes() { funcArgumentScopes = null; }
/// <summary> /// Sets the scopes to evaluate function arguments for particles. /// </summary> public static void SetFunctionArgumentScopes(AlgoScopeCollection scopes) { funcArgumentScopes = scopes; }
/// <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); } }
/// <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); } }