Commits

Mathias Panzenböck  committed d9721d2

opt++, opt bugfix, started enriching visitor

  • Participants
  • Parent commits fa1e7c7

Comments (0)

Files changed (4)

 exports.visitors.CloneVisitor = require("./lib/clonevisitor.js").CloneVisitor;
 exports.visitors.OptimizingVisitor = require("./lib/optimizingvisitor.js").OptimizingVisitor;
 exports.visitors.MinVisitor = require("./lib/minvisitor.js").MinVisitor;
-exports.nodes = require("./lib/nodes");
+exports.nodes = require("./lib/nodes.js");
+exports.transform = require("./lib/transform.js");
 
-function jsmin (code) {
+function optimize (code) {
 	if (typeof(code) === "string") code = esprima.parse(code);
-	return new exports.visitors.MinVisitor().visit(
-		new exports.visitors.OptimizingVisitor().visit(code));
+	return new exports.visitors.OptimizingVisitor().visit(code);
 }
 
-exports.jsmin = jsmin;
+function min (code) {
+	return new exports.visitors.MinVisitor().visit(optimize(code));
+}
+
+exports.optimize = optimize;
+exports.min = min;

File lib/minvisitor.js

 		return computed ? obj+"["+prop+"]" : obj+"."+prop;
 	},
 	switchCase: function (test, cons) {
+		if (!test) return "default:"+cons.join("");
 		return "case"+lwrap(test)+":"+cons.join("");
 	},
 	catchClause: function (arg, body) {

File lib/optimizingvisitor.js

 	var optimized = [], last;
 	for (var i = 0; i < statements.length; ++ i) {
 		var node = statements[i];
-		if (node.type !== "EmptyStatement" && !(
-			i === 0 &&
-			node.type === "ExpressionStatement" &&
-			node.expression.type === "Literal" &&
-			node.expression.value === "use strict")) {
-			if (last &&
-				node.type === "VariableDeclaration" &&
-				last.type === "VariableDeclaration" &&
-				node.kind === last.kind) {
-				last.declarations = last.declarations.concat(node.declarations);
-			}
-			else {
-				optimized.push(node);
-				last = node;
-			}
+		if (node.type === "EmptyStatement") continue;
+		if (node.type === "ExpressionStatement" &&
+			node.expression.type === "Literal") {
+			if (i !== 0 || node.expression.value !== "use strict") continue;
+		}
+		
+		if (last &&
+			node.type === "VariableDeclaration" &&
+			last.type === "VariableDeclaration" &&
+			node.kind === last.kind) {
+			last.declarations = last.declarations.concat(node.declarations);
+		}
+		else {
+			optimized.push(node);
+			last = node;
 		}
 	}
 	return optimized;
 					return new nodes.Literal(left.value instanceof right.value);
 			}
 		}
-		
 		return new nodes.BinaryExpression(op, left, right, loc);
 	},
 	unaryExpression: function (op, arg, loc) {
 		}
 		return new nodes.UnaryExpression(op, arg, loc);
 	},
+	logicalExpression: function (op, left, right, loc) {
+		if (left.type === 'Literal') {
+			if (op === '&&') {
+				return left.value ? right : left;
+			}
+			else {
+				return !left.value ? right : left;
+			}
+		}
+		return new nodes.LogicalExpression(op, left, right, loc);
+	},
 	ifStatement: function (test, cons, alt, loc) {
 		if (test.type === "Literal") {
 			if (test.value) {
 				return alt;
 			}
 			else {
-				return new nodes.EmptyStatement();
+				return new nodes.EmptyStatement(loc);
 			}
 		}
 		return new nodes.IfStatement(test, cons, alt, loc);
 	},
 	whileStatement: function (test, body, loc) {
 		if (test.type === "Literal" && !test.value) {
-			return new nodes.EmptyStatement();
+			return new nodes.EmptyStatement(loc);
 		}
 		return new nodes.WhileStatement(test, body, loc);
 	},
 	},
 	forStatement: function (init, test, update, body, loc) {
 		if (test.type === "Literal" && !test.value) {
-			return new nodes.EmptyStatement();
+			return new nodes.EmptyStatement(loc);
 		}
 		return new nodes.ForStatement(init, test, update, body, loc);
 	},

File lib/transform.js

+"use strict";
+
+var Visitor = require("./visitor.js").Visitor;
+
+function Scope (lexical, names) {
+	this.lexical = !!lexical;
+	this._names = {};
+	if (names) this.update(names);
+}
+
+Scope.prototype = {
+	add: function (name) {
+		this._names[name] = true;
+	},
+	remove: function (name) {
+		delete this._names[name];
+	},
+	has: function (name) {
+		return this._names[name] === true;
+	},
+	update: function (names) {
+		if (names instanceof Scope) {
+			for (var name in names._names) {
+				this._names[name] = true;
+			}
+		}
+		else if (Array.isArray(names)) {
+			for (var i = 0; i < names.length; ++ i) {
+				this._names[names[i]] = true;
+			}
+		}
+		else {
+			for (var name in names) {
+				this._names[name] = true;
+			}
+		}
+	},
+	toArray: function () {
+		var names = [];
+		for (var name in this._names) {
+			names.push(name);
+		}
+		return names;
+	},
+	toString: function () {
+		return "new Scope("+!!this.lexical+","+JSON.stringify(this.toArray())+")";
+	}
+};
+
+function Context () {
+	this.path = [];
+	this.scopes = [new Scope()];
+}
+
+Context.prototype = {
+};
+
+function EnrichingVisitor () {
+	this.scopes = [];
+	this.literalScope = null;
+	this.scope = null;
+}
+
+EnrichingVisitor.prototype = {
+	push: function (node,literal) {
+		// XXX: enrich with chained link of scopes, not a single one!	
+
+		node.scope = new Scope(literal);
+		this.scopes.push(node.scope);
+		return node.scope;
+	},
+	pop: function () {
+		return this.scopes.pop();
+	},
+	enrich: function () {
+	},
+	visitProgram: function (node) {
+		this.push(node);
+		node.body.forEach(this.visit.bind(this));
+		this.pop();
+	},
+	visitEmptyStatement: function (node) {
+
+	},
+	visitBlockStatement: function (node) {
+		this.push(node,true);
+		node.body.forEach(this.visit.bind(this));
+		this.pop();
+	},
+	visitExpressionStatement: function (node) {
+		this.visit(node.expression);
+	},
+	visitIfStatement: function (node) {
+		this.visit(node.test);
+		this.visit(node.consequent);
+		if (node.alternate) this.visit(node.alternate);
+	}
+
+
+};