HipHop Environment
==================
> [!NOTE]
> The source files used in this chapter are available in the HipHop
> [github](https://github.com/manuel-serrano/hiphop/tree/master/examples/web)
> repository.
Shell Variables
---------------
HipHop uses the following shell variables environment:
* `HIPHOP_DEBUG`: `true` | `false`.
* `HIPHOP_TRACE`: `causality`, `compile`, `connect`, any combination of these keywords.
* `HIPHOP_COMPILER`: `orig` | `int` | `new`.
* `HIPHOP_NATIVE`: `true` | `false`, compile acyclic net lists to plain JavaScript.
* `HIPHOP_DEBUG_NATIVE`: `true` | `false`, dumps the native JavaScript code when true.
* `HIPHOP_SWEEP`: `true` | `false`.
* `HIPHOP_DUMPNETS`: `true` | `false`.
Running HipHop programs on the Web (server and client)
------------------------------------------------------
In this chapter, we show how to run HipHop programs on a server-side
of an application, e.g., on Nodejs, and on the client-side of a web
application, .e.g., on Firefox. To run the examples, first create a
fresh directory and install HipHop inside it.
```shell
mkdir example
cd example
npm install https://www-sop.inria.fr/members/Manuel.Serrano/software/npmx/hiphop.tgz
```
In the rest of this section we assume the file `abro.hh.js` defined as:
★ [abro.hh.mjs](../examples/web/abro.hh.mjs)
### Server-side execution ###
To execute a HipHop program on an unmodified JavaScript execution engines,
let it be Nodejs, Hop, or any other compliant engine, it has to be
compiled first. This is accomplished by the `hhc.mjs` compiler that
is part of the standard HipHop distribution. To compile our `abro.hh.js`
example, one has to use the following command:
```shell
./node_module/@hop/hiphop/bin/hhc.mjs abro.hh.mjs -o abro.mjs
```
This will generate two files:
* `abro.mjs`, which a standard JavaScript ES6 module.
* `abro.map.json`, which is a _source map_ file that will let the
native JavaScript engine refer to source location inside `abro.hh.js`
instead of `abro.mjs`.
Once, compiled, the program can be imported by any regular ES6 module
and executed using the HipHop API. Example:
★ [hello.mjs](../examples/web/hello.mjs)
This program can be executed with:
```shell
nodejs --enable-source-maps hello.mjs
```
### Client-side execution with a Nodejs server ###
In this section we show how to use HipHop on client-side of web
applications. We show how to proceed to implement a web app executing
the `abro.hh.mjs` reactive program on a web browser. Let's implement a
minimal web server only using the bare
Nodejs' [http](https://nodejs.org/docs/latest/api/http.html) api.
Let us first describe the web page the server delivers.
★ [index.html](../examples/web/index.html)
The `script type="importmap"` specify a mapping from JavaScript module
names to URL. As such, when the JavaScript code running on the browser
will import the module `@hop/hiphop`, the browser will request the URL
`/hiphop.mjs` to the server (we'll see in a moment how we configure
the server so that it can respond to this request). By specifying a
module-to-URL mapping, we can re-use the same program `abro.mjs`
as the one we use when running on the server, althought the module
`@hop/hiphop` has different implementations for the server and for the
client.
The configuration of the web server is as follows:
★ [node-server.mjs](../examples/web/node-server.mjs)
It is a standard implementation of a web server using Nodejs and contains
no code specific to HipHop.
### Client-side execution with a Hop Server ###
We can simplify the implementation of our simple HipHop web
application by using a [hop](https://github.com/manuel-serrano/hop)
server instead of a plain Nodejs server.
As for the previous example, the Hiphop `abro.hh.mjs` file remain unchanged.
In Hop, the standard way to generate HTML documents is to build them
dynamically using the builtin XML syntax. The HTML page will be then
generated by the `index` function defined as:
★ [index.hop.mjs](../examples/web/index.hop.mjs)
Before being executed, this module has to be compiled to plain JavaScript
```shell
./node_modules/@hop/hop/bin/hopc index.hop.mjs -o index.mjs
```
The main difference with the static document we have used for Nodejs is
the use of the `R` variable. The Nodejs version was only able to deliver
a fixed set of files and the mapping between URL and files was fixed once
for all at the initialization of the program. Hop uses a more elaborated
mechanism for implementing the mapping. The only useful information here
is that `R` is a bidirectional data structure mapping actual file names
to URL and vice-versa.
The server-side module is defined as follows:
★ [hop-server.mjs](../examples/web/hop-server.mjs)
Typed HipHop (a.k.a. TypeScript compilation)
--------------------------------------------
In this section we show to use add type annotations to HipHop programs
and how to use the TypeScript compiler to detect type errors statically.
The build process is more complex because TypeScript requires all the
sources to be available when it compiles a module (otherwise, it
cannot type-check the module being compiled) and because of the import
rules TypeScript uses. In a TypeScript `import` form, the module file
name designates the name of the generated JavaScript file, not the
name of the TypeScript source file. The last difficulty is to deal with
source-map files. The TypeScript compiler generates source-map but does not
read any. Meaning that if a TypeScript file is generated, the TypeScript
compiler cannot associates the program it compiles with another source
file. In this section, we show how to use the `hhc`, the HipHop compiler,
and `hopc`, the Hop compiler to solve all these issues.
First let's add type annotations to the `abro` HipHop module. This
typed version is stored in a file named `abro.hh.ts`.
★ [abro.hh.ts](../examples/typescript/abro.hh.ts)
This file has to be compiled in two steps. First, it has to be compiled
to plain TypeScript.
```shell
./node_module/@hop/hiphop/bin/hhc.mjs abro.hh.mjs -o abro.ts
```
and the, using the `hopc` compiler into a plain JavaScript file. The `hopc`
compiler is a mere wrapper around the `tsc` compiler. To let `tsc` generates
a JavaScript ES module instead of the CommonJS module, there must be
a `package.json`. For instance:
★ [abro.hh.ts](../examples/typescript/package.json)
The declaration `"type": "module"` tells `tsc` to generate an ES module. The
compilation is executed with:
```shell
./node_module/@hop/hiphop/bin/hopc.mjs abro.ts -o abro.mjs
```
> [!NOTE]
> We compiled `hopc` instead of `tsc` for compiling the generated TypeScript
> file, because `hopc` is able to deal with multiple source-map file, so that
> the file `abro.map.json` that will get generated will correctly map any
> possible runtime erroor into the orignal `abro.hh.ts` file. If we had used
> `tsc` instead, the generated `abro.map.json` file would have pointed to
> `abro.ts` instead.
Let us assume a main program that imports the HipHop machine:
★ [hello.ts](../examples/typescript/hello.ts)
This program can be compiled and executed with:
```shell
./node_module/@hop/hiphop/bin/hopc.mjs hello.ts -o hello.mjs
node --enable-source-maps hello.mjs
```
The Net List
------------
The HipHop compiler generates a net list from a HipHop source using
the technique described in [The Constructive Semantics of Pure
Esterel](http://www-sop.inria.fr/members/Gerard.Berry/Papers/EsterelConstructiveBook.pdf).
This compiled program can be executed by simulating the generated
circuit. Two tools `tools/nets2text.mjs` and `tools/nets2dot.mjs`
can be used to visualize these circuits.
#### The tool `tools/nets2text.mjs` generates a plain text.
Here is how to proceed for generating these files, considering
a HipHop source file named `foo.hh.js`:
1. Add the option `{ dumpNets: true }` to the reactive machine for
which you want to dump the net list, or set the shell `HIPHOP_DUMPNETS=true`
to dump the net lists of all machines.
2. Run your program. This will generate two files: `foo.hh.js.nets-.json`
and `foo.hh.js.nets+.json`. The former is the net list before optimizations
the latter after optimizations.
3. Generate the text files:
- bin/nets2text.js foo.hh.js.nets-.json > nets-.txt
- bin/nets2text.js foo.hh.js.nets+.json > nets+.txt
#### The tool `tools/nets2dot.mjs` can be used in conjunction
with the [dot](https://graphviz.org) graph visualizer to generate PDF
files. Here is how to proceed for generating these files, considering
a HipHop source file named `foo.hh.js`:
1. Add the option `{ dumpNets: true }` to the reactive machine for
which you want to dump the net list.
2. Run your program. This will generate two files: `foo.hh.js.nets-.json`
and `foo.hh.js.nets+.json`. The former is the net list before optimizations
the latter after optimizations.
3. Generate the `.dot` files:
- bin/nets2dot.js foo.hh.js.nets-.json > nets-.dot
- bin/nets2dot.js foo.hh.js.nets+.json > nets+.dot
4. Generate the PDF files:
- dot -T pdf nets-.dot > nets-.pdf
- dot -T pdf nets+.dot > nets+.pdf
The main syntax of the `json` files representing the net lists is as follows:
```bnf
NETLIST ::= {
"filename": STRING, # the name fo the source file of the main hiphop module
"sweep": BOOL, # true iff the sweep optimization is enabled
"nets": [ NET, ..., NET ] # the actual net list
}
```
The syntax of the `NET` is as follows.
```bnf
NET ::= {
"id": INTEGER, # a unique identifier
"lvl": INTEGER, # the re-incarnation level (used for loops)
"type": NET-TYPE, # the type of the net
"fanout": [FAN, ... FAN], # the out nets of this net
"fanin": [FAN, ... FAN] # the int nets of this net
}
NET-TYPE ::= "REG"
| "SIG"
| "TRUE"
| "FALSE"
| "AND"
| "OR"
| "TEST"
| "ACTION"
| "SIGACTION"
FAN ::= {
"id": INTEGER, # the net the fan points to
"polarity": BOOL, # the polarity of the connection
"dep": BOOL # true iff a signal dependency
}
```
Nets have also pre-type extra fields.
```bnf
NET-REG ::= { # fields available withe type == "REG"
...
value: BOOL # the initial value of the register
}
NET-SIG ::= { # fields available withe type == "SIG"
...
signame: STRING # the name of the associated signal
accessibility: INTEGER # 1: IN, 2: OUT, 3: INOUT, 4: LOCAL
}
NET-SIG ::= { # fields available withe type == "SIG"
...
signame: STRING # the name of the associated signal
accessibility: INTEGER # 1: IN, 2: OUT, 3: INOUT, 4: LOCAL
}
NET-SIGACTION ::= { # fields available withe type == "SIGACTION"
...
signal: STRING # the name of the emitted signal
}
```
> [!NOTE]
> Finally, `json` structures might contain extra private fields whose names
> start with the `$` characters. These fields are used for better visualizations
> of the net list but they are not required to execute of optimize the net
> lists.
Example. Let us consider the P15 example found in page 75 of
[The Constructive Semantics of Pure Esterel](http://www-sop.inria.fr/members/Gerard.Berry/Papers/EsterelConstructiveBook.pdf). In HipHop this program
is implemented as:
★ [p15.hh.js](../examples/netlist/p15.hh.hs)
The generated net list is:
★ [p15.net.json](../examples/netlist/p15.net.json)
#### Executing the Net List
The execution of a HipHop reaction consists in simulating the
propagation of the electricity in a net list. For that HipHop puts all
the nets in a queue and removed the nets one by one when all their
dependencies are known. It initiates the process with the `REG` nets
whose values are always known at the beginning of the reaction and
with the `TRUE` and `FALSE` gates.
When a gate has obtained its value in the reaction, it propagates it
to its fanout. When a net receives a value, it checks if this value
is sufficient for it to compute its value in the reaction (for instance,
when an `OR` receives a `true` value, it does not need to wait for all
its `fanin`, and conversely when an `AND` net receives a `false` value).
If it is, it compute its values and registers itself and recurisevely
propagates its value to its fanout nets.
`TEST`, `ACTION`, and `SIGACTION` nets invokes their associated JavaScript
action when the value of the net is known and when all their dependencies
(i.e., the fanins whose `dep` value is `true`) are resolved.
At the end of the reaction, if some nets are left unpropagated, an error
is raised.