private string GetOrCreatePinName(NodeOutputDataPin pin) { // Return the default value of the pin type if nothing is connected if (pin == null) { return("null"); } if (variableNames.ContainsKey(pin)) { return(variableNames[pin]); } string pinName; // Special case for property setters, input name "value". // TODO: Don't rely on set_ prefix if (pin.Node is EntryNode && method.Name.StartsWith("set_")) { pinName = "value"; } else { pinName = TranslatorUtil.GetUniqueVariableName(pin.Name.Replace("<", "_").Replace(">", "_"), variableNames.Values.ToList()); } variableNames.Add(pin, pinName); return(pinName); }
/// <summary> /// Translates a class into C#. /// </summary> /// <param name="c">Class to translate.</param> /// <returns>C# code for the class.</returns> public string TranslateClass(Class c) { StringBuilder content = new StringBuilder(); foreach (Variable v in c.Variables) { content.AppendLine(TranslateVariable(v)); } foreach (Method constructor in c.Constructors) { content.AppendLine(TranslateConstructor(constructor)); } foreach (Method m in c.Methods) { content.AppendLine(TranslateMethod(m)); } StringBuilder modifiers = new StringBuilder(); modifiers.Append($"{TranslatorUtil.VisibilityTokens[c.Visibility]} "); if (c.Modifiers.HasFlag(ClassModifiers.Static)) { modifiers.Append("static "); } if (c.Modifiers.HasFlag(ClassModifiers.Abstract)) { modifiers.Append("abstract "); } if (c.Modifiers.HasFlag(ClassModifiers.Sealed)) { modifiers.Append("sealed "); } if (c.Modifiers.HasFlag(ClassModifiers.Partial)) { modifiers.Append("partial "); } string genericArguments = ""; if (c.DeclaredGenericArguments.Count > 0) { genericArguments = "<" + string.Join(", ", c.DeclaredGenericArguments) + ">"; } string generatedCode = (string.IsNullOrWhiteSpace(c.Namespace) ? CLASS_TEMPLATE_NO_NAMESPACE : CLASS_TEMPLATE) .Replace("%Namespace%", c.Namespace) .Replace("%ClassModifiers%", modifiers.ToString()) .Replace("%ClassName%", c.Name) .Replace("%GenericArguments%", genericArguments) .Replace("%SuperType%", c.SuperType.FullCodeName) .Replace("%Content%", content.ToString()); return(TranslatorUtil.FormatCode(generatedCode)); }
public void TranslateDependentPureNodes(Node node) { var sortedPureNodes = TranslatorUtil.GetSortedPureNodes(node); foreach (Node depNode in sortedPureNodes) { TranslateNode(depNode, 0); } }
private string GetPinIncomingValue(NodeInputDataPin pin) { if (pin.IncomingPin == null) { if (pin.UsesUnconnectedValue && pin.UnconnectedValue != null) { return(TranslatorUtil.ObjectToLiteral(pin.UnconnectedValue, (TypeSpecifier)pin.PinType.Value)); } else { return($"default({pin.PinType.Value.FullCodeName})"); } } else { return(GetOrCreatePinName(pin.IncomingPin)); } }
private string GetOrCreatePinName(NodeOutputDataPin pin) { // Return the default value of the pin type if nothing is connected if (pin == null) { return("null"); } if (variableNames.ContainsKey(pin)) { return(variableNames[pin]); } string pinName = TranslatorUtil.GetUniqueVariableName(pin.Name, variableNames.Values.ToList()); variableNames.Add(pin, pinName); return(pinName); }
public void TranslateCallMethodNode(CallMethodNode node) { // Wrap in try / catch if (node.HandlesExceptions) { builder.AppendLine("try"); builder.AppendLine("{"); } string temporaryReturnName = null; if (!node.IsPure) { // Translate all the pure nodes this node depends on in // the correct order TranslateDependentPureNodes(node); } // Write assignment of return values if (node.ReturnValuePins.Count == 1) { string returnName = GetOrCreatePinName(node.ReturnValuePins[0]); builder.Append($"{returnName} = "); } else if (node.OutputDataPins.Count > 1) { temporaryReturnName = TranslatorUtil.GetTemporaryVariableName(random); var returnTypeNames = string.Join(", ", node.OutputDataPins.Select(pin => pin.PinType.Value.FullCodeName)); builder.Append($"{typeof(Tuple).FullName}<{returnTypeNames}> {temporaryReturnName} = "); } // Get arguments for method call var argumentNames = GetPinIncomingValues(node.ArgumentPins); // Check whether the method is an operator and we need to translate its name // into operator symbols. Otherwise just call the method normally. if (OperatorUtil.TryGetOperatorInfo(node.MethodSpecifier, out OperatorInfo operatorInfo)) { if (operatorInfo.Unary) { if (argumentNames.Count() != 1) { throw new Exception($"Unary operator was found but did not have one argument: {node.MethodName}"); } if (operatorInfo.UnaryRightPosition) { builder.AppendLine($"{argumentNames.ElementAt(0)}{operatorInfo.Symbol};"); } else { builder.AppendLine($"{operatorInfo.Symbol}{argumentNames.ElementAt(0)};"); } } else { if (argumentNames.Count() != 2) { throw new Exception($"Binary operator was found but did not have two arguments: {node.MethodName}"); } builder.AppendLine($"{argumentNames.ElementAt(0)}{operatorInfo.Symbol}{argumentNames.ElementAt(1)};"); } } else { // Static: Write class name / target, default to own class name // Instance: Write target, default to this if (node.IsStatic) { builder.Append($"{node.DeclaringType.FullCodeName}."); } else { if (node.TargetPin.IncomingPin != null) { string targetName = GetOrCreatePinName(node.TargetPin.IncomingPin); builder.Append($"{targetName}."); } else { // Default to this builder.Append("this."); } } // Prefix with "out" / "ref" / "in" string[] argNameArray = argumentNames.ToArray(); Debug.Assert(argNameArray.Length == node.MethodSpecifier.Parameters.Count); for (int i = 0; i < node.MethodSpecifier.Parameters.Count; i++) { MethodParameterPassType passType = node.MethodSpecifier.Parameters[i].PassType; switch (passType) { case MethodParameterPassType.Out: argNameArray[i] = "out " + argNameArray[i]; break; case MethodParameterPassType.Reference: argNameArray[i] = "ref " + argNameArray[i]; break; case MethodParameterPassType.In: // Don't pass with in as it could break implicit casts. // argNameArray[i] = "in " + argNameArray[i]; break; default: break; } } // Write the method call builder.AppendLine($"{node.BoundMethodName}({string.Join(", ", argNameArray)});"); } // Assign the real variables from the temporary tuple if (node.ReturnValuePins.Count > 1) { var returnNames = GetOrCreatePinNames(node.ReturnValuePins); for (int i = 0; i < returnNames.Count(); i++) { builder.AppendLine($"{returnNames.ElementAt(i)} = {temporaryReturnName}.Item{i+1};"); } } // Set the exception to null on success if catch pin is connected if (node.HandlesExceptions) { builder.AppendLine($"{GetOrCreatePinName(node.ExceptionPin)} = null;"); } // Go to the next state if (!node.IsPure) { WriteGotoOutputPinIfNecessary(node.OutputExecPins[0], node.InputExecPins[0]); } // Catch exceptions if catch pin is connected if (node.HandlesExceptions) { string exceptionVarName = TranslatorUtil.GetTemporaryVariableName(random); builder.AppendLine("}"); builder.AppendLine($"catch (System.Exception {exceptionVarName})"); builder.AppendLine("{"); builder.AppendLine($"{GetOrCreatePinName(node.ExceptionPin)} = {exceptionVarName};"); // Set all return values to default on exception foreach (var returnValuePin in node.ReturnValuePins) { string returnName = GetOrCreatePinName(returnValuePin); builder.AppendLine($"{returnName} = default({returnValuePin.PinType.Value.FullCodeName});"); } if (!node.IsPure) { WriteGotoOutputPinIfNecessary(node.CatchPin, node.InputExecPins[0]); } builder.AppendLine("}"); } }
/// <summary> /// Translates a method to C#. /// </summary> /// <param name="method">Method to translate.</param> /// <param name="withSignature">Whether to translate the signature.</param> /// <returns>C# code for the method.</returns> public string Translate(Method method, bool withSignature) { this.method = method; // Reset state variableNames.Clear(); nodeStateIds.Clear(); pinsJumpedTo.Clear(); nextStateId = 0; builder.Clear(); random = new Random(0); nodes = TranslatorUtil.GetAllNodesInMethod(method); execNodes = TranslatorUtil.GetExecNodesInMethod(method); // Assign a state id to every non-pure node CreateStates(); // Assign jump stack state id // Write it later once we know which states get jumped to jumpStackStateId = GetNextStateId(); // Create variables for all output pins for every node CreateVariables(); // Write the signatures if (withSignature) { TranslateSignature(); } builder.AppendLine("{"); // Method start // Write a placeholder for the jump stack declaration // Replaced later builder.Append("%JUMPSTACKPLACEHOLDER%"); // Write the variable declarations TranslateVariables(); builder.AppendLine(); // Start at node after method entry if necessary (id!=0) if (method.EntryNode.OutputExecPins[0].OutgoingPin != null && GetExecPinStateId(method.EntryNode.OutputExecPins[0].OutgoingPin) != 0) { WriteGotoOutputPin(method.EntryNode.OutputExecPins[0]); } // Translate every exec node foreach (Node node in execNodes) { if (!(node is EntryNode)) { for (int pinIndex = 0; pinIndex < node.InputExecPins.Count; pinIndex++) { builder.AppendLine($"State{(nodeStateIds[node][pinIndex])}:"); TranslateNode(node, pinIndex); builder.AppendLine(); } } } // Write the jump stack if it was ever used if (pinsJumpedTo.Count > 0) { TranslateJumpStack(); builder.Replace("%JUMPSTACKPLACEHOLDER%", $"{JumpStackType} {JumpStackVarName} = new {JumpStackType}();{Environment.NewLine}"); } else { builder.Replace("%JUMPSTACKPLACEHOLDER%", ""); } builder.AppendLine("}"); // Method end string code = builder.ToString(); // Remove unused labels code = RemoveUnnecessaryLabels(code); return(code); }
public void PureTranslateLiteralNode(LiteralNode node) { string literalString = TranslatorUtil.ObjectToLiteral(node.Value, node.LiteralType); builder.AppendLine($"{GetOrCreatePinName(node.ValuePin)} = {literalString};"); }
public void TranslateCallMethodNode(CallMethodNode node) { string temporaryReturnName = null; // Translate all the pure nodes this node depends on in // the correct order TranslateDependentPureNodes(node); // Write assignment of return values if (node.OutputDataPins.Count == 1) { string returnName = GetOrCreatePinName(node.OutputDataPins[0]); builder.Append($"{returnName} = "); } else if (node.OutputDataPins.Count > 1) { temporaryReturnName = TranslatorUtil.GetTemporaryVariableName(); var returnTypeNames = string.Join(", ", node.OutputDataPins.Select(pin => pin.PinType)); builder.Append($"{typeof(Tuple).FullName}<{returnTypeNames}> {temporaryReturnName} = "); } // Static: Write class name / target, default to own class name // Instance: Write target, default to this if (node.IsStatic) { builder.Append($"{node.DeclaringType}."); } else { if (node.TargetPin.IncomingPin != null) { string targetName = GetOrCreatePinName(node.TargetPin.IncomingPin); builder.Append($"{targetName}."); } else { // Default to thise builder.Append("this."); } } // Write function call with arguments var argumentNames = GetPinIncomingValues(node.ArgumentPins); builder.AppendLine($"{node.MethodName}({string.Join(", ", argumentNames)});"); // Assign the real variables from the temporary tuple if (node.OutputDataPins.Count > 1) { var returnNames = GetOrCreatePinNames(node.OutputDataPins); for (int i = 0; i < returnNames.Count(); i++) { builder.AppendLine($"{returnNames.ElementAt(i)} = {temporaryReturnName}.Item{i+1};"); } } // Go to the next state WriteGotoOutputPin(node.OutputExecPins[0]); }
public void TranslateCallMethodNode(CallMethodNode node) { // Wrap in try/catch if we have a catch handler if (node.CatchPin.OutgoingPin != null) { builder.AppendLine("try"); builder.AppendLine("{"); } string temporaryReturnName = null; // Translate all the pure nodes this node depends on in // the correct order TranslateDependentPureNodes(node); // Write assignment of return values if (node.ReturnValuePins.Count == 1) { string returnName = GetOrCreatePinName(node.ReturnValuePins[0]); builder.Append($"{returnName} = "); } else if (node.OutputDataPins.Count > 1) { temporaryReturnName = TranslatorUtil.GetTemporaryVariableName(); var returnTypeNames = string.Join(", ", node.OutputDataPins.Select(pin => pin.PinType)); builder.Append($"{typeof(Tuple).FullName}<{returnTypeNames}> {temporaryReturnName} = "); } // Get arguments for method call var argumentNames = GetPinIncomingValues(node.ArgumentPins); // Check whether the method is an operator and we need to translate its name // into operator symbols. Otherwise just call the method normally. if (OperatorUtil.TryGetOperatorInfo(node.MethodSpecifier, out OperatorInfo operatorInfo)) { if (operatorInfo.Unary) { if (argumentNames.Count() != 1) { throw new Exception($"Unary operator was found but did not have one argument: {node.MethodName}"); } if (operatorInfo.UnaryRightPosition) { builder.AppendLine($"{argumentNames.ElementAt(0)}{operatorInfo.Symbol};"); } else { builder.AppendLine($"{operatorInfo.Symbol}{argumentNames.ElementAt(0)};"); } } else { if (argumentNames.Count() != 2) { throw new Exception($"Binary operator was found but did not have two arguments: {node.MethodName}"); } builder.AppendLine($"{argumentNames.ElementAt(0)}{operatorInfo.Symbol}{argumentNames.ElementAt(1)};"); } } else { // Static: Write class name / target, default to own class name // Instance: Write target, default to this if (node.IsStatic) { builder.Append($"{node.DeclaringType.FullCodeName}."); } else { if (node.TargetPin.IncomingPin != null) { string targetName = GetOrCreatePinName(node.TargetPin.IncomingPin); builder.Append($"{targetName}."); } else { // Default to this builder.Append("this."); } } // Write the method call builder.AppendLine($"{node.MethodName}({string.Join(", ", argumentNames)});"); } // Assign the real variables from the temporary tuple if (node.ReturnValuePins.Count > 1) { var returnNames = GetOrCreatePinNames(node.ReturnValuePins); for (int i = 0; i < returnNames.Count(); i++) { builder.AppendLine($"{returnNames.ElementAt(i)} = {temporaryReturnName}.Item{i+1};"); } } // Go to the next state WriteGotoOutputPin(node.OutputExecPins[0]); // Catch exceptions and execute catch pin if (node.CatchPin.OutgoingPin != null) { string exceptionVarName = TranslatorUtil.GetTemporaryVariableName(); builder.AppendLine("}"); builder.AppendLine($"catch (System.Exception {exceptionVarName})"); builder.AppendLine("{"); builder.AppendLine($"{GetOrCreatePinName(node.ExceptionPin)} = {exceptionVarName};"); WriteGotoOutputPin(node.CatchPin); builder.AppendLine("}"); } }