| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 | #!/bin/bash## This is a "compiler" for Amber code. Run without arguments for help.# Get Amber root directory from the location of this script so that# we can find the st and js directories etc.# Earlier we used this but it does not work on Mac# Amber=$(readlink -f `dirname ${0}`/..)TARGET=`dirname ${0}`/..pushd . >/dev/nullcd $TARGETAMBER="`\pwd -P`"popd >/dev/nullfunction usage {	cat <<ENDOFHELPUsage: $0 [-l lib1,lib2...] [-i file] [-m class] [-M file]          [-o] [-O|-A] [-d] [-s suffix] [-S suffix] [file1 [file2 ...]] [Program]   Will compile Amber files - either separately or into a runnable complete   program. If no .st files are listed only a linking stage is performed.   Files listed will be handled using these rules:   *.js     Files are linked (concatenated) in listed order.     If not found we look in $AMBER/js   *.st     Files are compiled into .js files before concatenated.     If not found we look in $AMBER/st.     NOTE: Each file is currently considered to be a fileout of a single class     category of the same name as the file!   If no Program is specified each given .st file will be compiled into   a .js file. Otherwise a <Program>.js file is linked together based on   the options:  -l library1,library2     Additionally add listed libraries (no spaces or .js) in listed order.  -i file     Add library initializer <file> instead of default $AMBER/js/init.js   -m class     Add at end a call to #main in class <class>.   -M file     Add at end javascript file <file> acting as main.          -o     Optimize each js file using the Google closure compiler.     Using Closure compiler found at ~/compiler.jar      -O     Optimize final <Program>.js using the Google closure compiler.     Using Closure compiler found at ~/compiler.jar  -A Same as -O but use --compilation_level ADVANCED_OPTIMIZATIONS  -d     Additionally export code for deploy - stripped from source etc.     Uses suffix ".deploy.js" in addition to any explicit given suffic using -s.  -s suffix     Add <suffix> to compiled js files so that File.st is compiled into     File.<suffix>.js.  -S suffix     Use <suffix> for all libraries accessed using -L or -l. This makes it possible     to have multiple flavors of Amber and libraries in the same place.     Example invocations:     Just compile Kernel-Objects.st to Kernel-Objects.js:        amberc Kernel-Objects.st     Compile Hello.st to Hello.js and create complete program called     Program.js and adding a call to class method #main in class Hello:        amberc -m Hello Hello.st Program     Compile two .st files into corresponding .js files,     and link with specific myboot.js, myKernel.js, myinit.js     and main.js and create complete program called Program.js:        amberc -M main.js myinit.js myboot.js myKernel.js Cat1.st Cat2.st ProgramENDOFHELP	exit 1;}# Check we at least got one argumentif [ -z $1 ] ; then   usagefi# Define our predefined library combinationsKERNEL="boot Kernel-Objects Kernel-Classes Kernel-Methods Kernel-Collections Kernel-Exceptions Kernel-Transcript"COMPILER="$KERNEL parser Compiler"# Predefined initializerINITIALIZER="$AMBER/js/init.js"# Default valuesENV=INIT=$INITIALIZERMAIN=MAINFILE=BASE=$KERNELLOAD=CLOSUREOPTS=# Ok, bad coding practice but hey, who would use such a suffix?SUFFIX=no-silly-suffixSUFFIXUSED=DEPLOY=falseNODECOMPILE=nodecompile# Read options and shift them awaywhile getopts "l:i:m:M:oOAds:S:h?" o; docase "$o" in   l) LOAD=$OPTARG;;   i) INIT=$OPTARG;;   m) MAIN=$OPTARG;;   M) MAINFILE=$OPTARG;;   o) CLOSURE=true      CLOSUREPARTS=true;;   O) CLOSURE=true      CLOSUREFULL=true;;   A) CLOSURE=true      CLOSUREOPTS="$CLOSUREOPTS --compilation_level ADVANCED_OPTIMIZATIONS"      CLOSUREFULL=true;;   d) DEPLOY=true;;   s) SUFFIX=$OPTARG      SUFFIXUSED=$SUFFIX;;   S) LOADSUFFIX=$OPTARG      SUFFIXUSED=$SUFFIX;;   h) usage;;   [?])  usage;;   esacdoneshift $(($OPTIND - 1))# Check for Closure compiler and Javaif [ ! -z $CLOSURE ]; then  java > /dev/null  if [ $? -eq 0 ]; then     if [ ! -f ~/compiler.jar ]; then      echo "Can not find Closure compiler at ~/compiler.jar"      exit 1    fi  else   echo "java is not installed and is needed for -O, -A or -o (Closure compiler)."   exit 1  fifi# Function for looking up listed js filesfunction resolvejs {  FNAME="$1$LOADSUFFIX.js"  if [ -f $FNAME ]; then    RESOLVED="$FNAME"   else    if [ -f $AMBER/js/$FNAME ]; then      RESOLVED="$AMBER/js/$FNAME"    else      echo "Javascript file not found: $FNAME"      exit 1    fi  fi}# Resolve listed libraries in $BASE deparated by spacesfor FILE in $BASEdo   resolvejs $FILE   TOBASE="$TOBASE $RESOLVED"done# Resolve listed libraries in $LOAD separated by ,LOAD=${LOAD//,/\ }for FILE in $LOADdo   resolvejs $FILE   TOLOAD="$TOLOAD $RESOLVED"done# Resolve COMPILERfor FILE in $COMPILERdo   resolvejs $FILE   TOCOMPILER="$TOCOMPILER $RESOLVED"done# Add supplied libraries we have not already loaded (they are already resolved)#for FILE in $EXTRA#do#   resolvejs $FILE#   TOEXTRA="$TOEXTRA $RESOLVED"#doneTOCOMPILER="$TOCOMPILER$TOLOAD"# Resolve init and nodecompileTHEREST="init $AMBER/bin/$NODECOMPILE"for FILE in $THERESTdo   resolvejs $FILE   TOCOMPILER="$TOCOMPILER $RESOLVED"done# Add supplied librariesLIBS="$TOBASE $TOLOAD"# Get a unique tempdir and make it get auto removed on exitTMPDIR=`mktemp -d amberc.XXXXXX`trap "rm -rf $TMPDIR" EXIT# --------------------------------------------------# Collect libraries and Smalltalk files looking# both locally and in $AMBER/js and $AMBER/st # --------------------------------------------------PROGRAM=until [ "$*" = "" ]do  case $1 in     *.st)        CATEGORY=`basename $1 .st`        if [ -f "$1" ]; then           COMPILE="$COMPILE $1 $CATEGORY"           COMPILED="$COMPILED $CATEGORY$SUFFIXUSED.js"        else           if [ -f $AMBER/st/$1 ]; then             COMPILE="$COMPILE $AMBER/st/$1 $CATEGORY"             COMPILED="$COMPILED $CATEGORY$SUFFIXUSED.js"           else             echo "Amber file not found: $1"             exit 1           fi        fi        ;;     *.js)        resolvejs $1	LIBS="$LIBS $RESOLVED"         ;;      *)        # Will end up being the last non js/st argument        PROGRAM=$1        ;;  esac  shiftdone# --------------------------------------------------# Actual compilation phase of collected .st files# --------------------------------------------------# Create compiler dynamicallycat $TOCOMPILER > $TMPDIR/compiler.js # Compile all collected .st files to .jsecho "Loading libraries$TOCOMPILER and compiling ..."node $TMPDIR/compiler.js $DEPLOY $SUFFIX $COMPILE# Verify all .js files corresponding to .st files were created, otherwise exitIFS=" "for FILE in $COMPILEDdo  if [ ! -f "$FILE" ]; then    echo "Failed compilation of $FILE, exiting."    exit 1  fi doneif [ ! -z $CLOSUREPARTS ]; then  echo "Compiling all js files using Google closure compiler."  ALLJSFILES="$COMPILED $LIBS"  for FILE in $ALLJSFILES  do    mv $FILE $FILE.original    java -jar ~/compiler.jar $CLOSUREOPTS --js $FILE.original --js_output_file $FILE    rm $FILE.original  donefiif [ -z $PROGRAM ]; then  echo "Done."  exit 0fi# --------------------------------------------------# Now we start composing resulting javascript file.# --------------------------------------------------# Add collected libraries to libs.js file.if [ ! -z "$LIBS" ]; then  echo "Adding libraries $LIBS ..."  cat $LIBS > $TMPDIR/libs.js  LIBS=$TMPDIR/libs.jsfiecho "Adding Amber code$COMPILED ..."# Check for init fileif [ ! -z "$INIT" ]; then   if [ -f "$INIT" ]; then      echo "Adding initializer $INIT ..."   else      echo "Can not find init file $INIT, exiting."      exit 1   fi fi# Check for adding mainif [ ! -z "$MAIN" ]; then  echo "Adding call to $MAIN class >> main ..."  echo "smalltalk.$MAIN._main()" > $TMPDIR/main.js  MAIN=$TMPDIR/main.jsfi# Check for adding main fileif [ ! -z "$MAINFILE" ]; then   if [ -f "$MAINFILE" ]; then      echo "Adding main as $MAINFILE ..."   else      echo "Can not find main file $MAINFILE, exiting."      exit 1   fi    MAIN=$MAINFILEfi# And finally concatenate Program.jsecho "Writing $PROGRAM.js ..."cat $LIBS $COMPILED $INIT $MAIN > $PROGRAM.jsecho "Done."if [ ! -z $CLOSUREFULL ]; then  echo "Compiling $PROGRAM.js file using Google closure compiler."  mv $PROGRAM.js $PROGRAM.js.original  java -jar ~/compiler.jar $CLOSUREOPTS --js $PROGRAM.js.original --js_output_file $PROGRAM.js  rm $PROGRAM.js.original  echo "Done."fi
 |