#! /usr/bin/env bash
#
# Copy tree-sitter grammars from the semgrep-grammars repo into the current
# language directory.
#
set -eu

name=$(basename "$(pwd)")

# Location of pre-generated grammar.json. This is required
# if we're using a tree-sitter grammar.
#
# It is ignored if 'grammar.js' exists locally.
#
import_from=../semgrep-grammars/lang/"$name"

error() {
  cat >&2 <<EOF
Error: $*
EOF
  exit 1
}

# Generate C source code for the grammar, in two passes:
#
# 1. Import files from semgrep-grammars
# 2. Simplify grammar.json so it's compatible with ocaml-tree-sitter.
# 3. Generate 'parser.c' from the simplified 'grammar.json'.
#

if [[ -e grammar.js ]]; then
  # This mechanism is used for ocaml-tree-sitter test grammars, which just
  # consist of a local 'grammar.json' file.

  echo "$name: Generating initial 'grammar.json' from 'grammar.js'."
  tree-sitter generate --no-bindings
  mkdir -p src
  if [[ -e orig/LICENSE ]]; then cp -L orig/LICENSE src; fi
  if [[ -e orig/scanner.c ]]; then cp -L orig/scanner.c src; fi
  if [[ -e orig/scanner.cc ]]; then cp -L orig/scanner.cc src; fi
else
  # This mechanism is used with languages whose base grammar is defined
  # in a tree-sitter-* submodule.

  # tree-sitter 0.22.6 creates a dummy 'grammar.js' file if
  # there isn't one already. This creates confusing situations
  # because our input grammar as created by ocaml-tree-sitter is
  # 'src/grammar.json', not the usual 'grammar.js'. Creating our
  # own unparseable 'grammar.js' is a protection against using
  # the wrong grammar.
  # Tracked at https://github.com/tree-sitter/tree-sitter/issues/3415
  echo "..... not the input grammar! Use 'tree-sitter generate src/grammar.json'" \
    > grammar.js

  orig_grammar_json="$import_from"/src/grammar.json
  if [[ ! -e "$orig_grammar_json" ]]; then
    cat >&2 <<EOF
Missing local 'grammar.js' and missing '$orig_grammar_json'.
One of these files must exist.
EOF
    exit 1
  else
    echo "$name: Importing initial 'grammar.json'."
    mkdir -p src
    cp -RL "$import_from"/src/* src/
    rm -f src/parser.c
  fi
fi

echo "$name: Simplifying 'grammar.json' for ocaml-tree-sitter."
mv src/grammar.json src/grammar.json.orig
ocaml-tree-sitter simplify src/grammar.json.orig src/grammar.json

echo "$name: Recovering informational JS grammars from JSON."
ocaml-tree-sitter to-js src/grammar.json.orig grammar-rev.js.orig
ocaml-tree-sitter to-js src/grammar.json grammar-rev.js

echo "$name: Generating definitive 'parser.c'."
tree-sitter generate src/grammar.json --no-bindings

# Make sure we get an error in case of OOM leading to no src/parser.c
test -f src/parser.c || error \
  "tree-sitter didn't generate src/parser.c." \
  "This may happen when not enough memory is available."
