/// <summary> /// Evaluate line and body if needed. /// 'requestor' is positioned on the next line to eval. /// </summary> internal static Value DoOne(ILineRequestor requestor, IScope scope) { DelimiterList list = requestor.GetCurrentLine(scope); try { // eval using list's scope, falling back to passed in scope if not present IScope theScope = (list.Scope != null ? list.Scope : scope); Value value = EvalList.Do(list.Nodes, theScope, requestor); // if only item on line was a func, see if it needs a body ValueFunction func = value as ValueFunction; if (func != null && func.RequiresBody()) // if line created a partial function that needs a body, // eval all subsequent indented lines value = EvalList.DoAddBody(func, scope, requestor); // if only item was a map w/ one value, see if it needs a body if (func == null && value is ValueMap) { Map map = value.AsMap; if (map.Raw.Count == 1) { string key = ""; foreach (string k in map.Raw.Keys) key = k; func = map[key] as ValueFunction; if (func != null && func.RequiresBody()) map[key] = EvalList.DoAddBody(func, scope, requestor); } } // if only item was an array, see if last item needs a body if (func == null && value is ValueArray) { List<Value> array = value.AsArray; if (array.Count > 0) { func = array[array.Count - 1] as ValueFunction; if (func != null && func.RequiresBody()) array[array.Count - 1] = EvalList.DoAddBody(func, scope, requestor); } } requestor.Advance(); return value; } catch (Loki3Exception e) { e.AddLine(list.ToString()); throw e; } }
/// <summary> /// Get the body following the current line. /// 'requestor' will be positioned on the last line of the body. /// </summary> internal static List<DelimiterList> DoGetBody(IScope scope, ILineRequestor requestor) { List<DelimiterList> body = new List<DelimiterList>(); // if we have a subset of all lines, we should simply use them as-is if (requestor.IsSubset()) { while (requestor.HasCurrent()) { DelimiterList dline = requestor.GetCurrentLine(scope); dline.Scope = scope; // use this scope when evaling later body.Add(dline); requestor.Advance(); } return body; } // else just grab indented lines DelimiterList pline = requestor.GetCurrentLine(scope); int parentIndent = pline.Indent; while (requestor.HasCurrent()) { requestor.Advance(); DelimiterList childLine = requestor.GetCurrentLine(scope); if (childLine == null || childLine.Indent <= parentIndent) { requestor.Rewind(); break; // now we have the body } childLine.Scope = scope; // use this scope when evaling later // keep adding to the body body.Add(childLine); } return body; }