HipHop Modules ============== Modules are the HipHop architectural tool for structuring programs. They are syntactic constructs that facilitate code re-use. There is two ways to use a module: * to [load](./.api.md) it into a reactive machine; * to [run](#run) it from another module via the `run` statement Modules are lexically scoped and each module introduces it own signal and trap scopes. That is: * a module can only use the signal it defines, either in its argument list or locally; * trap labels are only visible inside a module. > [!NOTE] > This chapter documents _static_ modules. _Dynamic_ or _staged_ modules, > that is, modules generated dynamically by prior JavaScrpt executions > are described in the [staging chapter](../staging.md). ### module [ident](arg, ...) [implements [mirror] intf, ...] { sigdecl... } ### ☆ [Formal syntax](../syntax/hiphop.bnf#HHModule) If the optional `ident` is specified a JavaScript constant named `ident` is automatically declared and bound to the HipHop module. That is, the two following forms are equivalent: ```javascript const M0 = hiphop module () { ... }; hiphop module M0() { ... }; ``` Modules parameters (`arg`, ...) are equivalent to variables declared with `var` or `let` forms. They denote Hop values that can be used in any expressions of the module. They are passed to the module with the `run` form. Module bodies constist of HipHop [statements](../syntax/hiphop.bnf#HHStatement). The arguments, which are signal declarations, constitute its interface. Module arguments are either _input_ signals, _output_ signals, or _input/output_ signals. Here is an example of a module with an input, an output signal, and an input/output signal: ```javascript module M1(x) { in S; out T; inout U; ... } ``` These signals, in addition to the ones declared in the optional interfaces (`intf`, ...), form the module interface. For a module to be executed, its signals have to be bound the caller signals in its scope (the scope of the corresponding `run` form). Within a module, the `in`, `out`, and `inout` signals can be used as any [local signals](./signal.md). For instance, the `M1` module can be used in the following `run` statement from a `M2` module. ```javascript module M2() { ... run M1(10) { myS as S, myT as T, U as U } ... } ``` In that example, the `M2`'s `myS` signal is bound to the `M1`'s `S`, `myT` to `T` and `M2`'s signal `U` is bound to `M1`'s signal `U`. Example: [run2.hh.js](../../test/run2.hh.js) See [`run`](#running-modules) for a complete description of the `run` form. Signals that are declared after the first body statements are local signals and they cannot be bound in a `run` statement. #### module.precompile() #### Compiles a module. Compiling a module is optional and serves only the purpose of running preliminary checks such as signal names resolution. HipHop Interfaces ----------------- Module arguments can either be specified in the module declaration or packed into an _interface_ that a module can then implements. The interface declaration is all similar to a module declaration but an interface contains no body. ### interface [ident] [extends intf, ...] { ... } ### ☆ [Formal syntax](../syntax/hiphop.bnf#HHInterface) If the optional `ident` is specified a JavaScript constant named `ident` is automatically declared and bound to the HipHop interface. That is, the two following forms are equivalent: ```javascript const I0 = hiphop interface { in I, out O }; hiphop interface I0 { in I, out O }; ``` Here is an example of interface declaration and use to define a module: ```hiphop interface common { in S; out T }; module mod() implements common { inout U; ... } ``` The signals `S`, `T`, and `U` are all defined in `mod`. A module can also implements the _mirror_ of an interface. This is lets two modules, one emitted, the other receiving to be easily connected. The syntax is as follows: ```hiphop interface intf(out T); module producer() implements intf { ; } module consumer() implements mirror intf { ; } ``` Example: [imirror.hh.js](../../test/imirror.hh.js) Running Modules --------------- A module can be executed either because it is directly loaded into a [reactive machine](./api.html) or because it is ran by other module via the `run` syntactif form. ### run ident(arg, ...) { sig, ...} ### ☆ [Formal syntax](../syntax/hiphop.bnf#HHRun). The module `ident` expression must be a JavaScript variable holding a module. > [!WARNING] > The module resolution always take place *before* the HipHop execution. That is, when a > module identifier is used, that identifier is searched before the execution. The arguments of the `run` form are bound the module variables. When a module is ran the signals of the callee are _linked_ to the caller signals. The purpose of the signals list is to specify are to proceed to this linking. The linkings can either be: 1. `ident`; 2. `ident to ident`; bind the caller signal to the module input signal 3. `ident from ident`; bind the caller signal to the module output signal 4. `ident as ident`; bind the caller signal to the module signal 5. `+`; autocomplete the signals list, bind automatically signals with same names, raises an error if some signals are unbound. 6. `***`; autocomplete the signals list, bind automatically signals with same names, but contrary to `+`, ignore unbound signals. Examples -------- ### A Basic example ### A basic module with one input signal `I`, and one input/output signal `O`. Each time `I` is received, `O` is emitted. The module is directly loaded into a reactive machine. It constitutes the program this machine will execute. Example: [every1.js](../../test/every1.hh.js) ### Example using combined signals ### A module with an input/output signal `O` with default value `5` and a combine function. Example: [value1.hh.js](../../test/value1.hh.js) ### Example of submodule ### This example defines a `main` module that runs a submodule `sub`. The signals `S` and `U` are connected to the submodule under the same name. That is when the input signal `S` is sent to the machine, both modules see it simultaneously and when `sub` emits the output signal `U`, the program behaves as if the emission was executed by `main`. Example: [run.hh.js](../../test/run.hh.js) ### Example of Interfaces ### This example defines two interfaces that are used in two distinct modules. The module `M1` runs the module `M2` by aliasing its signal `Z` to the `M2`'s signal `D` and by linking all the other signals (`A`, `B`, and `C`) directly. Example: [interface.hh.js](../../test/interface.hh.js) ### Example of Mirrored Interfaces ### This example defines two modules connected with mirrored interfaces. Example: [imirror.hh.js](../../test/imirro.hh.js) ### Modules Variables ### This example shows how to use module variable parameters. In that example, two instances of the smae module `mod` are executed in parallel construct, each invoking the module with a different variable paramter value. This example shows, that each instance "sees" its own copy of the parameter. Example: [run4.hh.js](../../test/run4.hh.js) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [[main page]](../../README.md) | [[documentation]](../README.md) | [[language]](./README.md) | [[license]](../license.md)