Generated code

Adam Bergmark edited this page Sep 30, 2013 · 5 revisions

This is not completely up to date

This page explains what Fay outputs when you compile with it, and how you can configure it. I use a demo project with commandline examples throughout, so that you can reproduce the same inspection steps with your own project.

What Fay outputs

Fay outputs several components which may or may not be necessary depending on your use-case. In order of appearance:

  • The module wrapper
  • The runtime
  • The actual code
  • Exports
  • Builtin-exports
  • Instantiation of the module for executables

The module wrapper

By default, Fay outputs a wrapper around all the code. So if we have a very simple module like this:

import Prelude
main = putStrLn "Hello, World!"

And we compile it with all the default options,

$ fay demo.hs

we get Main as the default module wrapper:

$ head demo.js -n 1
var Main = function(){

If you want to disable the module wrapper all together, and output code “naked”, you can use the --naked flag:

$ fay demo.hs --naked
$ head demo.js -n 3
/*******************************************************************************
 * Thunks.
 */

So it goes straight to outputting the runtime.

The runtime

The “runtime” (that's a loose term) is a set of prim-ops and a couple thunk forcing operations that need to be implemented in JavaScript for speed reasons. It consists mainly of:

  • The thunk code.
  • The monad code.
  • Prim-ops, so (*), (//), list producing operations, etc.
  • FFI conversion functions.

You can read it in the file js/runtime.js in the fay repo.

You generally need all of this output, but simple primitive FFI conversions are specialised as specific functions, e.g.

$ grep '_int' demo.js | head -n 1
function Fay$$jsToFay_int(x){return x;}

So the more generic data type converter,

$ grep 'fayToJs(' demo.js | head -n 1
function Fay$$fayToJs(type,fayObj){

Could technically be ommitted. We'll see why this is useful to know later.

The actual code

This section consists of a list of declarations for all the modules being compiled into one big list. By default, output will be all on one line, but you can use the -p flag to make it prettier to read.

$ fay demo.hs --library --no-builtins -p
$ grep 'var Main$main' demo.js -A2
var Main$main = new Fay$$$(function(){
  return Fay$$_(Prelude$putStrLn)(Fay$$list("Hello, World!"));
});

All modules symbols are named as ModuleName$theName for namespacing.

Exports

Exports are things put in the module object, and they are controlled by your main module's export list, so:

$ fay demo.hs --library --no-builtins
$ grep '^// Exports' demo.js -A 1
// Exports
this.Main$main = Main$main;

So if you have a module like this:

module Exports where
import Prelude
main = putStrLn "Hello, World!"
foo = 123

Then you get main and foo exported:

$ fay exports.hs --library --no-builtins
$ grep '^// Exports' exports.js -A 2
// Exports
this.Exports$foo = Exports$foo;
this.Exports$main = Exports$main;

But if you just put (main) in the exports list, you'll get just main:

$ fay exports.hs --library --no-builtins
$ grep '^// Exports' exports.js -A 2
// Exports
this.Exports$main = Exports$main;

This can be important to remember when considering compression.

Builtin-exports

Fay will export built-ins for use outside of Fay, such as:

  • Thunk forcing.
  • Thunk making.
  • Conversions to and from JS.

So in here,

$ fay demo.hs --library
$ tail demo.js
// Exports
this.Main$main = Main$main;

// Built-ins
this._ = Fay$$_;
this.$           = Fay$$$;
this.$fayToJs    = Fay$$fayToJs;
this.$jsToFay    = Fay$$jsToFay;

};

we see some this.x = … exports.

To stop the inessential ones from being exported, you can use the --no-builtins flag:

$ fay demo.hs --library --no-builtins

(Doesn't have to be combined with --library, that's just for output clarity in this demo.)

Leaving only the thunk forcer, which you will need to actually run your Fay code, so this can't be omitted:

$ tail demo.js -n 3
// Built-ins
this._ = Fay$$_;
};

Instantiation of the module for executables

By default we are compiling programs, so at the end of the file, we instantiate an instance of that module and run it:

$ tail demo.js -n 3
var main = new Main();
main._(main.Main$main);

As in GHC. If you want to disable this instantiation, you can use the --library flag:

$ fay demo.hs --library
$ tail demo.js -n 3
this.$jsToFay    = Fay$$jsToFay;

};