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(); }); }
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"); }
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(); }