private static LNode ChangePath(LNode call, LNode path, IMacroContext context, Func <LNode, IMacroContext, LNode> change) { foreach (var index in path.AsList(CodeSymbols.Tuple)) { // Check if index is an integer, a negated integer, or an // identifier matching the name of an argument of `call`... if (index.Value is int iArg || index.Calls(S.Sub, 1) && index[0].Value is int negArg && ((iArg = -negArg) & 0) == 0 || index.IsId && (iArg = EnumerableExt.FirstIndexWhere <LNode>(call, n => n.Name == index.Name) ?? -1) != -1 && ((iArg += call.Min) & 0) == 0) { LNode arg = call.TryGet(iArg, null); if (arg == null) { context.Warning(path, "Index is out of range ({1})", iArg, call.Min <= call.Max ? "expected {0} to {1}".Localized(call.Min, call.Max) : "'{0}' has no children".Localized(LNode.Printer.Print(call, null, ParsingMode.Expressions))); } else { call = call.WithChildChanged(iArg, change(arg, context)); } }