# All files / src/core function-pointer.js

100% Statements 28/28
100% Branches 12/12
100% Functions 8/8
100% Lines 28/28

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    9023x
    23x

    87x

    87x

    87x
    111x

    111x
    3x

    108x

    87x
    580x
    580x

    580x
    573x

    7x
    6x

    7x

    87x
    176x
    176x
    176x

    176x
    174x

    2x
    2x

    2x

    2x

    2x

     import Syntax from '../Syntax';
    import {
      TYPE_INDEX,
      GLOBAL_INDEX,
      FUNCTION_INDEX,
    } from '../semantics/metadata';

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

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

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

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

                if (table[node.value] == null) {
                  table[node.value] = functions[node.value];
                }

                return {
                  ...node,
                  type: 'i32',
                  meta: {
                    [FUNCTION_INDEX]: functions[node.value].meta[FUNCTION_INDEX],
                  },
                  value: Object.keys(table).indexOf(node.value),
                  Type: Syntax.FunctionPointer,
                };
              },
            FunctionCall: next =>
              function indirectCall(args, transform) {
                const [call, context] = args;
                const { locals, types } = context;
                const local = locals[call.value];
                // Nothing we need transform
                if (!local) {
                  return next(args);
                }

                const typedef = types[local.type];
                const typeIndex = Object.keys(types).indexOf(local.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,
                  { ...local, Type: Syntax.Identifier },
                ].map(p => transform([p, context]));

                return {
                  ...call,
                  meta: {
                    ...call.meta,
                    ...local.meta,
                    [TYPE_INDEX]: typeIndex,
                  },
                  type: typedef != null ? typedef.type : call.type,
                  params,
                  Type: Syntax.IndirectFunctionCall,
                };
              },
          };
        },
      };
    }