text: function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  
  function _sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
  
  function _slicedToArray(arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return _sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }
  
  import { isBlock, isFunc, isIdentifier, numberLiteralFromRaw, traverse } from "../../index";
  import { moduleContextFromModuleAST } from "../ast-module-to-module-context"; // FIXME(sven): do the same with all block instructions, must be more generic here
  
  function newUnexpectedFunction(i) {
    return new Error("unknown function at offset: " + i);
  }
  
  export function transform(ast) {
    var module;
    traverse(ast, {
      Module: function (_Module) {
        function Module(_x) {
          return _Module.apply(this, arguments);
        }
  
        Module.toString = function () {
          return _Module.toString();
        };
  
        return Module;
      }(function (path) {
        module = path.node;
      })
    });
    var moduleContext = moduleContextFromModuleAST(module); // Transform the actual instruction in function bodies
  
    traverse(ast, {
      Func: function (_Func) {
        function Func(_x2) {
          return _Func.apply(this, arguments);
        }
  
        Func.toString = function () {
          return _Func.toString();
        };
  
        return Func;
      }(function (path) {
        transformFuncPath(path, moduleContext);
      }),
      Start: function (_Start) {
        function Start(_x3) {
          return _Start.apply(this, arguments);
        }
  
        Start.toString = function () {
          return _Start.toString();
        };
  
        return Start;
      }(function (path) {
        var index = path.node.index;
  
        if (isIdentifier(index) === true) {
          var offsetInModule = moduleContext.getFunctionOffsetByIdentifier(index.value);
  
          if (typeof offsetInModule === "undefined") {
            throw newUnexpectedFunction(index.value);
          } // Replace the index Identifier
          // $FlowIgnore: reference?
  
  
          path.node.index = numberLiteralFromRaw(offsetInModule);
        }
      })
    });
  }
  
  function transformFuncPath(funcPath, moduleContext) {
    var funcNode = funcPath.node;
    var signature = funcNode.signature;
  
    if (signature.type !== "Signature") {
      throw new Error("Function signatures must be denormalised before execution");
    }
  
    var params = signature.params; // Add func locals in the context
  
    params.forEach(function (p) {
      return moduleContext.addLocal(p.valtype);
    });
    traverse(funcNode, {
      Instr: function (_Instr) {
        function Instr(_x4) {
          return _Instr.apply(this, arguments);
        }
  
        Instr.toString = function () {
          return _Instr.toString();
        };
  
        return Instr;
      }(function (instrPath) {
        var instrNode = instrPath.node;
        /**
         * Local access
         */
  
        if (instrNode.id === "get_local" || instrNode.id === "set_local" || instrNode.id === "tee_local") {
          var _instrNode$args = _slicedToArray(instrNode.args, 1),
              firstArg = _instrNode$args[0];
  
          if (firstArg.type === "Identifier") {
            var offsetInParams = params.findIndex(function (_ref) {
              var id = _ref.id;
              return id === firstArg.value;
            });
  
            if (offsetInParams === -1) {
              throw new Error("".concat(firstArg.value, " not found in ").concat(instrNode.id, ": not declared in func params"));
            } // Replace the Identifer node by our new NumberLiteral node
  
  
            instrNode.args[0] = numberLiteralFromRaw(offsetInParams);
          }
        }
        /**
         * Global access
         */
  
  
        if (instrNode.id === "get_global" || instrNode.id === "set_global") {
          var _instrNode$args2 = _slicedToArray(instrNode.args, 1),
              _firstArg = _instrNode$args2[0];
  
          if (isIdentifier(_firstArg) === true) {
            var globalOffset = moduleContext.getGlobalOffsetByIdentifier( // $FlowIgnore: reference?
            _firstArg.value);
  
            if (typeof globalOffset === "undefined") {
              // $FlowIgnore: reference?
              throw new Error("global ".concat(_firstArg.value, " not found in module"));
            } // Replace the Identifer node by our new NumberLiteral node
  
  
            instrNode.args[0] = numberLiteralFromRaw(globalOffset);
          }
        }
        /**
         * Labels lookup
         */
  
  
        if (instrNode.id === "br") {
          var _instrNode$args3 = _slicedToArray(instrNode.args, 1),
              _firstArg2 = _instrNode$args3[0];
  
          if (isIdentifier(_firstArg2) === true) {
            // if the labels is not found it is going to be replaced with -1
            // which is invalid.
            var relativeBlockCount = -1; // $FlowIgnore: reference?
  
            instrPath.findParent(function (_ref2) {
              var node = _ref2.node;
  
              if (isBlock(node)) {
                relativeBlockCount++; // $FlowIgnore: reference?
  
                var name = node.label || node.name;
  
                if (_typeof(name) === "object") {
                  // $FlowIgnore: isIdentifier ensures that
                  if (name.value === _firstArg2.value) {
                    // Found it
                    return false;
                  }
                }
              }
  
              if (isFunc(node)) {
                return false;
              }
            }); // Replace the Identifer node by our new NumberLiteral node
  
            instrNode.args[0] = numberLiteralFromRaw(relativeBlockCount);
          }
        }
      }),
  
      /**
       * Func lookup
       */
      CallInstruction: function (_CallInstruction) {
        function CallInstruction(_x5) {
          return _CallInstruction.apply(this, arguments);
        }
  
        CallInstruction.toString = function () {
          return _CallInstruction.toString();
        };
  
        return CallInstruction;
      }(function (_ref3) {
        var node = _ref3.node;
        var index = node.index;
  
        if (isIdentifier(index) === true) {
          var offsetInModule = moduleContext.getFunctionOffsetByIdentifier(index.value);
  
          if (typeof offsetInModule === "undefined") {
            throw newUnexpectedFunction(index.value);
          } // Replace the index Identifier
          // $FlowIgnore: reference?
  
  
          node.index = numberLiteralFromRaw(offsetInModule);
        }
      })
    });
  }