marko/compiler/ast/InvokeMacro.js
2016-01-19 10:48:19 -07:00

121 lines
3.4 KiB
JavaScript

'use strict';
var Node = require('./Node');
var ok = require('assert').ok;
function removeTrailingUndefineds(args) {
var i;
var last = args.length-1;
for (i=last; i>=0; i--) {
if (args[i].type !== 'Literal' || args[i].value !== undefined) {
break;
}
}
if (i !== last) {
args = args.slice(0, i+1);
}
return args;
}
class InvokeMacro extends Node {
constructor(def) {
super('InvokeMacro');
this.el = def.el;
this.name = def.name;
this.args = def.args;
this.body = this.makeContainer(def.body);
if (this.name != null) {
ok(typeof this.name === 'string', 'Invalid macro name: ' + this.name);
}
}
generateCode(codegen) {
var el = this.el;
var name = this.name;
var args = this.args;
var body = this.body;
var builder = codegen.builder;
var macroDef;
if (el) {
name = el.tagName;
body = el.body;
if (typeof name !== 'string') {
codegen.context.addError(el, 'Element node with a dynamic tag name cannot be used to invoke a macro', 'ERR_INVOKE_MACRO');
return;
}
macroDef = codegen.context.getRegisteredMacro(name);
if (!macroDef) {
codegen.context.addError(el, 'Element node does not correspond to a macro', 'ERR_INVOKE_MACRO');
return;
}
if (el.argument) {
args = builder.parseJavaScriptArgs(el.argument);
} else {
args = new Array(macroDef.params.length);
for (let i=0; i<args.length; i++) {
args[i] = builder.literal(undefined);
}
el.forEachAttribute((attr) => {
var paramName = attr.name;
var paramIndex = macroDef.getParamIndex(paramName);
if (paramIndex == null) {
codegen.context.addError(el, 'The "' + name + '" macro does not have a parameter named "' + paramName + '"', 'ERR_INVOKE_MACRO');
return;
}
var value = attr.value;
if (value == null) {
value = builder.literal(true);
}
args[paramIndex] = value;
});
}
} else {
macroDef = codegen.context.getRegisteredMacro(name);
if (!macroDef) {
codegen.addError('Macro not found with name "' + name + '"', 'ERR_INVOKE_MACRO');
return;
}
}
if (!args) {
args = [];
}
while (args.length < macroDef.params.length) {
args.push(builder.literal(undefined));
}
if (body && body.length) {
args[macroDef.getParamIndex('renderBody')] = builder.renderBodyFunction(body);
}
args[macroDef.getParamIndex('out')] = builder.identifier('out');
args = removeTrailingUndefineds(args);
return builder.functionCall(builder.identifier(macroDef.functionName), args);
}
walk(walker) {
this.el = walker.walk(this.el);
this.name = walker.walk(this.name);
this.args = walker.walk(this.args);
this.body = walker.walk(this.body);
}
}
module.exports = InvokeMacro;