// =================================================================== // CODE GENERATION FUNCTIONS // ------------------------------------------------------------------- /// Generate the enable block header code. /// /// @param indentSize The indentation needed for the class definition. /// @return The formatted header code for the if-statement. /// public override string GenerateHeader(int indentSize) { var indent = ToIndent(indentSize); var result = new StringBuilder(indent, 1024); result.Append("if("); var len = myEnablePorts.Length; for (int i = 0; i < len; ++i) { if (myEnableCode[i] != null) { result.Append(myEnableCode[i].GenerateBody(0)); } else { result.Append(GetNameFor(GraphInfo.GetProducerPort(myEnablePorts[i]))); } if (i < len - 1) { result.Append(" || "); } } result.Append(") {\n"); return(result.ToString()); }
// ------------------------------------------------------------------------- /// Returns list of nodes required for code generation /// /// @param node Root node from which the code will be generated. /// CodeBase[] GetFunctionBodyParts(iCS_EditorObject node) { var code = new List <CodeBase>(); node.ForEachChildRecursiveDepthFirst( vsObj => { if (Context.IsInError(vsObj.InstanceId)) { Debug.LogWarning("iCanScript: Code not generated for node in Error: " + VSObject.FullName); return; } if (IsFieldOrPropertyGet(vsObj)) { code.Add(new GetPropertyCallDefinition(vsObj, this)); } else if (IsFieldOrPropertySet(vsObj)) { code.Add(new SetPropertyCallDefinition(vsObj, this)); } else if (vsObj.IsKindOfFunction && !vsObj.IsConstructor) { code.Add(new FunctionCallDefinition(vsObj, this)); } else if (vsObj.IsConstructor && !AreAllInputsConstant(vsObj)) { code.Add(new ConstructorDefinition(vsObj, this)); } else if (vsObj.IsInlineCode) { code.Add(new InlineCodeDefinition(vsObj, this)); } else if (vsObj.IsTriggerPort) { if (ShouldGenerateTriggerCode(vsObj)) { var triggerSet = new TriggerSetDefinition(vsObj, this); var triggerVariable = new TriggerVariableDefinition(vsObj, this, triggerSet); code.Add(triggerVariable); code.Add(triggerSet); } } else if (vsObj.IsOutDataPort && vsObj.ParentNode == node) { var portVariable = Context.GetCodeFor(vsObj); if (portVariable != null) { var producerPort = GraphInfo.GetProducerPort(vsObj); if (producerPort != null) { var consumerCode = new VariableReferenceDefinition(vsObj, this); var producerCode = new VariableReferenceDefinition(producerPort, this); code.Add(new AssignmentDefinition(this, consumerCode, producerCode)); } } } } ); return(code.ToArray()); }
// =================================================================== // COMMON INTERFACE FUNCTIONS // ------------------------------------------------------------------- /// Resolves any dependencies that this code has. public override void ResolveDependencies() { // Optimize input parameters to fields/properties for (int i = 0; i < myParameters.Length; ++i) { var code = myParameters[i]; var producerCode = OptimizeInputParameter(code, myParent); if (producerCode != null) { myParameters[i] = producerCode; producerCode.Parent = myParent; } myParameters[i].ResolveDependencies(); } // -- Optimize target port from get fields/properties. -- if (!IsStatic()) { var targetPort = GraphInfo.GetTargetPort(VSObject); if (targetPort != null) { var producerPort = GraphInfo.GetProducerPort(targetPort); var producerCode = Context.GetCodeFor(producerPort.ParentNode); if (producerCode is GetPropertyCallDefinition) { if (producerPort.ConsumerPorts.Length == 1) { myTargetCode = producerCode; producerCode.Parent.Remove(producerCode); producerCode.Parent = myParent; } } } } // Ask output objects to resolve their own child dependencies. foreach (var v in myOutputVariables) { v.ResolveDependencies(); } if (myReturnVariable != null) { myReturnVariable.ResolveDependencies(); // Return variable relocation var returnParent = GetProperParentForProducerPort(myReturnVariable); if (returnParent != null && returnParent != myParent) { var returnPort = myReturnVariable.VSObject; if (returnParent is ClassDefinition) { var v = new VariableDefinition(returnPort, returnParent, AccessSpecifier.Private, ScopeSpecifier.NonStatic); returnParent.AddVariable(v); myReturnVariable = null; v.ResolveDependencies(); } } } }
// ------------------------------------------------------------------- /// Build information for parameters. void BuildParameterInformation() { var parameters = GetParameters(VSObject); var pLen = parameters.Length; myParameters = new CodeBase[pLen]; foreach (var p in parameters) { int idx = p.PortIndex; if (idx >= parameters.Length) { VSObject.ForEachChildPort( dp => { Debug.Log("Index: " + dp.PortIndex + " => " + dp.FullName); } ); } if (p.IsInputPort) { var producerPort = GraphInfo.GetProducerPort(p); if (producerPort != null && producerPort != p) { myParameters[idx] = new FunctionCallParameterDefinition(p, this, p.RuntimeType); } else { // Generate class variable for UnityEngine.Objects var portType = p.RuntimeType; if (iCS_Types.IsA <UnityEngine.Object>(portType)) { myParameters[idx] = new FunctionCallParameterDefinition(p, this, p.RuntimeType); var typeDef = GetClassDefinition(); var v = new VariableDefinition(p, typeDef, AccessSpecifier.Public, ScopeSpecifier.NonStatic); typeDef.AddVariable(v); } else { myParameters[idx] = new ConstantDefinition(p, this); } } } else { myParameters[idx] = new FunctionCallOutParameterDefinition(p, this); } } }
// =================================================================== // CODE GENERATION FUNCTIONS // ------------------------------------------------------------------- /// Generate the parameter code. /// /// @param indentSize The indentation needed for the class definition. /// @return The formatted body code for the parameter. /// public override string GenerateBody(int indentSize) { var producerPort = GraphInfo.GetProducerPort(VSObject); var result = new StringBuilder(GetNameFor(producerPort), 64); if (myType != null) { var desiredTypeName = ToTypeName(myType); var producerType = Context.GetRuntimeTypeFor(producerPort); if (!iCS_Types.IsA(myType, producerType)) { result.Append(" as "); result.Append(desiredTypeName); } } return(result.ToString()); }
// ------------------------------------------------------------------------- /// Generates the function call prefix code fragment. /// /// @param memberInfo The member information of the function to call. /// @param node Visual script function call node. /// @return The code fragment to prepend to the function call. /// protected string FunctionCallPrefix(iCS_EditorObject node) { var result = new StringBuilder(32); if (IsStatic()) { if (!GraphInfo.IsLocalType(VSObject)) { result.Append(ToTypeName(node.RuntimeType)); result.Append("."); } } else { var thisPort = GraphInfo.GetTargetPort(node); if (thisPort != null) { // result.Append(GetExpressionFor(thisPort)); // result.Append("."); // -- Prepend target code producer if optimized. -- if (myTargetCode != null) { result.Append(myTargetCode.GenerateBody(0)); result.Append("."); return(result.ToString()); } var producerPort = GraphInfo.GetProducerPort(thisPort); var producerType = Context.GetRuntimeTypeFor(producerPort); var producerCode = Context.GetCodeFor(producerPort); if (producerCode is FunctionDefinitionParameter) { var producerPortName = GetNameFor(producerPort); if (producerPortName == null || producerPortName == "null") { Debug.LogWarning("producer port is null: " + producerPort.CodeName); } result.Append(GetNameFor(producerPort)); result.Append("."); } else if (producerCode is LocalVariableDefinition) { var producerPortName = Parent.GetLocalVariableName(producerPort); if (producerPortName == null || producerPortName == "null") { Debug.LogWarning("producer port is null: " + producerPort.CodeName); } result.Append(producerPortName); result.Append("."); } else if (producerPort.IsOwner) { if (producerType == typeof(Transform)) { result.Append("transform."); } else if (producerType == typeof(GameObject)) { result.Append("gameObject."); } } else if (producerPort != thisPort) { var desiredType = VSObject.RuntimeType; var desiredTypeName = ToTypeName(desiredType); var isUpcastNeeded = producerType != desiredType && iCS_Types.IsA(producerType, desiredType); if (isUpcastNeeded) { result.Append("("); } var producerNode = producerPort.ParentNode; if (producerNode.IsConstructor) { result.Append(GetNameFor(producerNode)); } else { result.Append(GetNameFor(producerPort)); } if (isUpcastNeeded) { result.Append(" as "); result.Append(desiredTypeName); result.Append(")"); } result.Append("."); } } } return(result.ToString()); }
// ------------------------------------------------------------------- /// Resolves code dependencies. public override void ResolveDependencies() { // -- Ask our children to resolve their dependencies. -- base.ResolveDependencies(); // -- Don't generate code if all enables are false. -- if (ControlFlow.IsAllEnablesAlwaysFalse(myEnablePorts)) { Parent.Remove(this); return; } // -- Merge with parent if one of the enables is always true. -- if (ControlFlow.IsAtLeastOneEnableAlwaysTrue(myEnablePorts)) { (Parent as ExecutionBlockDefinition).Replace(this, myExecutionList); return; } // -- Determine if enable producers where optimized out. -- var enableLen = myEnablePorts.Length; bool hasProducer = false; for (int i = 0; i < enableLen; ++i) { var enable = myEnablePorts[i]; var producerPort = GraphInfo.GetProducerPort(enable); if (FindCodeBase(producerPort) != null || producerPort.ParentNode.IsConstructor) { hasProducer = true; break; } } if (!hasProducer) { (Parent as ExecutionBlockDefinition).Replace(this, myExecutionList); return; } // -- Reposition code for simple trigger->enable -- CodeBase commonParent = null; if (AreAllInSameExecutionContext(out commonParent)) { var parentAsExecBlock = commonParent as ExecutionBlockDefinition; if (AreAllProducersTriggers()) { if (parentAsExecBlock != null) { Debug.Log("Removing enable for=> " + myEnablePorts[0].FullName); parentAsExecBlock.Replace(this, myExecutionList); return; } } else if (parentAsExecBlock != null) { if (Parent != parentAsExecBlock) { Parent.Remove(this); parentAsExecBlock.AddExecutable(this); } } } // -- Determine best enable order for code optimization. -- if (enableLen > 1) { for (int i = 0; i < enableLen; ++i) { var enable = myEnablePorts[i]; if (enable.IsTheOnlyConsumer && !enable.SegmentProducerPort.IsTriggerPort) { if (i != 0) { var t = myEnablePorts[0]; myEnablePorts[0] = enable; myEnablePorts[i] = t; } break; } } } // -- Verify if we can optimize parameter ports. -- myEnableCode[0] = Context.GetCodeFor(GraphInfo.GetProducerPort(myEnablePorts[0])); if (myEnableCode[0] != null) { myEnableCode[0] = OptimizeInputParameter(myEnableCode[0], myParent); if (myEnableCode[0] != null) { myEnableCode[0].Parent = this; } } }