function functionPointer() {
  return {
    semantics() {
      return {
        // Handle Table definitions
        [Syntax.ImmutableDeclaration]: next => function (args) {
          const [decl, context] = args;

          // Short circuit since memory is a special type of declaration
          if (!context.locals && decl.type === 'Table') {
            return _extends({}, decl, {
              meta: _extends({}, decl.meta, {
                [GLOBAL_INDEX]: -1
              })
            });
          }

          return next(args);
        },
        [Syntax.Identifier]: next => function (args) {
          const [node, context] = args;
          const { functions, table, scopes } = context;

          if (scope_4(scopes, node.value) || !functions[node.value]) {
            return next(args);
          }

          if (table[node.value] == null) {
            table[node.value] = functions[node.value];
          }
          return _extends({}, node, {
            type: 'i32',
            meta: {
              [FUNCTION_INDEX]: functions[node.value].meta[FUNCTION_INDEX]
            },
            value: Object.keys(table).indexOf(node.value),
            Type: Syntax.FunctionPointer
          });
        },
        [Syntax.FunctionResult]: next => (args, transform) => {
          const [node, context] = args;
          const { types } = context;
          if (!types[node.type]) {
            return next(args);
          }

          return next([extendNode({
            type: 'i32',
            meta: { ALIAS: node.type },
            params: node.params.map(p => transform([p, context]))
          }, node), context]);
        },
        [Syntax.FunctionCall]: next => function (args, transform) {
          const [call, context] = args;
          const { scopes, types } = context;
          const ref = scope_4(scopes, call.value);
          // Nothing we need transform
          if (!ref) {
            return next(args);
          }

          const typedef = types[ref.type];
          const typeIndex = Object.keys(types).indexOf(ref.type);

          // We will short all of the other middleware so transform the parameters
          // here and append an identifier which will be used to get the table
          // value
          const params = [...call.params.slice(1), _extends({}, ref, { Type: Syntax.Identifier })].map(p => transform([p, context]));

          return _extends({}, call, {
            meta: _extends({}, call.meta, ref.meta, {
              [TYPE_INDEX]: typeIndex
            }),
            type: typedef != null ? typedef.type : call.type,
            params,
            Type: Syntax.IndirectFunctionCall
          });
        }
      };
    }
  };
}
Function pointer plugin.
Handles function pointer declaration and indirect calls.