/// <summary> /// Evaluates a token, possibly requesting the previous and next values. /// Returns a value. /// </summary> /// <param name="token">token representing a function or variable</param> /// <param name="scope">used to request functions, variables, and delimiters if there's no scope attached to the node</param> /// <param name="nodes">used to request previous and next nodes</param> internal static Value Do(DelimiterNode node, IScope scope, INodeRequestor nodes, ILineRequestor requestor) { if (node.Value != null) { // node has already been evaluated return node.Value; } else if (node.Token != null) { // function/variable or built-in Token token = node.Token; Value value = scope.GetValue(token); if (value is ValueFunction && nodes != null) { ValueFunction function = value as ValueFunction; // get previous & next nodes if needed DelimiterNode previous = (function.ConsumesPrevious ? nodes.GetPrevious() : null); DelimiterNode next = (function.ConsumesNext ? nodes.GetNext() : null); scope.FunctionName = token.Value; // evaluate try { return function.Eval(previous, next, scope, scope, nodes, requestor); } catch (Loki3Exception e) { // this function is the correct context if there isn't already one there if (!e.Errors.ContainsKey(Loki3Exception.keyFunction)) e.AddFunction(token.Value); if (!e.Errors.ContainsKey(Loki3Exception.keyScope)) e.AddScope(scope); throw e; } } else if (value != null) { return value; } else { return EvalBuiltin.Do(token); } } else if (node.List != null) { // delimited list of nodes Value value = null; DelimiterList list = node.List; IScope listScope = (list.Scope != null ? list.Scope : scope); DelimiterType type = list.Delimiter.DelimiterType; // get contents as a Value switch (type) { case DelimiterType.AsString: value = new ValueString(list.Original); break; case DelimiterType.AsValue: value = EvalList.Do(list.Nodes, listScope); break; case DelimiterType.AsArray: List<Value> values = new List<Value>(list.Nodes.Count); foreach (DelimiterNode subnode in list.Nodes) { // note: 'nodes' is null so functions don't get evaled Value subvalue = Do(subnode, listScope, null, requestor); values.Add(subvalue); } value = new ValueArray(values); break; case DelimiterType.AsEvaledArray: value = EvalList.DoEvaledArray(list.Nodes, listScope); break; case DelimiterType.AsRaw: value = new ValueRaw(list, listScope); break; case DelimiterType.AsArrayOfRaw: List<Value> rawvalues = new List<Value>(list.Nodes.Count); foreach (DelimiterNode subnode in list.Nodes) rawvalues.Add(new ValueRaw(subnode, listScope)); value = new ValueArray(rawvalues); break; } // run contents through a function if specified ValueFunction function = list.Delimiter.Function; if (function == null) return value; DelimiterNode next = new DelimiterNodeValue(value); return function.Eval(null, next, scope, scope, nodes, requestor); } return new ValueNil(); }
internal override Value Eval(Value arg, IScope scope) { Map map = arg.AsMap; List<Value> array = map["array"].AsArray; ValueFunction filter = map["filter?"] as ValueFunction; ValueFunction transform = map["transform"] as ValueFunction; if (filter == null && transform == null) return map["array"]; List<Value> newarray = new List<Value>(array.Count); bool bPre = ((filter != null && filter.ConsumesPrevious) || (transform != null && transform.ConsumesPrevious)); int i = 0; foreach (Value val in array) { DelimiterNode prev = (bPre ? new DelimiterNodeValue(new ValueInt(i)) : null); DelimiterNode node = new DelimiterNodeValue(val); // if we should use this value... if (filter == null || filter.Eval(prev, node, scope, scope, null, null).AsBool) { // ...transform if appropriate Value newval = (transform == null ? val : transform.Eval(prev, node, scope, scope, null, null)); newarray.Add(newval); } i++; } return new ValueArray(newarray); }
internal override Value Eval(Value arg, IScope scope) { Map map = arg.AsMap; List<Value> array = map["array"].AsArray; ValueFunction function = map["function"] as ValueFunction; Value last = array[array.Count - 1]; for (int i = array.Count - 2; i >= 0; i--) { Value val = array[i]; DelimiterNode node1 = new DelimiterNodeValue(last); DelimiterNode node2 = new DelimiterNodeValue(val); last = function.Eval(node2, node1, scope, scope, null, null); } return last; }
internal override Value Eval(Value arg, IScope scope) { Map map = arg.AsMap; List<Value> array = map["array"].AsArray; ValueFunction function = map["function"] as ValueFunction; bool bFirst = true; Value last = null; foreach (Value val in array) { if (bFirst) { last = val; bFirst = false; } else { DelimiterNode node1 = new DelimiterNodeValue(last); DelimiterNode node2 = new DelimiterNodeValue(val); last = function.Eval(node1, node2, scope, scope, null, null); } } return last; }
internal override Value Eval(Value arg, IScope scope) { Map map = arg.AsMap; Map inputMap = map["map"].AsMap; bool bUseValue = map["value?"].AsBool; ValueFunction filter = map["filter?"] as ValueFunction; ValueFunction transform = map["transform"] as ValueFunction; if (filter == null && transform == null) return map["map"]; Dictionary<string, Value> dict = inputMap.Raw; Dictionary<string, Value> newdict = new Dictionary<string, Value>(); if (dict == null) return new ValueMap(new Map(newdict)); bool bPre = ((filter != null && filter.ConsumesPrevious) || (transform != null && transform.ConsumesPrevious)); foreach (string key in dict.Keys) { DelimiterNode prev = (bPre ? new DelimiterNodeValue(new ValueString(key)) : null); DelimiterNode next = new DelimiterNodeValue(dict[key]); // if we should use this value... if (filter == null || filter.Eval(prev, next, scope, scope, null, null).AsBool) { // ...transform if appropriate if (bUseValue) { Value newval = (transform == null ? dict[key] : transform.Eval(prev, next, scope, scope, null, null)); newdict[key] = newval; } else { string newkey = (transform == null ? key : transform.Eval(prev, next, scope, scope, null, null).AsString); newdict[newkey] = dict[key]; } } } return new ValueMap(new Map(newdict)); }
internal override Value Eval(Value arg, IScope scope) { Map map = arg.AsMap; Map inputMap = map["map"].AsMap; bool bKeepValue = map["value?"].AsBool; ValueFunction filter = map["filter?"] as ValueFunction; ValueFunction transform = map["transform"] as ValueFunction; if (filter == null && transform == null) return map["map"]; Dictionary<string, Value> dict = inputMap.Raw; List<Value> newarray = new List<Value>(); if (dict != null) { bool bPre = (filter is ValueFunctionPre || transform is ValueFunctionPre); foreach (string key in dict.Keys) { DelimiterNode prev = (bPre ? null : new DelimiterNodeValue(new ValueString(key))); DelimiterNode toFilter = new DelimiterNodeValue(dict[key]); // if we should use this value... if (filter == null || filter.Eval(prev, toFilter, scope, scope, null, null).AsBool) { // get value or key & possibly transform Value newval = (bKeepValue ? dict[key] : new ValueString(key)); if (transform != null) { DelimiterNode toTransform = new DelimiterNodeValue(newval); newval = transform.Eval(prev, toTransform, scope, scope, null, null); } newarray.Add(newval); } } } return new ValueArray(newarray); }