## mustacheCore.makeEvaluator Given a scope and expression, returns a function that evaluates that expression in the scope.  This function first reads lookup values in the args and hash.  Then it tries to figure out if a helper is being called or a value is being read.  Finally, depending on if it's a helper, or not, and which mode the expression is in, it returns a function that can quickly evaluate the expression. 
@hide
Given a mode and expression data, returns a function that evaluates that expression.
@param {can-view-scope} The scope in which the expression is evaluated.
@param {can.view.Options} The option helpers in which the expression is evaluated.
@param {String} mode Either null, #, ^. > is handled elsewhere
@param {Object} exprData Data about what was in the mustache expression
@param {renderer} [truthyRenderer] Used to render a subsection
@param {renderer} [falseyRenderer] Used to render the inverse subsection
@param {String} [stringOnly] A flag to indicate that only strings will be returned by subsections.
@return {Function} An 'evaluator' function that evaluates the expression.
function (scope, nodeList, mode, exprData, truthyRenderer, falseyRenderer, stringOnly) {

		if(mode === "^") {
			var temp = truthyRenderer;
			truthyRenderer = falseyRenderer;
			falseyRenderer = temp;
		}

		var value,
			helperOptions = new HelperOptions(scope, nodeList, exprData, stringOnly);
			// set up renderers
			utils.createRenderers(helperOptions, scope, nodeList, truthyRenderer, falseyRenderer, stringOnly);

		if(exprData instanceof expression.Call) {
			value = exprData.value(scope, helperOptions);
		} else if (exprData instanceof expression.Bracket) {
			value = exprData.value(scope);
		} else if (exprData instanceof expression.Lookup) {
			value = exprData.value(scope);
		} else if (exprData instanceof expression.Literal) {
			value = exprData.value.bind(exprData);
		} else if (exprData instanceof expression.Helper && exprData.methodExpr instanceof expression.Bracket) {
			// Brackets get wrapped in Helpers when used in attributes
			// like `<p class="{{ foo[bar] }}" />`
			value = exprData.methodExpr.value(scope, helperOptions);
		} else {
			value = exprData.value(scope, helperOptions);
			if (typeof value === "function") {
				return value;
			}
		}
		// {{#something()}}foo{{/something}}
		// return evaluator for no mode or rendered value if a renderer was called
		if(!mode || helperOptions.metadata.rendered) {
			return value;
		} else if( mode === "#" || mode === "^" ) {

			return function(){
				// Get the value
				var finalValue = canReflect.getValue(value);
				var result;

				// if options.fn or options.inverse was called, we take the observable's return value
				// as what should be put in the DOM.
				if(helperOptions.metadata.rendered) {
					result = finalValue;
				}
				// If it's an array, render.
				else if ( typeof finalValue !== "string" && canReflect.isListLike(finalValue) ) {
					var isObserveList = canReflect.isObservableLike(finalValue) &&
						canReflect.isListLike(finalValue);

					if(canReflect.getKeyValue(finalValue, "length")) {
						if (stringOnly) {
							result = utils.getItemsStringContent(finalValue, isObserveList, helperOptions);
						} else {
							result = frag(utils.getItemsFragContent(finalValue, helperOptions, scope));
						}
					} else {
						result = helperOptions.inverse(scope);
					}
				}
				else {
					result = finalValue ? helperOptions.fn(finalValue || scope) : helperOptions.inverse(scope);
				}
				// We always set the rendered result back to false.
				// - Future calls might change from returning a value to calling `.fn`
				// - We are calling `.fn` and `.inverse` ourselves.
				helperOptions.metadata.rendered = false;
				return result;
			};
		} else {
			// not supported!
		}
	}