text: "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;
  