/// <summary> /// Gets the translated code for the grammar structure. /// </summary> /// <returns>The translated code for the grammar structure.</returns> public IEnumerable <Block> Translate(TranslationContext context) { List <Block> output = new List <Block>(); // Create scope of loop Scope innerScope = new Scope(context.CurrentScope); TranslationContext newContext = new TranslationContext(innerScope, context); // TODO: Inbuilt foreach block optimisation // TODO: Inline foreach // Create counter variable StackValue internalCounter = context.CurrentScope.CreateStackValue(); output.AddRange(internalCounter.CreateDeclaration(1)); // Create item variable StackValue itemVar = new StackValue(Variable, VarType, false); innerScope.StackValues.Add(itemVar); output.AddRange(itemVar.CreateDeclaration(VarType.GetDefault())); List <Block> loopContents = new List <Block>(); GlobalListDeclaration globalList = context.CurrentSprite.GetList(SourceName) ?? context.Project.GetList(SourceName); StackValue arrayValue = null; if (globalList != null) { // Translate loop contents loopContents.Add(itemVar.CreateVariableAssignment(new Block(BlockSpecs.GetItemOfList, internalCounter.CreateVariableLookup(), SourceName))); } else { // Get stackvalue for array arrayValue = context.CurrentScope.Search(SourceName); if (arrayValue == null) { context.ErrorList.Add(new CompilerError($"Array '{SourceName}' is not defined", ErrorType.NotDefined, ErrorToken, FileName)); return(Enumerable.Empty <Block>()); } loopContents.Add(itemVar.CreateVariableAssignment(arrayValue.CreateArrayLookup(internalCounter.CreateVariableLookup()))); } // Increment counter loopContents.Add(internalCounter.CreateVariableIncrement(1)); // Translate loop main body foreach (IEnumerable <Block> translated in Statements.Select(x => x.Translate(newContext))) { loopContents.AddRange(translated); } // Create loop Scratch block object repeats = globalList != null ? new Block(BlockSpecs.LengthOfList, SourceName) : (object)arrayValue.StackSpace; output.Add(new Block(BlockSpecs.Repeat, repeats, loopContents.ToArray())); // Clean up scope output.AddRange(internalCounter.CreateDestruction()); output.AddRange(itemVar.CreateDestruction()); return(output); }