-
Notifications
You must be signed in to change notification settings - Fork 635
/
ScopedIf.cs
132 lines (118 loc) · 5.43 KB
/
ScopedIf.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using System.Collections.Generic;
using System.Linq;
using CoreNodeModels.Properties;
using Dynamo.Engine.CodeGeneration;
using Dynamo.Graph.Nodes;
using Dynamo.Graph.Nodes.CustomNodes;
using Newtonsoft.Json;
using ProtoCore;
using ProtoCore.AST.AssociativeAST;
using CodeBlockNode = ProtoCore.AST.AssociativeAST.CodeBlockNode;
using LanguageBlockNode = ProtoCore.AST.AssociativeAST.LanguageBlockNode;
namespace CoreNodeModels.Logic
{
[NodeName("ScopeIf"), NodeCategory(BuiltinNodeCategories.LOGIC),
NodeDescription("ScopeIfDescription", typeof(Resources)), IsDesignScriptCompatible]
[AlsoKnownAs("DSCoreNodesUI.Logic.ScopedIf")]
[OutPortTypes("Function")]
public class ScopedIf : ScopedNodeModel
{
[JsonConstructor]
private ScopedIf(IEnumerable<PortModel> inPorts, IEnumerable<PortModel> outPorts) : base(inPorts, outPorts) { }
public ScopedIf() : base()
{
InPorts.Add(new PortModel(PortType.Input, this, new PortData("test", Resources.PortDataTestBlockToolTip)));
InPorts.Add(new PortModel(PortType.Input, this, new PortData("true", Resources.PortDataTrueBlockToolTip)));
InPorts.Add(new PortModel(PortType.Input, this, new PortData("false", Resources.PortDataFalseBlockToolTip)));
OutPorts.Add(new PortModel(PortType.Output, this, new PortData("result", Resources.PortDataResultToolTip)));
RegisterAllPorts();
}
private List<AssociativeNode> GetAstsForBranch(int branch, List<AssociativeNode> inputAstNodes, bool verboseLogging, AstBuilder builder)
{
// Get all upstream nodes and then remove nodes that are not
var nodes = GetInScopeNodesForInport(branch, false).Where(n => !(n is Symbol));
nodes = ScopedNodeModel.GetNodesInTopScope(nodes);
// The second parameter, isDeltaExecution, is set to false so that
// all AST nodes will be added to this IF graph node instead of
// adding to the corresponding graph node.
var allAstNodes = builder.CompileToAstNodes(nodes, CompilationContext.None, verboseLogging);
var astNodes = allAstNodes.SelectMany(t => t.Item2).ToList();
astNodes.Add(AstFactory.BuildReturnStatement(inputAstNodes[branch]));
return astNodes;
}
/// <summary>
/// Specify if upstream nodes that connected to specified inport should
/// be compiled in the scope or not.
/// </summary>
/// <param name="portIndex"></param>
/// <returns></returns>
protected override bool IsScopedInport(int portIndex)
{
return portIndex == 1 || portIndex == 2;
}
public override IEnumerable<AssociativeNode> BuildOutputAstInScope(List<AssociativeNode> inputAstNodes, bool verboseLogging, AstBuilder builder)
{
// This function will compile IF node to the following format:
//
// cond = ...;
// v = [Imperative]
// {
// if (cond) {
// return = [Associative] {
// ...
// }
// }
// else {
// return = [Associative] {
// ...
// }
// }
// }
//
var astsInTrueBranch = GetAstsForBranch(1, inputAstNodes, verboseLogging, builder);
var astsInFalseBranch = GetAstsForBranch(2, inputAstNodes, verboseLogging, builder);
// if (cond) {
// return = [Associative] {...}
// }
var ifBlock = new LanguageBlockNode
{
codeblock = new LanguageCodeBlock(Language.Associative),
CodeBlockNode = new CodeBlockNode { Body = astsInTrueBranch }
};
var ifBranch = AstFactory.BuildReturnStatement(ifBlock).ToImperativeAST();
// else {
// return = [Associative] { ... }
// }
var elseBlock = new LanguageBlockNode
{
codeblock = new LanguageCodeBlock(Language.Associative),
CodeBlockNode = new CodeBlockNode { Body = astsInFalseBranch }
};
var elseBranch = AstFactory.BuildReturnStatement(elseBlock).ToImperativeAST();
var ifelseStatement = new ProtoCore.AST.ImperativeAST.IfStmtNode()
{
IfExprNode = inputAstNodes[0].ToImperativeAST(),
IfBody = new List<ProtoCore.AST.ImperativeAST.ImperativeNode> { ifBranch },
ElseBody = new List<ProtoCore.AST.ImperativeAST.ImperativeNode> { elseBranch }
};
// thisVariable = [Imperative]
// {
// ...
// }
var outerBlock = new LanguageBlockNode
{
codeblock = new LanguageCodeBlock(Language.Imperative),
CodeBlockNode = new ProtoCore.AST.ImperativeAST.CodeBlockNode
{
Body = new List<ProtoCore.AST.ImperativeAST.ImperativeNode> { ifelseStatement }
}
};
var thisVariable = GetAstIdentifierForOutputIndex(0);
var assignment = AstFactory.BuildAssignment(thisVariable, outerBlock);
return new AssociativeNode[]
{
assignment
};
}
}
}