Expression beautifier

You know how calc expressions can become a nightmare when growing in size. Nested IIFs, long chains of logical operators, service calls and dozen of brackets. And all these in a single line. It can take minutes before one can understand what is going on. Sometimes I copy the expression into a text editor and manually format it - with tabs and newlines, the same way modern IDE formats the code. Once done, it is much easier to read a logic from the rule.

Inspired by the idea to automate the routine, I did a research and then spent some time on a "grammar playground". Check out the result below or in a new window.

Siebel Expressions online beautifier

Current formatting logic is to simply print function parameters (when more than 2) on new lines as well as logical expressions enclosed in parenthesis. I plan to make it a bit smarter in future.

Source code

function trav(o, t, f) {
	var r = "";
	if ("object" === typeof o) {
		var p = o.par;
		var n = o.not;

		if (o.type === "bin") {
			r =  trav(o.left, t) + " " + o.operator + " " + trav(o.right, t);
		} else if (o.type === "log") {
			if(p) { // format logical operators eclosed in brackets
				tt = t + "\t";
				r = "(\n";
				r += tt + trav(o.left, tt, true);
				r += "\n" + tt + o.operator + " " + trav(o.right, tt, true);
				r += "\n" + t + ")";
				p = false;
			} else {
				if(f) {
					r = trav(o.left, t, true);
					r += "\n" + t + o.operator + " " + trav(o.right, t, true);
				} else {
					r = trav(o.left, t) + " " + o.operator + " " + trav(o.right, t);
				}
			}
		} else if (o.type === "func") {
			var f = o.arguments.length > 2; // split params when more then 2
			var s = (f ? "\n" + t : "");
			var st = (f ? s + "\t" : "");
			r = o.name + "(";
			for (var i in o.arguments) {
				r += st + trav(o.arguments[i], t + "\t") + (i < o.arguments.length - 1 ? ", " : "");
			}
			r += s + ")";
		} else if (o.type === "field") {
			r = "[" + o.field + "]";
		} else if (o.type === "param") {
			r =  "[&" + o.param + "]";
		} else if (o.type === "num") {
			r =  o.value;
		} else if (o.type === "str") {
			r = o.quote + o.value + o.quote;
		}

		if (p) {
			r = "(" + r + ")";
		}
		if (n) {
			r = "NOT " + r;
		}

	} else {
		r = o.toString();
	}
    return r;
}

$(document).ready(function(){
	$("#ExpParser").on("click", function() {
		var s = $("#ExpParserInput").val();
		console.log(s);
		if (s) {
			try {
				var o = SiebelQueryLang.parse(s);
				s = trav(o.expression, "");
			} catch(e) {
				s = e.toString();
			}
		} else {
			s = "Please, insert a Siebel expression first";
		}
		$("#ExpParserOutput").val(s);
	}).click();
})

The main outcome of the effort is, of course, to make it a part of Expression Playground. Check out an updated version here.