balanceTypesInMathExpression = expression => {
  // find the heaviest type in the expression
  const type = expression.params.reduce((acc, { type: childType }) => {
    // The way we do that is by scanning the top-level nodes in our expression
    if (typeWeight(acc) < typeWeight(childType)) {
      return childType;
    }

    return acc;
  }, expression.type);

  // iterate again, this time, patching any lighter types
  const params = expression.params.map(paramNode => {
    if (paramNode.type != null && typeWeight(paramNode.type) !== typeWeight(type)) {
      // Convert constants to the desired type directly
      if (paramNode.Type === Syntax.Constant) {
        return extendNode({
          type
        }, paramNode);
      }

      return extendNode({
        type,
        value: paramNode.value,
        Type: Syntax.TypeCast,
        meta: {
          [TYPE_CAST]: { to: type, from: paramNode.type }
        },
        params: [paramNode]
      }, paramNode);
    }

    return paramNode;
  });

  return _extends({}, expression, {
    params,
    type
  });
}
Core language plugin

The parsers in here very closely mirror the underlying WebAssembly structure
and are used as the core language for every feature built on top.