# All files / src/semantics index.js

100% Statements 27/27
100% Branches 2/2
100% Functions 2/2
100% Lines 27/27

    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

    23x
    23x
    23x
    23x
    23x
    23x
    23x
    23x
    23x
    23x
    23x

    77x
    77x
    77x
    77x
    77x
    77x
    77x
    77x

    77x
    1x

    77x

    26x
    26x

    77x
    30x

    77x

     /**
     * Semantic Analysis
     *
     * The semantic analyzer below accepts a Walt AST and maps it, returning a new
     * transformed AST which contains all necessary data to generate the final
     * WebAssembly binary.
     *
     * The transformations may or may not create new nodes or attach metadata to
     * existing nodes.
     *
     * Metadata is information necessary to generate a valid binary, like type info.
     */

    // @flow
    import Syntax from "../Syntax";
    import mapNode from "../utils/map-node";
    import { mapImport } from "./map-import";
    import mapFunctionNode from "./map-function";
    import closureImports from "../closure-plugin/imports";
    import { parseGlobalDeclaration } from "./map-function/declaration";
    import mapStructNode from "./map-struct";
    import mapCharacterLiteral from "./map-char";
    import { mapGeneric } from "./map-generic";
    import hasNode from "../utils/has-node";
    import { AST_METADATA } from "./metadata";
    import type { NodeType } from "../flow/types";

    export default function semantics(ast: NodeType): NodeType {
      const functions: { [string]: NodeType } = {};
      const globals: { [string]: NodeType } = {};
      const types: { [string]: NodeType } = {};
      const userTypes: { [string]: NodeType } = {};
      const table: { [string]: NodeType } = {};
      const hoist: NodeType[] = [];
      const hoistImports: NodeType[] = [];
      const statics: { [string]: NodeType } = {};

      if (hasNode(Syntax.Closure, ast)) {
        ast = { ...ast, params: [...closureImports(), ...ast.params] };
      }
      // Types have to be pre-parsed before the rest of the program
      const astWithTypes = mapNode({
        [Syntax.Typedef]: (node, _) => {
          types[node.value] = node;
          return node;
        },
        [Syntax.GenericType]: mapGeneric({ types }),
      })(ast);

      const patched = mapNode({
        [Syntax.Typedef]: (_, __) => _,
        // Read Import node, attach indexes if non-scalar
        [Syntax.Import]: mapImport({ functions, types, globals }),
        [Syntax.Declaration]: parseGlobalDeclaration(false, { globals, types }),
        [Syntax.ImmutableDeclaration]: parseGlobalDeclaration(true, {
          globals,
          types,
        }),
        [Syntax.CharacterLiteral]: mapCharacterLiteral,
        [Syntax.Struct]: mapStructNode({ userTypes }),
        [Syntax.FunctionDeclaration]: mapFunctionNode({
          hoist,
          hoistImports,
          types,
          globals,
          functions,
          userTypes,
          table,
          statics,
        }),
      })(astWithTypes);

      return {
        ...patched,
        meta: {
          ...patched.meta,
          // Attach information collected to the AST
          [AST_METADATA]: { functions, globals, types, userTypes, statics },
        },
        params: [...hoistImports, ...patched.params, ...hoist],
      };
    }