/// <summary> /// Ejecuta una sentencia for /// </summary> private void ExecuteFor(SentenceFor sentence) { if (string.IsNullOrWhiteSpace(sentence.Variable)) { AddError("Cant find the variable name for loop index"); } else if (string.IsNullOrWhiteSpace(sentence.StartExpression)) { AddError("Cant find the start expression for loop index"); } else if (string.IsNullOrWhiteSpace(sentence.EndExpression)) { AddError("Cant find the end expression for loop index"); } else { VariableModel start = GetVariableValue($"StartIndex_Context{Context.Actual.ScopeIndex}", sentence.StartExpression); VariableModel end = GetVariableValue($"EndIndex_Context{Context.Actual.ScopeIndex}", sentence.EndExpression); if (start.Type != end.Type) { AddError("The types of start and end variable at for loop are distinct"); } else if (start.Type != VariableModel.VariableType.Numeric && start.Type != VariableModel.VariableType.Date) { AddError("The value of start and end at for loop must be numeric or date"); } else { VariableModel step = GetVariableValue($"StepIndex_Context{Context.Actual.ScopeIndex}", NormalizeStepExpression(sentence.StepExpression)); if (step.Value == null) { AddError("Cant find any value to step in for loop"); } else { VariableModel index = new VariableModel(sentence.Variable, start.Value); bool isPositiveStep = step.IsGreaterThan(0); // Abre un nuevo contexto Context.Add(); // Añade la variable al contexto Context.Actual.VariablesTable.Add(sentence.Variable, index.Value); // Ejecuta las sentencias while (!IsEndForLoop(index, end, isPositiveStep)) { // Ejecuta las sentencias Execute(sentence.Sentences); // Incrementa / decrementa el valor al índice (el step debería ser -x si es negativo, por tanto, siempre se suma) index.Sum(step); // y lo ajusta en el contexto Context.Actual.VariablesTable.Add(index); } // Elimina el contexto Context.Pop(); } } } }
/// <summary> /// Ejecuta el contenido de un bucle for /// </summary> private async Task ExecuteForLoopAsync(SentenceFor sentence, VariableModel start, VariableModel end, VariableModel step, CancellationToken cancellationToken) { VariableModel index = new VariableModel(sentence.Variable.Name, ConvertSymbolType(sentence.Variable.Type)); bool isPositiveStep = step.IsGreaterThan(0); // Asigna el valor inicial a la variable de índice index.Value = start.Value; // Abre un nuevo contexto Context.Add(); // Añade la variable al contexto Context.Actual.VariablesTable.Add(index); // Ejecuta las sentencias while (!IsEndForLoop(index, end, isPositiveStep) && !Stopped) { // Ejecuta las sentencias await ExecuteAsync(sentence.Sentences, cancellationToken); // Incrementa / decrementa el valor al índice (el step debería ser -x si es negativo, por tanto, siempre se suma) index.Sum(step); // y lo ajusta en el contexto Context.Actual.VariablesTable.Add(index); } // Elimina el contexto Context.Pop(); }
/// <summary> /// Carga una sentencia for /// </summary> private SentenceBase LoadSentenceFor(MLNode rootML, string pathBase) { SentenceFor sentence = new SentenceFor(); // Asigna las propiedades sentence.Variable = rootML.Attributes[TagVariable].Value; sentence.StartExpression = rootML.Attributes[TagStart].Value; sentence.EndExpression = rootML.Attributes[TagEnd].Value; sentence.StepExpression = rootML.Attributes[TagStep].Value; // Carga las sentencias sentence.Sentences.AddRange(LoadSentences(rootML.Nodes, pathBase)); // Devuelve la sentencia return(sentence); }
/// <summary> /// Ejecuta una sentencia for /// </summary> private async Task ExecuteForAsync(SentenceFor sentence, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(sentence.Variable.Name)) { AddError("Cant find the variable name for loop index"); } else if (sentence.StartExpression.Count == 0) { AddError("Cant find the start expression for loop index"); } else if (sentence.EndExpression.Count == 0) { AddError("Cant find the end expression for loop index"); } else { VariableModel start = await GetVariableValueAsync($"StartIndex_Context_{Context.Actual.ScopeIndex}", sentence.StartExpression, cancellationToken); VariableModel end = await GetVariableValueAsync($"EndIndex_Context_{Context.Actual.ScopeIndex}", sentence.EndExpression, cancellationToken); // Si se han podido evaluar las expresiones de inicio y fin if (!Stopped) { if (start.Type != end.Type) { AddError("The types of start and end variable at for loop are distinct"); } else if (start.Type != VariableModel.VariableType.Numeric && start.Type != VariableModel.VariableType.Date) { AddError("The value of start and end at for loop must be numeric or date"); } else { VariableModel step = await GetVariableValueAsync($"StepIndex_Context_{Context.Actual.ScopeIndex}", sentence.StepExpression, cancellationToken); // Asigna el valor a la expresión si no tenía if (step.Value == null) { step.Value = 1; } // Ejecuta el bucle for await ExecuteForLoopAsync(sentence, start, end, step, cancellationToken); } } } }
/// <summary> /// Transforma una sentencia for: como en python se utiliza un rango pero en un script SQL tenemos un for con inicio, fin y paso, lo transformamos /// en una sentencia while /// </summary> private void TransformFor(SentenceFor sentence) { // Añade la declaración del índice AddSentence(string.Empty); AddSentence(sentence.Variable.Name + " = " + TransformExpressions(sentence.StartExpression)); // Añade la sentencia while (con <=) AddSentence("while " + sentence.Variable.Name + " <= " + TransformExpressions(sentence.EndExpression) + ":"); // Añade las sentencias hija AddIndent(); Transform(sentence.Sentences); // Añade el step if (sentence.StepExpression.Count == 0) { AddSentence($"{sentence.Variable.Name} = {sentence.Variable.Name} + 1"); } else { AddSentence($"{sentence.Variable.Name} = {sentence.Variable.Name} + {TransformExpressions(sentence.StepExpression)}"); } // Y quita la indentación RemoveIndent(); }