aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMihai Bazon <mihai@bazon.net>2012-09-18 13:21:09 +0300
committerMihai Bazon <mihai@bazon.net>2012-09-18 13:21:09 +0300
commit3da0ac4897e1b12adbdedbfa1c3a145931f0af56 (patch)
tree155d17888ea85824a6aef7e81d176cb51a43cf7b
parent21968285e8fad1cfe775b389c6bcd16e14b62c6c (diff)
downloadtracifyjs-3da0ac4897e1b12adbdedbfa1c3a145931f0af56.tar.gz
tracifyjs-3da0ac4897e1b12adbdedbfa1c3a145931f0af56.zip
support for directives
-rw-r--r--lib/ast.js4
-rw-r--r--lib/compress.js11
-rw-r--r--lib/output.js1
-rw-r--r--lib/parse.js4
-rw-r--r--lib/scope.js11
5 files changed, 27 insertions, 4 deletions
diff --git a/lib/ast.js b/lib/ast.js
index 39a62b16..5c4b7e6a 100644
--- a/lib/ast.js
+++ b/lib/ast.js
@@ -126,7 +126,7 @@ var AST_Debugger = DEFNODE("Debugger", null, {
$documentation: "Represents a debugger statement"
}, AST_StatementBase);
-var AST_Directive = DEFNODE("Directive", "value", {
+var AST_Directive = DEFNODE("Directive", "value scope", {
$documentation: "Represents a directive, like \"use strict\";"
}, AST_StatementBase);
@@ -235,7 +235,7 @@ var AST_With = DEFNODE("With", "expression", {
/* -----[ scope and functions ]----- */
-var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
+var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
$documentation: "Base class for all statements introducing a lexical scope",
}, AST_Block);
diff --git a/lib/compress.js b/lib/compress.js
index aedd78fd..9d5dac17 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -742,6 +742,13 @@ function Compressor(options, false_by_default) {
/* -----[ node squeezers ]----- */
+ SQUEEZE(AST_Directive, function(self, compressor){
+ if (self.hoisted || self.scope.has_directive(self.value) !== self.scope) {
+ return new AST_EmptyStatement(self);
+ }
+ return self;
+ });
+
SQUEEZE(AST_Debugger, function(self, compressor){
if (compressor.option("drop_debugger"))
return new AST_EmptyStatement(self);
@@ -796,6 +803,10 @@ function Compressor(options, false_by_default) {
var vars = {}, vars_found = 0, vardecl = [];
var tw = new TreeWalker(function(node){
if (node !== self) {
+ if (node instanceof AST_Directive && (hoist_funs || hoist_vars) && !node.hoisted) {
+ hoisted.unshift(node.clone());
+ node.hoisted = true;
+ }
if (node instanceof AST_Defun && hoist_funs && !node.hoisted) {
hoisted.push(node.clone());
node.hoisted = true;
diff --git a/lib/output.js b/lib/output.js
index ee11aebc..149fc05e 100644
--- a/lib/output.js
+++ b/lib/output.js
@@ -428,6 +428,7 @@ function OutputStream(options) {
DEFPRINT(AST_Directive, function(self, output){
output.print_string(self.value);
+ output.semicolon();
});
DEFPRINT(AST_Debugger, function(self, output){
output.print("debugger");
diff --git a/lib/parse.js b/lib/parse.js
index 77c75343..6a5aad26 100644
--- a/lib/parse.js
+++ b/lib/parse.js
@@ -773,8 +773,8 @@ function parse($TEXT, exigent_mode) {
case "string":
var dir = S.in_directives, stat = simple_statement();
// XXXv2: decide how to fix directives
- // if (dir && stat instanceof AST_String && !is("punc", ","))
- // return new AST_Directive({ value: stat.value });
+ if (dir && stat.body instanceof AST_String && !is("punc", ","))
+ return new AST_Directive({ value: stat.body.value });
return stat;
case "num":
case "regexp":
diff --git a/lib/scope.js b/lib/scope.js
index 79d6e91d..dfbff4b8 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -82,6 +82,11 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
scope = save_scope;
return true; // don't descend again in TreeWalker
}
+ if (node instanceof AST_Directive) {
+ node.scope = scope;
+ push_uniq(scope.directives, node.value);
+ return true;
+ }
if (node instanceof AST_With) {
for (var s = scope; s; s = s.parent_scope)
s.uses_with = true;
@@ -193,6 +198,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
});
AST_Scope.DEFMETHOD("init_scope_vars", function(){
+ this.directives = []; // contains the directives defined in this scope, i.e. "use strict"
this.variables = {}; // map name to AST_SymbolVar (variables defined in this scope; includes functions)
this.functions = {}; // map name to AST_SymbolDefun (functions defined in this scope)
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
@@ -233,6 +239,11 @@ AST_Scope.DEFMETHOD("find_variable", function(name){
: (this.parent_scope && this.parent_scope.find_variable(name));
});
+AST_Scope.DEFMETHOD("has_directive", function(value){
+ return this.parent_scope && this.parent_scope.has_directive(value)
+ || (this.directives.indexOf(value) >= 0 ? this : null);
+});
+
AST_Scope.DEFMETHOD("def_function", function(symbol){
this.functions[symbol.name] = this.def_variable(symbol);
});