public static RCClosure Deserialize(RCBlock right) { long botId = right.GetLong("bot"); long fiber = right.GetLong("fiber"); RCSymbol locks = (RCSymbol)right.Get("locks", null); RCBlock parentBlock = (RCBlock)right.GetBlock("parent", null); RCClosure parent = null; if (parentBlock != null) { parent = Deserialize(parentBlock); } RCValue code = right.Get("code"); RCValue left = right.Get("left", null); RCBlock result = right.GetBlock("result"); int index = (int)right.GetLong("index"); RCValue userOp = right.Get("userOp"); RCBlock userOpContextBlock = right.GetBlock("userOpContext", null); RCArray <RCBlock> userOpContext = null; if (userOpContextBlock != null) { userOpContext = new RCArray <RCBlock> (); for (int i = 0; i < userOpContextBlock.Count; ++i) { userOpContext.Write((RCBlock)userOpContextBlock.Get(i)); } } bool noClimb = right.GetBoolean("noClimb"); bool noResolve = right.GetBoolean("noResolve"); return(new RCClosure(botId, fiber, locks, parent, code, left, result, index, userOp, userOpContext, noClimb, noResolve)); }
/// <summary> /// Find and return the value referenced by name. Return null if not found. /// </summary> public static RCValue Resolve(RCBlock context, RCClosure closure, RCArray <string> name, RCArray <RCBlock> @this, bool returnNull) { if (context != null) { RCValue result = context.Get(name, @this); if (result != null) { return(result); } } RCClosure parent = closure; RCValue val = null; while (parent != null) { RCRefable result = parent.Result; if (result != null && !parent.NoResolve) { val = result.Get(name, @this); } if (val != null) { break; } if (!parent.NoClimb) { parent = parent.Parent; } else { break; } } if (val == null && !returnNull) { // Delimit thing is annoying. throw new RCException(closure, RCErrors.Name, "Unable to resolve name " + RCReference.Delimit(name, ".")); } return(val); }
protected static RCString ExpandTemplate(StringBuilder builder, RCTemplate template, RCBlock right, int I, string parentIndent) { string indent = parentIndent; for (int i = 0; i < right.Count; ++i) { RCValue child = right.Get(i); RCVector <string> text = child as RCVector <string>; if (text == null) { RCArray <string> strings = new RCArray <string> (right.Count); RCBlock nestedBlock = (RCBlock)child; for (int j = 0; j < nestedBlock.Count; ++j) { strings.Write(nestedBlock.GetString(j)); } text = new RCString(strings); // ExpandTemplate (builder, template, (RCBlock) child, I + i, indent); } // else { bool somethingAdded = false; for (int j = 0; j < text.Count; ++j) { string section = text[j]; int start = 0; int lineNum = 0; for (int k = 0; k < section.Length; ++k) { if (section[k] == '\n') { string line; if (i % 2 == 1) { if (k > 0 && section.Length > 0 && section[k - 1] == '\r') { line = section.Substring(start, k - start - 1); } else { line = section.Substring(start, k - start); } // if (j > 0 || start > 0) // Using j and start here didn't work because sometimes empty strings // are added. Instead keep track of whether a line has been added. // We may need this variable to handle other cases as well, but // they haven't cropped yet. if (somethingAdded) { // Notice below in the section with w. If there is extra content // before the code section on the same line, it will have been // inserted/indented already. builder.Append(indent); } builder.Append(line); builder.Append("\n"); somethingAdded = true; } else { // In content sections after the first one, // skip newlines if they are the first thing in the section. line = section.Substring(start, k - start); if (I + i == 0) { builder.Append(line); builder.Append("\n"); } else if (line != "") { if (builder[builder.Length - 1] == '\n') { if (start == 0 && (k < section.Length - 1 || i == right.Count - 1)) { builder.Append(indent); } else if (k == section.Length - 1 && i < right.Count - 1) { builder.Append(indent); } } builder.Append(line); builder.Append("\n"); } else if (k > 0 || (builder.Length > 0 && builder[builder.Length - 1] != '\n')) { builder.Append(line); builder.Append("\n"); } } start = k + 1; ++lineNum; } } if (template.Multiline) { // If this is a code section, the lastPiece is just the last line of the // template. // There is no newline at the end. // If this is a text section, the lastPiece is a prefix for the next code // section. string lastPiece = section.Substring(start, section.Length - start); if (i % 2 == 1) { // Odd sections are always code sections. // Code sections don't have a newline at the end. if (j == 0) { // This means there was a newline at the end of section. if (start > 0 && lastPiece != "") { builder.Append(indent); } } else if (j == text.Count - 1) { indent = parentIndent; } builder.Append(lastPiece); } else { int w; for (w = 0; w < lastPiece.Length; ++w) { if (lastPiece[w] != ' ') { break; } } // indent only includes spaces before the first non-space character. // The non-space part of the text is only inserted once. // An edge case involves spaces inserted between code sections on the same // line. // \t not spoken here. // while (builder.Length == 0 || builder[builder.Length - 1] == '\n') { string end; if (builder.Length == 0 || builder[builder.Length - 1] == '\n') { indent = parentIndent + lastPiece.Substring(0, w); end = lastPiece.Substring(w, lastPiece.Length - w); } else { end = lastPiece; } if (i < right.Count - 1) { if (section.Length > 0) { if (builder.Length == 0 || builder[builder.Length - 1] == '\n') { builder.Append(indent); } } } builder.Append(end); } } } else { // If there are no newlines in the template then just drop the whole thing // in as is. builder.Append(text[j]); } } } } // Go back and remove the final newline now. // Let the enclosing template decide how to finish off. if (template.Multiline) { if (builder.Length > 0 && builder[builder.Length - 1] != '\n') { builder.Append("\n"); } } return(new RCString(builder.ToString())); }