#!/bin/bash

#  +====================+
#  SCript-Executor Script
#  Version 0.4
#  https://mauro.foti.eu/projects/sces.html
#  +====================+

# === REQUIREMENTS ===
#
#  C/C++   =>  apt install build-essential
#                (systemc) apt install libsystemc libsystemc-dev
#  C#      =>  apt install mono-mcs libmono-system-windows-forms4.0-cil binfmt-support
#                echo ":CLR:M::MZ::/usr/bin/mono:" | tee /etc/binfmt.d/mono.conf
#  Matlab  =>  matlab
#  ECL     =>  see guide on ECL
#
# === END ===

# ID randomly generated for every execution
ID=$(printf "%X" $RANDOM)

# input file path, extension and parent directory
FILE_PATH=$( if [[ "$1" =~ !.* ]]; then echo "$2"; else echo "$1"; fi )
FILE_EXT=${FILE_PATH##*.}
FILE_DIR=$(dirname $FILE_PATH)

# temporary file (executable) location
TEMP_DIR="/tmp"
TEMP_PATH="$TEMP_DIR/xscript.$ID.exe"

# execution variables
n=$( if [[ "$1" =~ !.* ]]; then echo 3; else echo 2; fi )
SCRIPT_ARGS=${@:n:$#}
COMPILER_ARGS=$( if [[ "$1" =~ !.* ]]; then echo "${1/\!}"; else echo ""; fi ) # remove ! from first line

function get-code
{
    # append an empty line where shabang once was to preserve line numbers
    # in some languages the shaband would be a syntax error (C/C++/C#)
    echo ""
    tail -n +2 "$FILE_PATH"
}

function clean
{
    rm "$TEMP_DIR/xscript.$ID"* 2>/dev/null
}

# clean if receives ctrl+c
trap "clean" SIGINT

case $FILE_EXT in
 "c") # c
    get-code | gcc -Wall -I "$FILE_DIR" -g -x c -o $TEMP_PATH - $COMPILER_ARGS
    cret=$?
    ;;
 "cpp") # c++
    get-code | g++ -Wall -I "$FILE_DIR" -g -x c++ -o $TEMP_PATH - $COMPILER_ARGS
    cret=$?
    ;;
 "cs") # c#
    get-code >> "$TEMP_DIR/xscript.$ID.cs" # apparently mcs does not accept source code from stdin, must copy .cs file
    mcs -out:$TEMP_PATH $COMPILER_ARGS "$TEMP_DIR/xscript.$ID.cs"
    cret=$?
    ;;
 #"m") # matlab
 #   get-code >> "$TEMP_DIR/xscript.$ID.m"
 #   echo -e "#!/bin/bash\ncd \"$FILE_DIR\" && matlab -nodesktop -nosplash < \"$TEMP_DIR/xscript.$ID.m\"" > $TEMP_PATH
 #   cret=$?
 #   ;;
 "ecl") # esterel C language
    get-code >> "$TEMP_DIR/xscript.$ID.ecl"
    cd "$TEMP_DIR" && ecl -ESTEREL "$TEMP_DIR/xscript.$ID.ecl" 1>/dev/null
    cret=$?
    mv "$TEMP_DIR/xscript.exe" "$TEMP_PATH" 2>/dev/null
    ;;
esac

# exit if compiler fails
# return code saved in $cret and check moved before because some tasks may be done after compilation (cleanup)
if [[ $cret -ne 0 ]]; then
    clean
    exit $cret
fi

# run executable and pass all necessary informations:
#  - command line arguments (argv)
#  - working directory of script (pwd)
#  - script call name (argv[0]) (currently not working in c# scripts)
#  - it will relay return code
#  - preserve line number
chmod +x "$TEMP_PATH"
(exec -a "$FILE_PATH" "$TEMP_PATH" "${@:n:$#}"); ret=$?

# delete executable (and any other associated file) and exit
clean
exit $ret
