internal override Value Eval(Value arg, IScope scope) { Map map = arg.AsMap; List<DelimiterNode> check = (map["check"] as ValueRaw).GetValue().Nodes; Value changeVal = map["change"]; List<DelimiterNode> change = changeVal is ValueNil ? null : (changeVal as ValueRaw).GetValue().Nodes; bool checkFirst = map["checkFirst?"].AsBool; // todo: consolidate these bodies, one from an explicit param & one from the following lines Value valueBody = map.ContainsKey("body") ? map["body"] : map[ValueFunction.keyBody]; bool isFirst = true; Value result = ValueBool.False; while (true) { // check if we should stop loop if (!isFirst || checkFirst) { Value retval = EvalList.Do(check, scope); if (!retval.AsBool) return result; // last value of body } else { isFirst = false; } // use bound scope if available IScope parentScope = scope; if (valueBody is ValueRaw) { IScope rawScope = (valueBody as ValueRaw).Scope; if (rawScope != null) parentScope = rawScope; } // eval body IScope local = new ScopeChain(parentScope); result = EvalBody.Do(valueBody, local); local.Exit(); // if per-loop code was passed, run it if (change != null) EvalList.Do(change, scope); } }
internal override Value Eval(Value arg, IScope scope) { Map map = arg.AsMap; Value collection = map["collection"]; // todo: consolidate these bodies, one from an explicit param & one from the following lines Value valueBody = map.ContainsKey("body") ? map["body"] : map[ValueFunction.keyBody]; IScope bodyScope = scope; if (valueBody is ValueRaw) { IScope tempScope = (valueBody as ValueRaw).Scope; if (tempScope != null) bodyScope = tempScope; } // todo: abstract iteration to avoid these ifs Value result = ValueNil.Nil; if (collection is ValueString) { string s = collection.AsString; foreach (char c in s) { IScope local = new ScopeChain(bodyScope); PatternAssign assign = new PatternAssign(map, local, true/*bCreate*/); assign.Assign(new ValueString(c.ToString())); result = EvalBody.Do(valueBody, local); local.Exit(); } } else if (collection is ValueArray) { List<Value> list = collection.AsArray; foreach (Value v in list) { IScope local = new ScopeChain(bodyScope); PatternAssign assign = new PatternAssign(map, local, true/*bCreate*/); assign.Assign(v); result = EvalBody.Do(valueBody, local); local.Exit(); } } else if (collection is ValueMap) { Dictionary<string, Value> dict = collection.AsMap.Raw; foreach (string key in dict.Keys) { List<Value> list = new List<Value>(); list.Add(new ValueString(key)); list.Add(dict[key]); IScope local = new ScopeChain(bodyScope); PatternAssign assign = new PatternAssign(map, local, true/*bCreate*/); assign.Assign(new ValueArray(list)); result = EvalBody.Do(valueBody, local); local.Exit(); } } else if (collection is ValueLine) { List<DelimiterList> list = collection.AsLine; // if delimiter is specified, wrap each line w/ it ValueDelimiter delim = scope.GetValue(new Token(map["delim"].AsString)) as ValueDelimiter; if (delim != null) { List<DelimiterList> delimList = new List<DelimiterList>(); int indent = (list.Count > 0 ? list[0].Indent : 0); foreach (DelimiterList line in list) { DelimiterList newLine = line; // wrap lines & nested lines with proper delimiter, except for nested values that get evaled if (line.Indent == indent || (delim.DelimiterType != DelimiterType.AsValue && line.Indent >= indent)) { List<DelimiterNode> nodes = new List<DelimiterNode>(); string original = line.Original; if (delim.DelimiterType == DelimiterType.AsString && line.Indent > indent) { // put the indentation back if portions of the body were indented original = ""; for (int i = 0; i < line.Indent - indent; i++) original += " "; original += line.Original; } nodes.Add(new DelimiterNodeList(new DelimiterList(delim, line.Nodes, line.Indent, "", original, line.Scope))); newLine = new DelimiterList(delim, nodes, indent, "", original, line.Scope); } delimList.Add(newLine); } list = delimList; } // for each line, eval it then eval the body ILineRequestor lines = new LineConsumer(list); while (lines.HasCurrent()) { IScope local = new ScopeChain(bodyScope); Value value = EvalLines.DoOne(lines, local); PatternAssign assign = new PatternAssign(map, local, true/*bCreate*/); assign.Assign(value); result = EvalBody.Do(valueBody, local); local.Exit(); } } return result; }