Chapter 10. Through ATS to Javascript

Javascript (JS) is arguably the most popular programming language on the plant Earth. In this chapter, I plan to demonstrate a style of co-programming with ATS and JS. In practice (of this style of co-programming), ATS is mainly intended for high-level programming (that, for instance, makes extensive use of combinators) and JS for relatively low-level programming (that, for instance, handles direct interactions with the browser running JS code).

Let us take a look at a simple webpage for computing factorials on-line. After inputing a natural number, one can click the Evaluate button to see some output mentioning the factorial of the number. Please find the HTML source for the webpage here. Note that the following JS scripts are needed for evaluating JS code generated from ATS source:


<script type="text/javascript"
 src="https://ats-lang.github.io/LIBRARY/libatscc2js/ATS2-0.3.2/libatscc2js_all.js">
</script>
<script type="text/javascript"
  src="https://ats-lang.github.io/LIBRARY/libatscc2js/ATS2-0.3.2/libatscc2js_print_store_cats.js">
</script>

The JS code in the file Factorial_dats.js is generated from compiling the ATS source stored in Factorial.dats. The command patsopt is called on the ATS source to compile it onto C code, and the command atscc2js is subsequently called on the generated C code to transpile it into JS code:


patsopt -o Factorial_dats.c -d Factorial.dats
atscc2js -o Factorial_dats.js -i Factorial_dats.c

As a concrete example, please see the code in Factorial.dats. At the beginning of the file, the following code is present:

// #define ATS_MAINATSFLAG 1 #define ATS_DYNLOADNAME "Factorial__dynload" //

which indicates to patsopt that a dynload-function of the name Factorial__dynload is to be generated when the ATS source contained in Factorial.dats is compiled into C. Then this dynload-function is transpiled into JS by atscc2js, and it is supposed to be called first (to perform initialization) before any function in the generated JS code is put into use.

The following lines in Factorial.dats are added for accessing the LIBATSCC2JS library, which is needed for compiling ATS to JS:

// #define LIBATSCC2JS_targetloc "$PATSHOME/contrib\ /libatscc2js/ATS2-0.3.2" // #include "{$LIBATSCC2JS}/staloadall.hats" // for prelude stuff #staload "{$LIBATSCC2JS}/SATS/print.sats" // for printing into a store //

The version we use here is ATS2-0.3.2, which is the latest stable release of LIBATSCC2JS.

In the following code, a function of the name funarg1_get is declared in ATS and implemented in JS:

// extern fun funarg1_get(): int = "mac#" // %{^ function funarg1_get() { return parseInt(document.getElementById("funarg1").value); } %} (* end of external code *) //

The function funarg1_get essentially locates a DOM-element identified by funarg1 and then converts into an integer the string stored in the value-field of the DOM-element. Note that the use of the string "mac#" simply indicates to patsopt that the function funarg1_get is to be given the same name when compiled into C. In contrast, the name automatically chosen (by patsopt) for funarg1_get contains a long prefix (for carrying some namespace information) if the string "mac#" is not present. In case a different name is needed for funarg1_get in C, the name should be explicitly mentioned after the symbol #. For instance, if the string "mac#JS_funarg1_get" is used, then the name JS_funarg1_get is chosen (by patsopt) for funarg1_get. In ATS source, the code written between %{^ and %} is considered external and is directly pasted by patsopt into the generated C code. The symbol ^ means that the pasted code is to appear near the beginning of the generated code. If the symbol ^ is omitted or replaced with $, the code is to be pasted near the bottom of the generated code.

The following function is called when the Evaluate button is clicked:

// extern fun Factorial__evaluate ((*void*)): void = "mac#" // implement Factorial__evaluate ((*void*)) = let val () = the_print_store_clear() val arg = funarg1_get() val () = println! ("The factorial of ", arg, " is ", fact(arg)) // end of [val] val theOutput = document_getElementById("theOutput") // end of [val] in xmldoc_set_innerHTML(theOutput, the_print_store_join()) end // end of [Factorial__evaluate] //

There is a global store, an array of strings, for receiving the output generated from calling various print-functions. The function the_print_store_clear is for clearing this store and the function the_print_store_join for joining the strings contained in the store into a single one. Given a name, document_getElementById locates the DOM-element identified by the name. Given a DOM-element and a string, xmldoc_set_innerHTML updates the innerHTML-field of the DOM-element with the string.

For a more involved example, please visit on-line a webpage for animating the process that searches (in the depth-first fashion) for solutions to the 8-queen puzzle. The HTML source for the webpage can be viewed here, and the code implementing depth-first search is simply adapted from some sample ATS code presented in a previous chapter.

Please find on-line the entirety of the code used in this chapter. The mentioned URL link(s) can be found as follows: