Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Markdown
## Building from Source

1. Clone the repository
2. Configure/fetch dependencies
    * [sbt](http://www.scala-sbt.org/0.13/docs/Installing-sbt-on-Linux.html)
    * [BNFC](http://bnfc.digitalgrammars.com/) v2.8.1 Nov 2016 - e.g. `cabal install bnfc`from github:
   ```sudo apt install haskell-platform
      git clone https://github.com/BNFC/bnfc.git
      cd bnfc/source
      cabal install```
    * jflex from apt
    * [cup 0.11b-2014 or later](https://versioncontrolseidl.in.tum.de/parsergenerators/cup), easiest to get from git
3. cd into the rholang/ folder
4. Run `sbt bnfc:generate` to generate the parser
5. Run `sbt compile` to compile classes
6. Run `sbt assembly` to build a stand-alone .jar file

## Command-line usage

    $ ./rho2rbl examples/token.rho
    compiled examples/token.rho to examples/token.rbl

which is short for:

    $ java -jar target/scala-2.11/rholang-assembly-0.1-SNAPSHOT.jar examples/token.rho 
    compiled examples/token.rho to examples/token.rbl

## SBT Console

After generating the parser:

1. Run `sbt console` to launch the sbt console
2. In the sbt console import the compiler with `import coop.rchain.rho2rose._`
3. And then compile any Rholang ".rho" file with `Rholang2RosetteCompiler.main(Array("<path_to_Rholang_file>.rho"))`

Certain Note(rare) ifsituations youmay makerequire anysbt changesclean youor may need to run `sbt clean` or `sbt bnfc:clean`.sbt bnfc:clean. (Mainly if you have changed bnfc)

## Structure of rholang/ directory
```
.
├── examples                            # Contains all example contracts
│   ├── old                             # Contains all old example contracts
│   ├── hello_world_again.rho
│   ├── log_time.rho
│   └── token.rho
├── lib                                 # Any jars we use in the compiler
│   ├── java-cup-11b.jar
│   ├── java-cup-11b-runtime.jar
│   └── JLex.jar
├── project                             
│   ├── target
│   ├── BNFC.scala
│   └── build.properties
├── src                                 # All source files
│   └── main
│       ├── bnfc                        # Folder containing current BNFC spec
│       ├── bnfc_old
│       ├── java
│       │   ├── JLex
│       │   └── rholang                 # BNFC generated AST
│       │       └── parsing
│       │           ├── delimc
│       │           │   └── Absyn
│       │           ├── lambda
│       │           │   └── Absyn
│       │           ├── rholang1
│       │           │   └── Absyn
│       │           └── rholang2
│       │               └── Absyn
│       ├── k
│       └── scala
│           ├── lib                     # Helper classes for the compiler
│           │   ├──└── term
│           │   └── zipper
│           └── rholang
│               └── rosette             # Scala files for the compiler
├── target                              # SBT compile output
│   ├── resolution-cache
│   ├── scala-2.11
│   └── streams
├── build.sbt                           # SBT build file
├── LICENSE
└── README.md
```

## Adding a new construct to Rholang

1. Add the syntax of the new construct in rholang/src/main/bnfc/rholang.fc
2. Run "sbt bnfc:generate" to get the new construct into the parser
3. Add a new visit method in src/main/scala/rholang/rosette/Roselang.scala and specify what the new construct should translate to in RBL. For example, if we are adding the Map type to the compiler and it has type QMap in the AST and we want it to translate to a RblTable in Rosette, we would write as follows:

```
  override def visit( p : QMap, arg : A) : R = {
    combine(
      arg,
      L(G( s"""(new RblTable)"""), Top())
    )
  }
```

4. Run "sbt compile" and "sbt assembly" to have that translation included into the compiler

## Details of the Compiler Source

The file src/main/scala/rholang/rosette/Roselang.scala is responsible for the meat of the compiler: essentially it translates the parsed Rholang AST into RBL source. The translation follows a modified version of the FoldVisitor pattern that comes with the default BNFC generator. The main compilation action is documented in the source as follows:



```
  /* The signature of the basic compilation action is 
   * 
   *      def visit[T]( p : T, arg : A ) : R
   * 
   * Where T is the type of expression being compiled and arg is the
   * context into which the result of the compilation will be placed.
   * For example, the compilation of the Nil process is the rosette
   * expression #niv (no intrinsic value). This expression will be
   * placed into the context represented by arg.
   * 
   * The compilation process is made completely regular
   * by certain embeddings. This means we have a single data type for
   * both the context, A and the result R. This regularity ends up
   * being forced by how the visitor pattern works together with
   * certain coherence requirements on all the bodies of the visit
   * method definitions. The embeddings are as follows: 
   * 
   *   1. every expression e lifts to a tree, * t = unit( e ),
   *      which is just e regarded as a tree; 
   *   2. every tree t lifts to a location, l = L( t, T() );
   *   3. every context c can be lifted to a location l = L( V( "*H*" ), c )
   *   4. the composition of context with tree can be uniquely lifted
   *      to a composition of locations of the form
   *      l1 = L( V( "*H*" ), c )
   *      l2 = L( t, T() )
   *      (See the combine method above.)
   * 
   *  So every visit body will be of the form:
   * 
   *     combine( 
   *       arg,
   *       ( context( p ) /: p.parts )( 
   *          { 
   *             ( acc, e ) => {
   *                combine( acc, visit( e, L( V( "*H*" ), T() ) ) ) 
   *             }
   *          }
   *       )
   *     )
   * 
   *  where p.parts stands in for accessing the components of the
   *  expression p. 
   * 
   *  This folds over the parts accumulating the results of compiling
   *  the sub-expressions of p, and then placing them into the right
   *  piece of the compilation p, and then finally places the result
   *  of the fold into the context supplied by arg. Of course, p is
   *  not generally a collection of its parts and so the access of
   *  of the parts of p will be specific to the structure of the
   *  expression, p. Likewise, the combination of the results of the
   *  compilation of the components of p will be more specific than a
   *  fold. However, this gives the general intuition behind how this
   *  algorithm works. Furthermore, it works generally for any CFL.
   * 
   *  This method favors regularity and ease of reasoning over
   *  efficiency. However, it is vastly more efficient than the
   *  parser combinators method provided out of the box by Scala as
   *  testing on a parser for prolog revealed in production.
```

## Debugging

I have found it useful to step through using the Intellij Debugger. I have also tried debugging using jdb but the interface wasn't as nice.

### Intellij Debugger Steps 

1. Open the rchain/rholang project in Intellij
2. Goto run -> debug -> edit configurations...
3. Click on the "+" on the top left and create a new Scala Console configuration
4. Add a debugging breakpoint on any line in the source code
5. Run the compiler through the scala console as instructed above

...