2
0

amberc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. #!/bin/bash
  2. #
  3. # This is a "compiler" for Amber code. Run without arguments for help.
  4. # Get Amber root directory from the location of this script so that
  5. # we can find the st and js directories etc.
  6. # Earlier we used this but it does not work on Mac
  7. # Amber=$(readlink -f `dirname ${0}`/..)
  8. TARGET=`dirname ${0}`/..
  9. pushd . >/dev/null
  10. cd $TARGET
  11. AMBER="`\pwd -P`"
  12. popd >/dev/null
  13. function usage {
  14. cat <<ENDOFHELP
  15. Usage: $0 [-l lib1,lib2...] [-i file] [-m class] [-M file]
  16. [-o] [-O|-A] [-d] [-s suffix] [-S suffix] [file1 [file2 ...]] [Program]
  17. Will compile Amber files - either separately or into a runnable complete
  18. program. If no .st files are listed only a linking stage is performed.
  19. Files listed will be handled using these rules:
  20. *.js
  21. Files are linked (concatenated) in listed order.
  22. If not found we look in $AMBER/js
  23. *.st
  24. Files are compiled into .js files before concatenated.
  25. If not found we look in $AMBER/st.
  26. NOTE: Each file is currently considered to be a fileout of a single class
  27. category of the same name as the file!
  28. If no Program is specified each given .st file will be compiled into
  29. a .js file. Otherwise a <Program>.js file is linked together based on
  30. the options:
  31. -l library1,library2
  32. Additionally add listed libraries (no spaces or .js) in listed order.
  33. -i file
  34. Add library initializer <file> instead of default $AMBER/js/init.js
  35. -m class
  36. Add at end a call to #main in class <class>.
  37. -M file
  38. Add at end javascript file <file> acting as main.
  39. -o
  40. Optimize each js file using the Google closure compiler.
  41. Using Closure compiler found at ~/compiler.jar
  42. -O
  43. Optimize final <Program>.js using the Google closure compiler.
  44. Using Closure compiler found at ~/compiler.jar
  45. -A Same as -O but use --compilation_level ADVANCED_OPTIMIZATIONS
  46. -d
  47. Additionally export code for deploy - stripped from source etc.
  48. Uses suffix ".deploy.js" in addition to any explicit given suffic using -s.
  49. -s suffix
  50. Add <suffix> to compiled js files so that File.st is compiled into
  51. File.<suffix>.js.
  52. -S suffix
  53. Use <suffix> for all libraries accessed using -L or -l. This makes it possible
  54. to have multiple flavors of Amber and libraries in the same place.
  55. Example invocations:
  56. Just compile Kernel.st to Kernel.js:
  57. amberc Kernel.st
  58. Compile Hello.st to Hello.js and create complete program called
  59. Program.js and adding a call to class method #main in class Hello:
  60. amberc -m Hello Hello.st Program
  61. Compile two .st files into corresponding .js files,
  62. and link with specific myboot.js, myKernel.js, myinit.js
  63. and main.js and create complete program called Program.js:
  64. amberc -M main.js myinit.js myboot.js myKernel.js Cat1.st Cat2.st Program
  65. ENDOFHELP
  66. exit 1;
  67. }
  68. # Check we at least got one argument
  69. if [ -z $1 ] ; then
  70. usage
  71. fi
  72. # Define our predefined library combinations
  73. KERNEL="boot Kernel"
  74. COMPILER="$KERNEL parser Compiler"
  75. # Predefined initializer
  76. INITIALIZER="$AMBER/js/init.js"
  77. # Default values
  78. ENV=
  79. INIT=$INITIALIZER
  80. MAIN=
  81. MAINFILE=
  82. BASE=$KERNEL
  83. LOAD=
  84. CLOSUREOPTS=
  85. # Ok, bad coding practice but hey, who would use such a suffix?
  86. SUFFIX=no-silly-suffix
  87. SUFFIXUSED=
  88. DEPLOY=false
  89. NODECOMPILE=nodecompile
  90. # Read options and shift them away
  91. while getopts "l:i:m:M:oOAds:S:h?" o; do
  92. case "$o" in
  93. l) LOAD=$OPTARG;;
  94. i) INIT=$OPTARG;;
  95. m) MAIN=$OPTARG;;
  96. M) MAINFILE=$OPTARG;;
  97. o) CLOSURE=true
  98. CLOSUREPARTS=true;;
  99. O) CLOSURE=true
  100. CLOSUREFULL=true;;
  101. A) CLOSURE=true
  102. CLOSUREOPTS="$CLOSUREOPTS --compilation_level ADVANCED_OPTIMIZATIONS"
  103. CLOSUREFULL=true;;
  104. d) DEPLOY=true;;
  105. s) SUFFIX=$OPTARG
  106. SUFFIXUSED=$SUFFIX;;
  107. S) LOADSUFFIX=$OPTARG
  108. SUFFIXUSED=$SUFFIX;;
  109. h) usage;;
  110. [?]) usage;;
  111. esac
  112. done
  113. shift $(($OPTIND - 1))
  114. # Check for Closure compiler and Java
  115. if [ ! -z $CLOSURE ]; then
  116. java > /dev/null
  117. if [ $? -eq 0 ]; then
  118. if [ ! -f ~/compiler.jar ]; then
  119. echo "Can not find Closure compiler at ~/compiler.jar"
  120. exit 1
  121. fi
  122. else
  123. echo "java is not installed and is needed for -O, -A or -o (Closure compiler)."
  124. exit 1
  125. fi
  126. fi
  127. # Function for looking up listed js files
  128. function resolvejs {
  129. FNAME="$1$LOADSUFFIX.js"
  130. if [ -f $FNAME ]; then
  131. RESOLVED="$FNAME"
  132. else
  133. if [ -f $AMBER/js/$FNAME ]; then
  134. RESOLVED="$AMBER/js/$FNAME"
  135. else
  136. echo "Javascript file not found: $FNAME"
  137. exit 1
  138. fi
  139. fi
  140. }
  141. # Resolve listed libraries in $BASE deparated by spaces
  142. for FILE in $BASE
  143. do
  144. resolvejs $FILE
  145. TOBASE="$TOBASE $RESOLVED"
  146. done
  147. # Resolve listed libraries in $LOAD separated by ,
  148. LOAD=${LOAD//,/\ }
  149. for FILE in $LOAD
  150. do
  151. resolvejs $FILE
  152. TOLOAD="$TOLOAD $RESOLVED"
  153. done
  154. # Resolve COMPILER
  155. for FILE in $COMPILER
  156. do
  157. resolvejs $FILE
  158. TOCOMPILER="$TOCOMPILER $RESOLVED"
  159. done
  160. # Add supplied libraries we have not already loaded (they are already resolved)
  161. #for FILE in $EXTRA
  162. #do
  163. # resolvejs $FILE
  164. # TOEXTRA="$TOEXTRA $RESOLVED"
  165. #done
  166. TOCOMPILER="$TOCOMPILER$TOLOAD"
  167. # Resolve init and nodecompile
  168. THEREST="init $AMBER/bin/$NODECOMPILE"
  169. for FILE in $THEREST
  170. do
  171. resolvejs $FILE
  172. TOCOMPILER="$TOCOMPILER $RESOLVED"
  173. done
  174. # Add supplied libraries
  175. LIBS="$TOBASE $TOLOAD"
  176. # Get a unique tempdir and make it get auto removed on exit
  177. TMPDIR=`mktemp -d amberc.XXXXXX`
  178. trap "rm -rf $TMPDIR" EXIT
  179. # --------------------------------------------------
  180. # Collect libraries and Smalltalk files looking
  181. # both locally and in $AMBER/js and $AMBER/st
  182. # --------------------------------------------------
  183. PROGRAM=
  184. until [ "$*" = "" ]
  185. do
  186. case $1 in
  187. *.st)
  188. CATEGORY=`basename $1 .st`
  189. if [ -f "$1" ]; then
  190. COMPILE="$COMPILE $1 $CATEGORY"
  191. COMPILED="$COMPILED $CATEGORY$SUFFIXUSED.js"
  192. else
  193. if [ -f $AMBER/st/$1 ]; then
  194. COMPILE="$COMPILE $AMBER/st/$1 $CATEGORY"
  195. COMPILED="$COMPILED $CATEGORY$SUFFIXUSED.js"
  196. else
  197. echo "Amber file not found: $1"
  198. exit 1
  199. fi
  200. fi
  201. ;;
  202. *.js)
  203. resolvejs $1
  204. LIBS="$LIBS $RESOLVED"
  205. ;;
  206. *)
  207. # Will end up being the last non js/st argument
  208. PROGRAM=$1
  209. ;;
  210. esac
  211. shift
  212. done
  213. # --------------------------------------------------
  214. # Actual compilation phase of collected .st files
  215. # --------------------------------------------------
  216. # Create compiler dynamically
  217. cat $TOCOMPILER > $TMPDIR/compiler.js
  218. # Compile all collected .st files to .js
  219. echo "Loading libraries$TOCOMPILER and compiling ..."
  220. node $TMPDIR/compiler.js $DEPLOY $SUFFIX $COMPILE
  221. # Verify all .js files corresponding to .st files were created, otherwise exit
  222. IFS=" "
  223. for FILE in $COMPILED
  224. do
  225. if [ ! -f "$FILE" ]; then
  226. echo "Failed compilation of $FILE, exiting."
  227. exit 1
  228. fi
  229. done
  230. if [ ! -z $CLOSUREPARTS ]; then
  231. echo "Compiling all js files using Google closure compiler."
  232. ALLJSFILES="$COMPILED $LIBS"
  233. for FILE in $ALLJSFILES
  234. do
  235. mv $FILE $FILE.original
  236. java -jar ~/compiler.jar $CLOSUREOPTS --js $FILE.original --js_output_file $FILE
  237. rm $FILE.original
  238. done
  239. fi
  240. if [ -z $PROGRAM ]; then
  241. echo "Done."
  242. exit 0
  243. fi
  244. # --------------------------------------------------
  245. # Now we start composing resulting javascript file.
  246. # --------------------------------------------------
  247. # Add collected libraries to libs.js file.
  248. if [ ! -z "$LIBS" ]; then
  249. echo "Adding libraries $LIBS ..."
  250. cat $LIBS > $TMPDIR/libs.js
  251. LIBS=$TMPDIR/libs.js
  252. fi
  253. echo "Adding Amber code$COMPILED ..."
  254. # Check for init file
  255. if [ ! -z "$INIT" ]; then
  256. if [ -f "$INIT" ]; then
  257. echo "Adding initializer $INIT ..."
  258. else
  259. echo "Can not find init file $INIT, exiting."
  260. exit 1
  261. fi
  262. fi
  263. # Check for adding main
  264. if [ ! -z "$MAIN" ]; then
  265. echo "Adding call to $MAIN class >> main ..."
  266. echo "smalltalk.$MAIN._main()" > $TMPDIR/main.js
  267. MAIN=$TMPDIR/main.js
  268. fi
  269. # Check for adding main file
  270. if [ ! -z "$MAINFILE" ]; then
  271. if [ -f "$MAINFILE" ]; then
  272. echo "Adding main as $MAINFILE ..."
  273. else
  274. echo "Can not find main file $MAINFILE, exiting."
  275. exit 1
  276. fi
  277. MAIN=$MAINFILE
  278. fi
  279. # And finally concatenate Program.js
  280. echo "Writing $PROGRAM.js ..."
  281. cat $LIBS $COMPILED $INIT $MAIN > $PROGRAM.js
  282. echo "Done."
  283. if [ ! -z $CLOSUREFULL ]; then
  284. echo "Compiling $PROGRAM.js file using Google closure compiler."
  285. mv $PROGRAM.js $PROGRAM.js.original
  286. java -jar ~/compiler.jar $CLOSUREOPTS --js $PROGRAM.js.original --js_output_file $PROGRAM.js
  287. rm $PROGRAM.js.original
  288. echo "Done."
  289. fi