3 var use = require('use');
4 var define = require('define-property');
5 var debug = require('debug')('snapdragon:compiler');
6 var utils = require('./utils');
9 * Create a new `Compiler` with the given `options`.
10 * @param {Object} `options`
13 function Compiler(options, state) {
14 debug('initializing', __filename);
15 this.options = utils.extend({source: 'string'}, options);
16 this.state = state || {};
19 this.set('eos', function(node) {
20 return this.emit(node.val, node);
22 this.set('noop', function(node) {
23 return this.emit(node.val, node);
25 this.set('bos', function(node) {
26 return this.emit(node.val, node);
35 Compiler.prototype = {
38 * Throw an error message with details including the cursor position.
39 * @param {String} `msg` Message to use in the Error.
42 error: function(msg, node) {
43 var pos = node.position || {start: {column: 0}};
44 var message = this.options.source + ' column:' + pos.start.column + ': ' + msg;
46 var err = new Error(message);
48 err.column = pos.start.column;
49 err.source = this.pattern;
51 if (this.options.silent) {
52 this.errors.push(err);
59 * Define a non-enumberable property on the `Compiler` instance.
62 * compiler.define('foo', 'bar');
65 * @param {String} `key` propery name
66 * @param {any} `val` property value
67 * @return {Object} Returns the Compiler instance for chaining.
71 define: function(key, val) {
72 define(this, key, val);
80 emit: function(str, node) {
86 * Add a compiler `fn` with the given `name`
89 set: function(name, fn) {
90 this.compilers[name] = fn;
95 * Get compiler `name`.
99 return this.compilers[name];
103 * Get the previous AST node.
107 return this.ast.nodes[this.idx - (n || 1)] || { type: 'bos', val: '' };
111 * Get the next AST node.
115 return this.ast.nodes[this.idx + (n || 1)] || { type: 'eos', val: '' };
122 visit: function(node, nodes, i) {
123 var fn = this.compilers[node.type];
126 if (typeof fn !== 'function') {
127 throw this.error('compiler "' + node.type + '" is not registered', node);
129 return fn.call(this, node, nodes, i);
133 * Map visit over array of `nodes`.
136 mapVisit: function(nodes) {
137 if (!Array.isArray(nodes)) {
138 throw new TypeError('expected an array');
140 var len = nodes.length;
142 while (++idx < len) {
143 this.visit(nodes[idx], nodes, idx);
152 compile: function(ast, options) {
153 var opts = utils.extend({}, this.options, options);
155 this.parsingErrors = this.ast.errors;
158 // source map support
159 if (opts.sourcemap) {
160 var sourcemaps = require('./source-maps');
162 this.mapVisit(this.ast.nodes);
163 this.applySourceMaps();
164 this.map = opts.sourcemap === 'generator' ? this.map : this.map.toJSON();
168 this.mapVisit(this.ast.nodes);
177 module.exports = Compiler;