#!/usr/bin/env bash

usage() {
  cat <<EOF
USAGE

  $0 [--help] [--debug] [--docker]

SUMMARY

  Compile the Tree-sitter WASM library. This will create two files in the
  \`lib/binding_web\` directory: \`tree-sitter.js\` and \`tree-sitter.wasm\`.

REQUIREMENTS

  You must have either the \`emcc\` command or the \`docker\` command
  on your PATH for this to work.

OPTIONS

  --help:   Display this message.
  --debug:  Compile the library more quickly, with fewer optimizations
            and more runtime assertions.
  --docker: Run emscripten using docker, even if \`emcc\` is installed.
            By default, \`emcc\` will be run directly when available.

EOF
}

set -e

web_dir=lib/binding_web
src_dir=lib/src
emscripten_flags="-O3"
minify_js=1
force_docker=0
emscripen_version=$(cat "$(dirname "$0")"/../cli/loader/emscripten-version)

while [[ $# > 0 ]]; do
  case "$1" in
    --debug)
      minify_js=0
      emscripten_flags="-s ASSERTIONS=1 -s SAFE_HEAP=1 -O0"
      ;;

    --help)
      usage
      exit 0
      ;;

    --docker)
      force_docker=1
      ;;

    -v|--verbose)
      emscripten_flags="-s VERBOSE=1 -v $emscripten_flags"
      ;;

    *)
      usage
      echo "Unrecognized argument '$1'"
      exit 1
      ;;
  esac
  shift
done

emcc=""
docker=""
if which emcc > /dev/null && [[ "$force_docker" == "0" ]]; then
  emcc=emcc
elif which docker > /dev/null; then
  # detect which one to use
  docker=docker
elif which podman > /dev/null; then
  docker=podman
fi

if [ -z "$emcc" ] && [ -n "$docker" ]; then
  export PODMAN_USERNS=keep-id
  emcc="$docker run                      \
    --rm                                 \
    -v $(pwd):/src:Z                     \
    -u $(id -u)                          \
    emscripten/emsdk:$emscripen_version  \
    emcc"
fi

if [ -z "$emcc" ]; then
  if [[ "$force_docker" == "1" ]]; then
    echo 'You must have `docker` or `podman` on your PATH to run this script with --docker'
  else
    echo 'You must have either `docker`, `podman`, or `emcc` on your PATH to run this script'
  fi
  exit 1
fi

mkdir -p target/scratch

runtime_methods='stringToUTF16','AsciiToString'

# Remove quotes, add leading underscores, remove newlines, remove trailing comma.
EXPORTED_FUNCTIONS=$(                                                \
    cat ${src_dir}/wasm/stdlib-symbols.txt ${web_dir}/exports.txt  | \
    sed -e 's/"//g'                                                | \
    sed -e 's/^/_/g'                                               | \
    tr -d '\n"'                                                    | \
    sed -e 's/,$//'                                                  \
)

# Use emscripten to generate `tree-sitter.js` and `tree-sitter.wasm`
# in the `target/scratch` directory
$emcc                                            \
  -s WASM=1                                      \
  -s INITIAL_MEMORY=33554432                     \
  -s ALLOW_MEMORY_GROWTH=1                       \
  -s MAIN_MODULE=2                               \
  -s FILESYSTEM=0                                \
  -s NODEJS_CATCH_EXIT=0                         \
  -s NODEJS_CATCH_REJECTION=0                    \
  -s EXPORTED_FUNCTIONS=${EXPORTED_FUNCTIONS} \
  -s EXPORTED_RUNTIME_METHODS=$runtime_methods   \
  $emscripten_flags                              \
  -fno-exceptions                                \
  -std=c11                                       \
  -D 'fprintf(...)='                             \
  -D NDEBUG=                                     \
  -I ${src_dir}                                  \
  -I lib/include                                 \
  --js-library ${web_dir}/imports.js             \
  --pre-js ${web_dir}/prefix.js                  \
  --post-js ${web_dir}/binding.js                \
  --post-js ${web_dir}/suffix.js                 \
  lib/src/lib.c                                  \
  ${web_dir}/binding.c                           \
  -o target/scratch/tree-sitter.js

# Use terser to write a minified version of `tree-sitter.js` into
# the `lib/binding_web` directory.
if [[ "$minify_js" == "1" ]]; then
  if [ ! -d ${web_dir}/node_modules/terser ]; then
    (
      cd ${web_dir}
      npm install
    )
  fi
  ${web_dir}/node_modules/.bin/terser   \
    --compress                       \
    --mangle                         \
    --keep-classnames                \
    -- target/scratch/tree-sitter.js \
    > ${web_dir}/tree-sitter.js
else
  cp target/scratch/tree-sitter.js ${web_dir}/tree-sitter.js
fi

mv target/scratch/tree-sitter.wasm ${web_dir}/tree-sitter.wasm
