Skip to content

Commit

Permalink
Better parse tree example
Browse files Browse the repository at this point in the history
  • Loading branch information
tj committed Sep 24, 2010
1 parent dbf7807 commit 65a2238
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 29 deletions.
5 changes: 4 additions & 1 deletion examples/parsetree.jade
@@ -1,5 +1,8 @@
:conditionals
if role == 'admin'
p User #{name} is an administrator
if name == 'tj'
p User is a wicked cool administrator
else
p User #{name} is an administrator
else
p User #{name} is a guest
56 changes: 35 additions & 21 deletions examples/parsetree.js
Expand Up @@ -5,6 +5,7 @@
*/

var jade = require('./../lib/jade'),
Compiler = jade.Compiler,
nodes = jade.nodes;

var options = {
Expand All @@ -20,26 +21,39 @@ jade.renderFile(__dirname + '/parsetree.jade', options, function(err, html){
console.log(html);
});

// To support nesting etc you will need to create a more
// robust compiler, view ./lib/compiler.js for the core example.
jade.filters.conditionals = function(block, compiler){
return new Visitor(block).compile();
};

// Without our filter we could either construct an entirely new string,
// and simply return it (using "buf.push('buffered text')") etc, or utilize
// the core compiler which is passed
function Visitor(node) {
this.node = node;
}

jade.filters.conditionals = function(block, compiler){
block.nodes.forEach(function(node, i){
switch (node.name) {
case 'if':
block.nodes[i] = new nodes.Code('if (' + node.block.nodes[0].lines[0] + ')');
node.block.nodes.shift();
block.nodes[i].block = node.block;
break;
case 'else':
block.nodes[i] = new nodes.Code('else');
block.nodes[i].block = node.block;
break;
}
});
compiler.visit(block);
};
Visitor.prototype.__proto__ = Compiler.prototype;

Visitor.prototype.visit = function(node){
if (node.name != 'else') this.line(node);
this.visitNode(node);
};

Visitor.prototype.visitTag = function(node){
switch (node.name) {
case 'if':
var condition = node.block.nodes[0].lines[0],
block = node.block;
block.nodes.shift();
node = new nodes.Code('if (' + condition + ')', false);
node.block = block;
this.visit(node);
break;
case 'else':
var block = node.block;
node = new nodes.Code('else', false);
node.block = block;
node.instrumentLineNumber = false;
this.visit(node);
break;
default:
Compiler.prototype.visitTag.call(this, node);
}
};
23 changes: 16 additions & 7 deletions lib/compiler.js
Expand Up @@ -74,6 +74,7 @@ Compiler.prototype = {
*/

line: function(node){
if (node.instrumentLineNumber === false) return;
this.buf.push('_.lineno = ' + node.line + ';');
},

Expand All @@ -85,11 +86,19 @@ Compiler.prototype = {
*/

visit: function(node){
var name = node.constructor.name;
if (name != 'Code' || !node.val.match(/^ *else/)) {
this.line(node);
}
return this['visit' + name](node);
this.line(node);
return this.visitNode(node);
},

/**
* Visit `node`.
*
* @param {Node} node
* @api private
*/

visitNode: function(node){
return this['visit' + node.constructor.name](node);
},

/**
Expand Down Expand Up @@ -228,9 +237,9 @@ Compiler.prototype = {
this.buf.push(code.val);
}
if (code.block) {
this.buf.push('(function(){');
this.buf.push(' (function(){');
this.visit(code.block);
this.buf.push('}).call(this);');
this.buf.push(' }).call(this);');
}
},

Expand Down
1 change: 1 addition & 0 deletions lib/nodes/code.js
Expand Up @@ -6,6 +6,7 @@ var Code = module.exports = function Code(val, buffer, escape) {
this.val = val;
this.buffer = buffer;
this.escape = escape;
if (/^ *else/.test(val)) this.instrumentLineNumber = false;
};

Code.prototype.__proto__ = Node.prototype;
16 changes: 16 additions & 0 deletions test/jade.test.js
Expand Up @@ -594,6 +594,22 @@ module.exports = {
'<p class="noFoo">no foo</p>'
].join('');

assert.equal(html, render(str));

var str = [
'- var foo;',
'- if (foo)',
' p.hasFoo= foo',
'- else if (true)',
' p kinda foo',
'- else',
' p.noFoo no foo'
].join('\n');

var html = [
'<p>kinda foo</p>'
].join('');

assert.equal(html, render(str));

var str = [
Expand Down

0 comments on commit 65a2238

Please sign in to comment.