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.