예제 #1
0
        /// <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)
        {
            // Get variable
            IDeclaration variable = context.GetDeclaration(VariableName);

            // Check variable was found
            if (variable == null)
            {
                context.ErrorList.Add(new CompilerError($"Variable '{VariableName}' was not defined",
                                                        ErrorType.NotDefined, ErrorToken, FileName));
                return(Enumerable.Empty <Block>());
            }

            // Try as stack variable
            StackValue stackValue = variable as StackValue;

            if (stackValue != null && stackValue.StackSpace == 1)
            {
                Operator.TestCompatible(stackValue.Type, context, FileName, ErrorToken);

                switch (Operator)
                {
                case AssignOperator.Equals:
                    return(stackValue.CreateVariableAssignment(context, Value));

                case AssignOperator.AddEquals:
                    return(stackValue.CreateVariableIncrement(context, Value));

                case AssignOperator.MinusEquals:
                    return(stackValue.CreateVariableIncrement(context, new UnaryExpression(Value, UnaryOperator.Minus, FileName,
                                                                                           ErrorToken)));

                case AssignOperator.DotEquals:
                    return(stackValue.CreateVariableAssignment(context, new CompoundExpression(CompoundOperator.Concat,
                                                                                               new LookupExpression(stackValue, FileName, ErrorToken), Value, FileName, ErrorToken)));

                case AssignOperator.PlusPlus:
                    return(new[] { stackValue.CreateVariableIncrement(1) });

                case AssignOperator.MinusMinus:
                    return(new[] { stackValue.CreateVariableIncrement(-1) });

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            // Try as global variable
            GlobalVarDeclaration globalVarDeclaration = variable as GlobalVarDeclaration;

            if (globalVarDeclaration != null)
            {
                Operator.TestCompatible(globalVarDeclaration.Type, context, FileName, ErrorToken);

                switch (Operator)
                {
                case AssignOperator.Equals:
                    return(new BlockBuilder(BlockSpecs.SetVariableTo, context)
                           .AddParam(VariableName)
                           .AddParam(Value, globalVarDeclaration.Type)
                           .Create());

                case AssignOperator.AddEquals:
                    return(new BlockBuilder(BlockSpecs.ChangeVarBy, context)
                           .AddParam(VariableName)
                           .AddParam(Value)
                           .Create());

                case AssignOperator.MinusEquals:
                    return(new BlockBuilder(BlockSpecs.ChangeVarBy, context)
                           .AddParam(VariableName)
                           .AddParam(new UnaryExpression(Value, UnaryOperator.Minus, FileName, ErrorToken))
                           .Create());

                case AssignOperator.DotEquals:
                    return(new BlockBuilder(BlockSpecs.SetVariableTo, context)
                           .AddParam(VariableName).AddParam(
                               new CompoundExpression(CompoundOperator.Concat,
                                                      new LookupExpression(globalVarDeclaration, FileName, ErrorToken),
                                                      Value, FileName, ErrorToken))
                           .Create());

                case AssignOperator.PlusPlus:
                    return(new BlockBuilder(BlockSpecs.ChangeVarBy, context)
                           .AddParam(VariableName)
                           .AddParam(1)
                           .Create());

                case AssignOperator.MinusMinus:
                    return(new BlockBuilder(BlockSpecs.ChangeVarBy, context)
                           .AddParam(VariableName)
                           .AddParam(-1)
                           .Create());

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            // Try as any readonly type
            if (variable is ParamDeclaration || variable is ConstDeclaration)
            {
                context.ErrorList.Add(new CompilerError($"Value '{VariableName}' is read-only", ErrorType.ValueIsReadonly,
                                                        ErrorToken, FileName));
                return(Enumerable.Empty <Block>());
            }

            // Fail
            context.ErrorList.Add(new CompilerError($"'{VariableName}' is not a variable", ErrorType.ImproperUsage,
                                                    ErrorToken, FileName));
            return(Enumerable.Empty <Block>());
        }
예제 #2
0
        /// <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);
        }