# All files / src/emitter/section code.js

100% Statements 51/51
93.33% Branches 14/15
100% Functions 7/7
100% Lines 49/49

    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
    22x
    22x
    22x
    22x
    22x

    22x
    123x
    123x
    123x

    22x

    164x

    164x

    2623x

    2623x
    1x
    1x

    2623x
    1904x
    1904x

    1904x
    244x
    244x

    1660x

    4x
    4x
    4x

    24x
    24x
    24x

    718x
    718x
    718x

    6x
    6x
    6x

    908x

    1904x

    164x
    164x

    164x
    164x

    164x
    164x
    164x

    22x

    64x
    64x
    164x

    64x

     // @flow
    import { u8, i32, f32, f64, i64 } from 'wasm-types';
    import { varint32, varuint32, varint7, varint64 } from '../numbers';
    import { getTypeString } from '../value_type';
    import OutputStream from '../../utils/output-stream';
    import opcode from '../opcode';

    const emitLocal = (stream, local) => {
      Eif (local.isParam == null) {
        stream.push(varuint32, 1, 'number of locals of following type');
        stream.push(varint7, local.type, `${getTypeString(local.type)}`);
      }
    };

    const emitFunctionBody = (stream, { locals, code, debug: functionName }) => {
      // write bytecode into a clean buffer
      const body = new OutputStream();

      code.forEach(({ kind, params, valueType, debug }) => {
        // There is a much nicer way of doing this
        body.push(u8, kind.code, `${kind.text}  ${debug ? debug : ''}`);

        if (valueType) {
          body.push(u8, valueType.type, 'result type');
          body.push(u8, valueType.mutable, 'mutable');
        }

        // map over all params, if any and encode each on
        params.forEach(p => {
          let type = varuint32;
          let stringType = 'i32.literal';

          // Memory opcode?
          if (kind.code >= 0x28 && kind.code <= 0x3e) {
            type = varuint32;
            stringType = 'memory_immediate';
          } else {
            // either encode unsigned 32 bit values or floats
            switch (kind.result) {
              case f64:
                type = f64;
                stringType = 'f64.literal';
                break;
              case f32:
                type = f32;
                stringType = 'f32.literal';
                break;
              case i32:
                type = varint32;
                stringType = 'i32.literal';
                break;
              case i64:
                type = varint64;
                stringType = 'i64.literal';
                break;
              default:
                type = varuint32;
            }
          }
          body.push(type, p, `${stringType}`);
        });
      });

      // output locals to the stream
      const localsStream = new OutputStream();
      locals.forEach(local => emitLocal(localsStream, local));

      // body size is
      stream.push(varuint32, body.size + localsStream.size + 2, functionName);
      stream.push(varuint32, locals.length, 'locals count');

      stream.write(localsStream);
      stream.write(body);
      stream.push(u8, opcode.End.code, 'end');
    };

    const emit = (functions: any[]) => {
      // do stuff with ast
      const stream = new OutputStream();
      stream.push(varuint32, functions.length, 'function count');
      functions.forEach(func => emitFunctionBody(stream, func));

      return stream;
    };

    export default emit;