public static bool DoIsLastCall(RCClosure closure, RCClosure arg, RCBlock block) { // Costly call to GetName, will want to address this at some point. // return block.Evaluator.Return; return(block.GetName(closure.Index).Evaluator.Return); }
public static RCBlock Append(RCBlock left, RCBlock right) { RCBlock result = left; for (int i = 0; i < right.Count; ++i) { RCBlock current = right.GetName(i); result = new RCBlock(result, current.Name, current.Evaluator, current.Value); } return(result); }
public static void WriteBlock(RCArray <byte> result, RCBlock block) { // Pre-order traversal of the expression tree. result.Write((byte)'k'); WriteScalarInt(result, block.Count); for (int i = 0; i < block.Count; ++i) { RCBlock name = block.GetName(i); Binary.WriteScalarString(name.Name, result); // Binary.WriteScalarString (RCEvaluator.For (name.Evaluator), result); Binary.WriteScalarString(name.Evaluator.Symbol, result); name.Value.ToByte(result); } }
protected static RCBlock NextBlock(RCRunner runner, RCBlock block, RCClosure previous, RCValue val) { RCBlock code = block.GetName(previous.Index); RCBlock result = new RCBlock(previous.Result, code.Name, code.Evaluator.Next, val); runner.Output(previous, new RCSymbolScalar(null, code.Name), val); return(result); }
public RCValue RepAction(string action) { if (_state.Get(action) == null) { throw new ArgumentException(string.Format("Unknown action name: {0}", action)); } RCValue result = Rep(string.Format("{0} {{}}", action), restoreStateOnError: true); RCBlock variables = result as RCBlock; if (variables != null) { for (int i = 0; i < variables.Count; ++i) { RCBlock variable = variables.GetName(i); _state = new RCBlock(_state, variable.Name, variable.Evaluator, variable.Value); } } return(result); }
protected void FinishTemplate(int escapeCount) { RCString section; TemplateVars template = _templates.Peek(); if (template._multilineTemplate) { for (int i = 0; i < _block.Count; ++i) { RCBlock current = _block.GetName(i); section = current.Value as RCString; if (section != null && i % 2 == 0) { string content = section[0]; int spaces = 0; bool broken = false; bool hasLine = false; int firstNewline = content.IndexOf('\n'); if (firstNewline > -1) { hasLine = true; } for (int j = firstNewline + 1; j < content.Length; ++j) { if (content[j] == ' ') { if (!broken) { ++spaces; } } else if (content[j] == '\n') { if (j > 0) { template._minSpaces = Math.Min(template._minSpaces, spaces); } spaces = 0; broken = false; hasLine = true; } else { broken = true; } } if (content.Length > 0 && content[content.Length - 1] != '\n' && hasLine && i < _block.Count - 1) { template._minSpaces = Math.Min(template._minSpaces, spaces); } if (template._minSpaces == int.MaxValue) { template._minSpaces = 0; } } } RCBlock final = RCBlock.Empty; // strip indentation (spaces only) from the lines in the content. // Ignore the first and last sections. for (int i = 0; i < _block.Count; ++i) { RCBlock current = _block.GetName(i); section = current.Value as RCString; if (section != null && i % 2 == 0) { string content = section[0]; StringBuilder builder = new StringBuilder(); int start = 0, end = 0; // Skip past the initial newline in the first section. if (i == 0) { while (content[start] != '\n') { ++start; } ++start; } else { while (end < content.Length) { if (content[end] == '\n') { ++end; break; } ++end; } if (end < content.Length && end > 1 && content[end - 2] == '\r') { builder.Append(content.Substring(start, (end - 2) - start)); builder.Append("\n"); } else { builder.Append(content.Substring(start, end - start)); } start = end; } end = start; GETLINE: start = end + template._minSpaces; while (end < content.Length) { if (content[end] == '\n') { ++end; break; } ++end; } // The problem is when the first character is a newline this gets f****d up. if (start < content.Length && end <= content.Length) { // string trimmed; if (end < start) { builder.Append(content.Substring(0, end)); } else { if (content.Length > 1 && content[end - 2] == '\r') { builder.Append(content.Substring(start, (end - 2) - start)); builder.Append("\n"); } else { builder.Append(content.Substring(start, end - start)); } } // builder.Append (trimmed); goto GETLINE; } else { final = new RCBlock(final, current.Name, current.Evaluator, new RCString(builder.ToString())); } } else { final = new RCBlock(final, current.Name, current.Evaluator, current.Value); } } _result = new RCTemplate(final, escapeCount, true); } else { _result = new RCTemplate(_block, escapeCount, false); } // The template must either be all on one line, // or the first and last lines with the [? and ?] tokens // must be free of any other content. // So this loop needs to find out whether there are any newlines. // If there are then we also need to find out where the // first non-white character is. // Reset state for the possible next template. // _multilineTemplate = false; // _parsingContent = false; // _minSpaces = 0; }
// Kicks off evaluation for a block. public static void DoEval(RCRunner runner, RCClosure closure, RCBlock block) { if (block.Count == 0) { DoYield(runner, closure, block); } else { RCBlock current = block.GetName(closure.Index); if (current.Evaluator.Invoke) { string op = ((RCString)current.Value)[0]; RCSystem.Activator.Invoke(runner, closure, op, closure.Result); } else if (current.Evaluator.Template) { try { RCString result = ExpandTemplate(new StringBuilder(), (RCTemplate)current, closure.Result, 0, ""); runner.Yield(closure, result); } catch (Exception ex) { RCException rcex = new RCException(closure, ex, RCErrors.Native, "An exception was thrown by the template."); runner.Finish(closure, rcex, (int)RCErrors.Native); } } else if (current.Evaluator.Pass) { DoYield(runner, closure, current.Value); } // This means that Value is an operator or a reference. else if (current.Value.ArgumentEval) { current.Value.Eval(runner, new RCClosure(closure, closure.Bot, current.Value, closure.Left, closure.Result, 0)); } else if (current.Evaluator.Return) { DoYield(runner, closure, current.Value); } else { // I need something different to happen when we are at the top level already. // Or maybe I need to inject a wrapper closure when I do Rep this way? if ((closure.Index < block.Count - 1) || (closure.Parent != null)) { DoYield(runner, closure, current.Value); } else { DoYield(runner, closure, current); } } } }
// It is possible to have multiple concurrent observers. // However each value will only be returned to one of the observers. // It is hard to see a reason to create multiple observers but there // are multiple potential problems with implementing the constraint that there // be only one. public void Watch(RCClosure closure, long bot) { RCBlock result; lock (_botLock) { Queue <RCAsyncState> output = _output[bot]; if (output.Count == 0) { Queue <RCClosure> watchers; if (!_watchers.TryGetValue(bot, out watchers)) { watchers = new Queue <RCClosure> (); _watchers[bot] = watchers; } watchers.Enqueue(closure); return; } RCBlock values = RCBlock.Empty; Stack <RCClosure> parts = new Stack <RCClosure> (); RCArray <RCSymbolScalar> names = new RCArray <RCSymbolScalar> (output.Count); while (output.Count > 0) { RCAsyncState state = output.Dequeue(); RCClosure parent = state.Closure; RCSymbolScalar name = new RCSymbolScalar(null, parent.Fiber); while (parent != null) { if (parent.Parent.Bot != parent.Bot || parent.Parent.Fiber != parent.Fiber) { break; } parts.Push(parent); parent = parent.Parent; } while (parts.Count > 0) { RCClosure top = parts.Pop(); if (top.Code.IsBlock) { RCBlock code = (RCBlock)top.Code; string part = code.GetName(top.Index).Name; if (part != "") { name = new RCSymbolScalar(name, part); } else { name = new RCSymbolScalar(name, (long)top.Index); } } } if (name != null) { RCValue val = (RCValue)state.Other; values = new RCBlock(values, "", ":", val); names.Write(name); } } result = new RCBlock(null, "names", ":", new RCSymbol(names)); result = new RCBlock(result, "values", ":", values); } Yield(closure, result); }
public static void DoFormat(RCBlock block, StringBuilder builder, RCFormat args, RCColmap colmap, int level) { if (block.Count == 0) { if (!args.Fragment) { builder.Append("{}"); } return; } if (level > 0 || !args.Fragment) { builder.Append("{"); builder.Append(args.Newline); } ++level; // Note the indexer requires a linear search backwards. // Maybe a custom iterator is in order? // It would also be useful for evaluation and other algorithms. for (int i = 0; i < block.Count; ++i) { RCBlock child = block.GetName(i); if (level > 1 || !args.Fragment) { for (int tab = args.Fragment ? 1 : 0; tab < level; ++tab) { builder.Append(args.Indent); } } if (args.Syntax == "JSON") { builder.AppendFormat("\"{0}\"", child.RawName); } else if (child.EscapeName) { builder.Append(child.Name); } else { builder.Append(child.Name); } builder.Append(child.Evaluator.Symbol); if (child.Value != null) { child.Value.Format(builder, args, colmap, level); } else // Only the empty block has no value. { builder.Append("{}"); } if (i < block.Count - 1) { builder.Append(args.RowDelimeter); } } builder.Append(args.Newline); --level; if (level > 0 || !args.Fragment) { for (int tab = args.Fragment ? 1 : 0; tab < level; ++tab) { builder.Append(args.Indent); } builder.Append("}"); } }