vendor/lib/visitor/evaluator.js in stylus-source-0.40.3 vs vendor/lib/visitor/evaluator.js in stylus-source-0.41.0

- old
+ new

@@ -424,11 +424,11 @@ debug('%s is built-in', call); ret = this.invokeBuiltin(fn.fn, args); // User-defined } else if ('function' == fn.nodeName) { debug('%s is user-defined', call); - ret = this.invokeFunction(fn, args); + ret = this.invokeFunction(fn, args, call.block); } // restore kwargs for (key in mapCopy) { args.map[key] = mapCopy[key]; @@ -452,10 +452,12 @@ } return nodes.null; // Lookup } else if (ident.val.isNull) { var val = this.lookup(ident.name); + // Object or Block mixin + if (val && ident.mixin) this.mixinNode(val); return val ? this.visit(val) : ident; // Assign } else { this.return++; ident.val = this.visit(ident.val); @@ -799,11 +801,11 @@ * @param {Array} args * @return {Node} * @api private */ -Evaluator.prototype.invokeFunction = function(fn, args){ +Evaluator.prototype.invokeFunction = function(fn, args, content){ var block = new nodes.Block(fn.block.parent); fn.block.parent = block; // Clone the function body // to prevent mutation of subsequent calls @@ -858,10 +860,13 @@ } scope.add(node); }); + // mixin block + if (content) scope.add(new nodes.Ident('block', content, true)); + // invoke return this.invoke(body, true, fn.filename); }; /** @@ -980,10 +985,64 @@ } } }; /** + * Mixin the given `node` to the current block. + * + * @param {Node} node + * @api private + */ + +Evaluator.prototype.mixinNode = function(node){ + node = this.visit(node.first); + var name = node.nodeName; + if ('object' == name || 'block' == name) { + 'block' == name + ? this.mixin(node.nodes, this.currentBlock) + // HACK + : this.mixinObject(node); + return nodes.null; + } +}; + +/** + * Mixin the given `object` to the current block. + * + * @param {Object} object + * @api private + */ + +Evaluator.prototype.mixinObject = function(object){ + var Parser = require('../parser') + , root = this.root + , str = '@block ' + object.toBlock() + , parser = new Parser(str, utils.merge({ root: block }, this.options)) + , block; + + try { + block = parser.parse(); + } catch (err) { + err.filename = this.filename; + err.lineno = parser.lexer.lineno; + err.input = str; + throw err; + } + + block.parent = root; + block.scope = false; + var ret = this.visit(block) + , vals = ret.first.nodes; + for (var i = 0, len = vals.length; i < len; ++i) { + if (vals[i].block) { + this.mixin(vals[i].block.nodes, this.currentBlock); + break; + } + } +}; + +/** * Evaluate the given `vals`. * * @param {Array} vals * @return {Node} * @api private @@ -1101,9 +1160,29 @@ case 'media': return block; } } } +}); + +/** + * Return the current selector. + * + * @return {String} + * @api private + */ + +Evaluator.prototype.__defineGetter__('currentSelector', function(){ + var block + , stack = []; + for (var i = 0, len = this.stack.length; i < len; ++i) { + block = this.stack[i].block; + if (block.node && 'group' == block.node.nodeName) { + stack.push(block.node.nodes); + } + } + if (!stack.length) return '&'; + return utils.compileSelectors(stack).join(','); }); /** * Lookup `name`, with support for JavaScript * functions, and BIFs.