Skip to content

Commit

Permalink
base: save progress on fetch/local
Browse files Browse the repository at this point in the history
  • Loading branch information
indutny committed Mar 20, 2014
1 parent 62586a0 commit 04b3512
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 74 deletions.
93 changes: 69 additions & 24 deletions lib/xjst/compiler/base.js
Expand Up @@ -92,7 +92,7 @@ Compiler.prototype.generate = function generate(code) {
' // Just ignore any errors\n' +
'}\n' +
'function templates(template, local, apply, applyNext, oninit, ' +
'__$$fetch) {\n' +
'__$$fetch, __$$set) {\n' +
'/// -------------------------------------\n' +
'/// ---------- Bootstrap end ------------\n' +
'/// -------------------------------------\n' +
Expand Down Expand Up @@ -312,7 +312,7 @@ Compiler.prototype.sanitize = function sanitize(stmt) {
// Replace `this` with `__$ctx`
Compiler.prototype.replaceThis = function replaceThis(stmt) {
var ctx = this.ctx;
estraverse.replace(stmt, {
return estraverse.replace(stmt, {
enter: function(node, parent, notify) {
if (node.type === 'ThisExpression') {
return ctx;
Expand All @@ -322,7 +322,37 @@ Compiler.prototype.replaceThis = function replaceThis(stmt) {
}
}
});
return stmt;
};

Compiler.prototype.replaceFetch = function replaceFetch(stmt) {
var self = this;
return estraverse.replace(stmt, {
enter: function(node, parent, notify) {
if (node.type === 'CallExpression' &&
node.callee.type === 'Identifier') {
if (node.callee.name !== '__$$fetch' &&
node.callee.name !== '__$$set') {
return;
}
assert(node.arguments.length >= 1);
assert.equal(node.arguments[0].type, 'Literal');

var id = self.fetchGlobal(node.arguments[0].value);

if (node.callee.name === '__$$fetch') {
return id;
} else {
assert.equal(node.arguments.length, 2);
return {
type: 'AssignmentExpression',
operator: '=',
left: id,
right: node.arguments[1]
};
}
}
}
});
};

Compiler.prototype.jailVars = function jailVars(stmt) {
Expand Down Expand Up @@ -491,7 +521,7 @@ Compiler.prototype.checkRef = function checkRef(expr) {
}

// Fastest case, just literal
if (cantBeRef(expr))
if (!expr || cantBeRef(expr))
return { apply: [{ type: 'ReturnStatement', argument: expr }] };

// Simple case
Expand Down Expand Up @@ -677,9 +707,24 @@ Compiler.prototype.sortGroup = function sortGroup(templates) {
return out;
};

Compiler.prototype.registerGlobal = function registerGlobal(name) {
if (name !== '__proto__')
this.globals[name] = true;
Compiler.prototype.fetchGlobal = function fetchGlobal(name) {
var parts = name.split('.');
var parent = '$$' + parts[0];

if (parent !== '__proto__')
this.globals[parent] = true;

var ret = { type: 'Identifier', name: parent };
for (var i = 1; i < parts.length; i++) {
ret = {
type: 'MemberExpression',
computed: true,
object: ret,
property: { type: 'Literal', value: parts[i] }
};
}

return ret;
};

Compiler.prototype.registerExtension = function registerExtension(name) {
Expand Down Expand Up @@ -770,7 +815,7 @@ Compiler.prototype.render = function render(program, bodyOnly) {
var stmts = [],
initializers = program.init.slice(),
applyBody = program.other.map(function(stmt) {
return this.sanitize(stmt);
return this.replaceFetch(this.sanitize(stmt));
}, this),
applyContext = {
type: 'LogicalExpression',
Expand Down Expand Up @@ -855,22 +900,6 @@ Compiler.prototype.render = function render(program, bodyOnly) {
}]
});

// global variables
var globals = Object.keys(this.globals);
if (globals.length !== 0) {
stmts.push({
type: 'VariableDeclaration',
kind: 'var',
declarations: globals.map(function(name) {
return {
type: 'VariableDeclarator',
id: { type: 'Identifier', name: name },
init: null
};
})
});
}

// exports.apply = apply
stmts.push(apply);
stmts.push({
Expand Down Expand Up @@ -948,6 +977,22 @@ Compiler.prototype.render = function render(program, bodyOnly) {
// Render each template
var out = this.renderArray(program.templates);

// global variables
var globals = Object.keys(this.globals);
if (globals.length !== 0) {
stmts.unshift({
type: 'VariableDeclaration',
kind: 'var',
declarations: globals.map(function(name) {
return {
type: 'VariableDeclarator',
id: { type: 'Identifier', name: name },
init: null
};
})
});
}

/// Apply to the bottom
if (out.apply) applyBody = applyBody.concat(out.apply);

Expand Down
68 changes: 37 additions & 31 deletions lib/xjst/compiler/entities/body.js
Expand Up @@ -148,6 +148,11 @@ Body.prototype.rollOutSpecific = function rollOutSpecific(node) {
assert.equal(node.arguments.length, 1);
assert.equal(node.arguments[0].type, 'Literal');
return this.rollOutFetch(node.arguments[0].value);
} else if (name === '__$$set') {
assert.equal(node.arguments.length, 2);
assert.equal(node.arguments[0].type, 'Literal');
return this.rollOutSet(node.arguments[0].value,
node.arguments[1]);
}
// local(locals)(body)
} else if (node.callee.type === 'CallExpression' &&
Expand Down Expand Up @@ -241,37 +246,32 @@ Body.prototype.rollOutLocal = function rollOutLocal(ast, changes, body) {
});
}

// `local(null, { a: 1 })` should be translated to
// `var oldA = a; a = 1; ...; a = oldA;`
var isGlobal = changes.some(function(change) {
return change.type === 'Literal' && change.value === null;
});

// Generate list of prop/value pairs
changes.forEach(function(change) {
if (change.type === 'Literal')
return;
assert.equal(change.type, 'ObjectExpression');
change.properties.forEach(function(property) {
var keys = (property.key.name || property.key.value).split('.'),
prop = keys.reduce(function(left, right, i, l) {
if (isGlobal && left === ctx) {
var sub = { type: 'Identifier', name: '$$' + right };

self.compiler.registerGlobal('$$' + right);
} else {
var sub = {
type: 'MemberExpression',
computed: false,
object: left,
property: { type: 'Identifier', name: right }
};

self.compiler.registerExtension(right);
}

return sub;
}, ctx);
var keys = (property.key.name || property.key.value).split('.');
var isGlobal = keys[0] === '$$global';
if (isGlobal)
keys.shift();
if (isGlobal) {
var prop = this.compiler.fetchGlobal(keys.join('.'));
} else {
var prop = keys.reduce(function(left, right, i, l) {
var sub = {
type: 'MemberExpression',
computed: false,
object: left,
property: { type: 'Identifier', name: right }
};

self.compiler.registerExtension(right);

return sub;
}, ctx);
}

addPair(this.compiler.sanitize(prop),
this.compiler.sanitize(property.value));
Expand All @@ -289,10 +289,7 @@ Body.prototype.rollOutLocal = function rollOutLocal(ast, changes, body) {
arguments: []
};

if (isGlobal)
this.compiler.addChange([]);
else
this.compiler.addChange(predicates);
this.compiler.addChange(predicates);
if (typeof body === 'function') {
body = body.call(this);
}
Expand Down Expand Up @@ -333,7 +330,7 @@ Body.prototype.rollOutLocal = function rollOutLocal(ast, changes, body) {

left = {
type: 'MemberExpression',
computed: false,
computed: left.computed,
object: tmp,
property: left.property
};
Expand Down Expand Up @@ -413,7 +410,16 @@ Body.prototype.rollOutLocal = function rollOutLocal(ast, changes, body) {
};

Body.prototype.rollOutFetch = function rollOutFetch(id) {
return { type: 'Identifier', name: '$$' + id };
return this.compiler.fetchGlobal(id);
};

Body.prototype.rollOutSet = function rollOutSet(id, value) {
return {
type: 'AssignmentExpression',
operator: '=',
left: this.compiler.fetchGlobal(id),
right: value
};
};

// Render body
Expand Down
2 changes: 1 addition & 1 deletion lib/xjst/compiler/entities/group.js
Expand Up @@ -44,7 +44,7 @@ Group.prototype._render = function render() {
declarations: [{
type: 'VariableDeclarator',
id: t,
init: this.predicate.expr
init: this.predicate.getExpr()
}]
});

Expand Down
6 changes: 3 additions & 3 deletions lib/xjst/compiler/entities/map.js
Expand Up @@ -10,13 +10,13 @@ function Map(compiler, pairs) {
this.shareable = false;
this.pairs = {};
if (pairs && pairs.length >= 1) {
this.predicate = pairs[0].predicate.expr;
this.predicate = pairs[0].predicate.getExpr();
this.predicateId = pairs[0].predicate.id;

pairs.forEach(function(pair) {
pair.bodies.forEach(function(body) {
assert(pair.predicate.value !== null);
this.add(pair.predicate.expr, pair.predicate.value, body);
this.add(this.predicate, pair.predicate.value, body);
}, this);
}, this);
} else {
Expand Down Expand Up @@ -46,7 +46,7 @@ Map.prototype.mapChildren = function mapChildren(fn, ctx) {
};

Map.prototype.add = function add(predicate, value, body) {
assert(value.type === 'Literal' && typeof value.value === 'string');
assert(value.type === 'Literal');
if (this.predicate === null) {
this.predicate = predicate;
this.predicateId = this.compiler.getId(predicate);
Expand Down
10 changes: 7 additions & 3 deletions lib/xjst/compiler/entities/predicate.js
Expand Up @@ -31,11 +31,11 @@ Predicate.prototype.render = function render() {
return {
type: 'BinaryExpression',
operator: '===',
left: this.expr,
right: this.value
left: this.getExpr(),
right: this.compiler.replaceFetch(this.value)
};
} else {
return this.expr;
return this.getExpr();
}
};

Expand All @@ -49,3 +49,7 @@ Predicate.prototype.simplify = function simplify() {
this.value = null;
}
};

Predicate.prototype.getExpr = function getExpr() {
return this.compiler.replaceFetch(this.expr);
};

0 comments on commit 04b3512

Please sign in to comment.