public void TestVariableGet()
        {
            var visualScript = new VisualScriptAsset();

            var condition = new Property("bool", "Condition");

            visualScript.Properties.Add(condition);

            // Build blocks
            // TODO: Switch to a simple Write(variable) later, so that we don't depend on ConditionalBranchBlock for this test?
            var functionStart = new FunctionStartBlock();
            var conditionGet  = new VariableGet {
                Name = condition.Name
            };
            var conditionalBranch = new ConditionalBranchBlock();
            var writeTrue         = new CustomCodeBlock {
                Code = "System.Console.Write(true);"
            };
            var writeFalse = new CustomCodeBlock {
                Code = "System.Console.Write(false);"
            };
            var method = new Method {
                Name = "Test"
            };

            method.Blocks.Add(functionStart);
            method.Blocks.Add(conditionGet);
            method.Blocks.Add(conditionalBranch);
            method.Blocks.Add(writeTrue);
            method.Blocks.Add(writeFalse);

            // Generate slots
            foreach (var block in method.Blocks)
            {
                block.Value.GenerateSlots(block.Value.Slots, new SlotGeneratorContext());
            }

            // Build links
            method.Links.Add(new Link(functionStart, conditionalBranch));
            method.Links.Add(new Link(conditionGet.ValueSlot, conditionalBranch.ConditionSlot));
            method.Links.Add(new Link(conditionalBranch.TrueSlot, writeTrue));
            method.Links.Add(new Link(conditionalBranch.FalseSlot, writeFalse));

            visualScript.Methods.Add(method);

            // Test
            TestAndCompareOutput(visualScript, "True", testInstance =>
            {
                testInstance.Condition = true;
                testInstance.Test();
            });

            TestAndCompareOutput(visualScript, "False", testInstance =>
            {
                testInstance.Condition = false;
                testInstance.Test();
            });
        }
Example #2
0
        public void BaseTest()
        {
            Env.Variables.Add("bar", new IceKoriInt(1));
            VariableGet variableGet = new VariableGet("bar");

            Assert.IsTrue(variableGet.Reducible, "VariableGet#Reducible is error");
            Assert.AreEqual(((IceKoriInt)variableGet.Reduce(Env)).Value, 1, "VariableGet#Reduce is error");

            variableGet.Name = "shit";

            Assert.AreEqual(variableGet.Reduce(Env).GetType(), typeof(ReferenceError),
                            "VariableGet#Reduce ReferenceError");
        }
Example #3
0
        public static void GenerateCode(LoopHeader header, GeneratorContext builder)
        {
            bool requiresOuterScope = !header.IsInfinite;
            bool requiresInnerScope = header.RequiresScopeHint;

            if (requiresOuterScope)
            {
                builder.AddOp(new ScopeBegin(), header.LoopToken);
            }

            string endLabel = builder.DeclareLabel("LoopEnd");

            builder.BreakLabels.Push(endLabel);

            string continueLabel = builder.DeclareLabel("LoopContinue");

            builder.ContinueLabels.Push(continueLabel);

            string indexName = null;

            if (header.IsInfinite)
            {
                builder.SetLabelToNext(continueLabel);
            }

            else if (header.IsRange)
            {
                builder.PushIndex();
                indexName = header.Name;

                // For the end expression, don't use a variable if a literal could be used instead
                // Actually, it would be better if this were generalized to statements that translate to a single
                // op, but that is an optimization for another day.
                Op endOp;

                if (header.RangeEnd is LiteralGet end)
                {
                    endOp = new LiteralValue(end.Value);
                }

                else
                {
                    string endName = builder.GetIndexedName("end");
                    builder.AddCode(header.RangeEnd);
                    builder.AddOp(new VariableCreate(endName), header.LoopToken);

                    endOp = new VariableGet(endName);
                }

                builder.AddCode(header.RangeStart);
                builder.AddOp(new VariableCreate(indexName), header.NameToken);

                builder.SetLabelToNext(continueLabel);

                builder.AddOp(new VariableGet(indexName), header.NameToken);
                builder.AddOp(endOp);
                builder.AddOp(new GreaterThan(), header.FromToken);
                builder.AddOp(new JumpLabelConditional(endLabel), header.FromToken);
            }
            else
            {
                builder.PushIndex();
                indexName = builder.GetIndexedName("index");
                string arrayName   = builder.GetIndexedName("array");
                string countName   = builder.GetIndexedName("count");
                string currentName = header.Name ?? "@";

                builder.AddCode(header.Array);
                builder.AddOp(new VariableCreate(arrayName), header.LoopToken);

                builder.AddOp(new ArrayCount(arrayName), header.LoopToken);
                builder.AddOp(new VariableCreate(countName), header.LoopToken);

                builder.AddOp(new LiteralValue(new SprakNumber(0)), header.LoopToken);
                builder.AddOp(new VariableCreate(indexName), header.LoopToken);

                builder.AddOp(new LiteralValue(SprakUnit.Value), header.LoopToken);
                builder.AddOp(new VariableCreate(currentName), header.LoopToken);

                builder.SetLabelToNext(continueLabel);

                builder.AddOp(new VariableGet(indexName), header.LoopToken);
                builder.AddOp(new VariableGet(countName), header.LoopToken);
                builder.AddOp(new GreaterThanOrEqualTo(), header.LoopToken);
                builder.AddOp(new JumpLabelConditional(endLabel), header.LoopToken);

                builder.AddOp(new VariableGet(arrayName), header.InToken);
                builder.AddOp(new VariableGet(indexName), header.InToken);
                builder.AddOp(new ArrayElementGet(), header.InToken);
                builder.AddOp(new VariableSet(currentName), header.InToken);

                builder.AddOp(new Increment(indexName), header.InToken);
            };

            // This is used by the continue command, currently.
            header.IndexNameHint = indexName;

            if (requiresInnerScope)
            {
                builder.AddOp(new ScopeBegin(), header.LoopToken);
            }

            foreach (Expression statement in header.ParentBlockHint.Statements)
            {
                builder.AddCode(statement);
            }

            if (requiresInnerScope)
            {
                builder.AddOp(new ScopeEnd(), header.EndToken);
            }

            if (header.IsRange)
            {
                builder.AddOp(new Increment(indexName), header.EndToken);
            }

            builder.AddOp(new JumpLabel(continueLabel), header.EndToken);
            builder.SetLabelToNext(endLabel);

            if (!header.IsInfinite)
            {
                builder.PopIndex();
            }

            if (requiresOuterScope)
            {
                builder.AddOp(new ScopeEnd(), header.EndToken);
            }

            builder.BreakLabels.Pop();
            builder.ContinueLabels.Pop();
        }