#!/bin/bash # # This is a "compiler" for JTalk code. Run without arguments for help. # Get JTalk 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 # JTALK=$(readlink -f `dirname ${0}`/..) TARGET=`dirname ${0}`/.. pushd . >/dev/null cd $TARGET JTALK="`\pwd -P`" popd >/dev/null function usage { cat <.js file is linked together based on the options: -N or -D or -E Compilation target. Currently Node.js, D8 (V8 shell) or Enyo (webOS 3.0). All currentl imply "-K -I" so boot.js and Kernel.js are added first and init.js is added last. -K Add libraries to get minimal Jtalk Kernel running. -C Add libraries to get minimal Jtalk Compiler running. -J Add libraries to get minimal Jtalk IDE running. -o Optimize each js file using the Google closure compiler. Using Closure at ~/compiler.jar -O Optimize final .js using the Google closure compiler. Using Closure at ~/compiler.jar -A Same as -O but use --compilation_level ADVANCED_OPTIMIZATIONS -g Compile Jtalk code in debug mode - include source and references etc. -p prefix Add to compiled js files so that File.st is compiled into File.st. -l library1,library2 Load listed libraries (no spaces) into Compiler before compiling. -L library1,library2 Load listed libraries (no spaces) into Compiler before compiling and also into Program.js in listed order. -i file Add library initializer . -I Add library standard initializer $JTALK/js/init.js -m class Add call to #main in class . -M file Add javascript file at the end acting as main. Example invocations: Just compile Kernel.st to Kernel.js: jtalkc Kernel.st Compile Hello.st to Hello.js and create complete program called Program.js for Node.js and adding a call to class method #main in class Hello: jtalkc -N -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: jtalkc -M main.js -I myinit.js myboot.js myKernel.js Cat1.st Cat2.st Program ENDOFHELP exit 1; } # Check we at least got one argument if [ -z $1 ] ; then usage fi # Define our predefined library combinations BOOT="boot.js" KERNEL="$BOOT Kernel.js" COMPILER="$KERNEL Parser.js Compiler.js" CANVAS="$COMPILER Canvas.js" IDE="$CANVAS JQuery.js IDE.js SUnit.js Examples.js" # Predefined initializer INITIALIZER="$JTALK/js/init.js" # Default values ENV= INIT= MAIN= MAINFILE= BASE= LOAD= LOADANDADD= CLOSUREOPTS= # Ok, bad coding practice but hey, who would use such a prefix? PREFIX=no-silly-prefix PREFIXUSED= DEBUG=false NODECOMPILE=nodecompile.js # Read options and shift them away while getopts "NDEKCJoOAgp:l:L:i:IM:m:h?" o; do case "$o" in N) ENV=NODE BASE=$KERNEL INIT=$INITIALIZER;; D) ENV=D8 BASE=$KERNEL INIT=$INITIALIZER;; E) ENV=ENYO BASE=$KERNEL INIT=$INITIALIZER;; K) BASE=$KERNEL;; C) BASE=$COMPILER;; J) BASE=$IDE;; o) CLOSURE=true CLOSUREPARTS=true;; O) CLOSURE=true CLOSUREFULL=true;; A) CLOSURE=true CLOSUREOPTS="$CLOSUREOPTS --compilation_level ADVANCED_OPTIMIZATIONS" CLOSUREFULL=true;; g) DEBUG=true;; p) PREFIX=$OPTARG PREFIXUSED=$PREFIX;; l) LOAD=$OPTARG;; L) LOADANDADD=$OPTARG;; I) INIT=$INITIALIZER;; i) INIT=$OPTARG;; M) MAINFILE=$OPTARG;; m) MAIN=$OPTARG;; h) usage;; [?]) usage;; esac done shift $(($OPTIND - 1)) # Check for Closure compiler and Java if [ ! -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 fi fi # Function for looking up listed js files function resolvejs { if [ -f "$1" ]; then RESOLVED="$1" else if [ -f $JTALK/js/$1 ]; then RESOLVED="$JTALK/js/$1" else echo "Javascript file not found: $1" exit 1 fi fi } # Resolve listed libraries in $BASE separated by spaces for FILE in $BASE do resolvejs $FILE TOBASE="$TOBASE $RESOLVED" done # Resolve listed libraries in $LOAD separated by spaces LOAD=${LOAD//,/\ } for FILE in $LOAD do resolvejs $FILE TOLOAD="$TOLOAD $RESOLVED" done # Resolve listed libraries in $LOADANDADD separated by spaces LOADANDADD=${LOADANDADD//,/\ } for FILE in $LOADANDADD do resolvejs $FILE TOLOAD="$TOLOAD $RESOLVED" TOADD="$TOADD $RESOLVED" done # Define our Compiler loading supplied libraries OURCOMPILER="$COMPILER $TOLOAD init.js $JTALK/nodejs/$NODECOMPILE" # Resolve OURCOMPILER for FILE in $OURCOMPILER do resolvejs $FILE TOOURCOMPILER="$TOOURCOMPILER $RESOLVED" done # Add supplied libraries LIBS="$TOBASE $TOADD" # Get a unique tempdir and make it get auto removed on exit TMPDIR=`mktemp -d` trap "rm -rf $TMPDIR" EXIT # -------------------------------------------------- # Collect libraries and Smalltalk files looking # both locally and in $JTALK/js and $JTALK/st # -------------------------------------------------- PROGRAM= until [ "$*" = "" ] do case $1 in *.st) CATEGORY=`basename $1 .st` if [ -f "$1" ]; then COMPILE="$COMPILE $1 $CATEGORY" COMPILED="$COMPILED $PREFIXUSED$CATEGORY.js" else if [ -f $JTALK/st/$1 ]; then COMPILE="$COMPILE $JTALK/st/$1 $CATEGORY" COMPILED="$COMPILED $PREFIXUSED$CATEGORY.js" else echo "JTalk 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 shift done # -------------------------------------------------- # Actual compilation phase of collected .st files # -------------------------------------------------- # Create compiler dynamically cat $TOOURCOMPILER > $TMPDIR/compiler.js # Compile all collected .st files to .js echo "Loading libraries $TOOURCOMPILER and compiling ..." node $TMPDIR/compiler.js $DEBUG $PREFIX $COMPILE # Verify all .js files corresponding to .st files were created, otherwise exit IFS=" " for FILE in $COMPILED do if [ ! -f "$FILE" ]; then echo "Failed compilation of $FILE, exiting." exit 1 fi done if [ ! -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 done fi if [ -z $PROGRAM ]; then echo "Done." exit 0 fi # -------------------------------------------------- # 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.js fi echo "Adding Jtalk code$COMPILED ..." # Check for init file if [ ! -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 main if [ ! -z "$MAIN" ]; then echo "Adding call to $MAIN class >> main ..." echo "smalltalk.$MAIN._main()" > $TMPDIR/main.js MAIN=$TMPDIR/main.js fi # Check for adding main file if [ ! -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=$MAINFILE fi # And finally concatenate Program.js echo "Writing $PROGRAM.js ..." cat $LIBS $COMPILED $INIT $MAIN > $PROGRAM.js echo "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