Skip to content

ambientsprotocol/ambc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

93 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ambients Protocol Compiler (ambc)

Ambient Syntax a[] to AST { "id": "a", "children": [], "capabilities": [], "create": [] }

Table of contents

Background

Ambients is a protocol for distributed computation. It allows you to request and execute computation as easily as you can data inside OrbitDB. Think of it like AWS Lambda or Azure Cloud functions, but on a decentralized peer-to-peer network.

The protocol also includes guarantees as to the verfiability and safety of the code, all without a blockchain.

Install

$ npm install ambc -g

First, install node.js Then:

$ git clone https://github.com/ambientsprotocol/ambc
$ cd ambc
$ npm install

Usage

Supported source languages

Via the command line

Usage for the CLI tool can be viewed by simply running ambc:

Compile source code to ambient syntax or JSON AST

Positionals:
  input  Path to the source code file you want to compile

Options:
  --help      Show help                                                 [boolean]
  --version   Show version number                                       [boolean]
  --display   Write output to stdout instead of the output file
                                                       [boolean] [default: false]
  --ipfs-api  Use an IPFS HTTP API by specifying a multiaddress i.e.
             "/ip4/127.0.0.1/tcp/5001"
  --format    Output format of the compiler
                           [choices: "ambient", "ir", "final"] [default: "final"]
  -o          Use to specify a custom path to the output file i.e.
              "./out/function.js"

In code

You can also use ambc within your JavaScript code.

const js2amb = require('js2amb')
const { irParser, parse } = require('ambc')

const js = '() => "hello"'

const ambientSyntax = js2amb(js)        // Outputs ambient syntax from JS
const irAst = irParser.parse(js)        // Outputs intermediate representation AST
const finalAst = parse(js)              // Outputs final AST

Note that to get ambient syntax from JavaScript, you will also need js2amb.

Description

From the Ambients whitepaper:

The Ambients protocol overall is programming language-agnostic. That means almost any programming language can be used to write distributed programs, as long as there's a compiler that can process the source language and turn it into the Ambients bytecode. While most common programming languages can be used, due to the protocol primitives, functions and types, functional languages are especially well-suited to write distributed programs.

Compilation model requires all compilers to:

  1. compile original source code to an intermediate abstract syntax structure (usually as in Abstract Syntax Tree)
  2. translate the intermediate structure to the computation primitives, distribution primitives and computation abstractions of the Ambients protocol
  3. generate the bytecode executable from the primitives

ambc satisfies requirements #1 and #2 by compiling ambients syntax, and JavaScript into either an intermeidate representation or final Abstract Syntax Tree.

Both ASTs are lossless encodings, meaning that no data is lost from the ambient syntax and by-proxy the original JS code. Downstream components in the overall system can satisfy requirement #3 as required.

Compiler steps

The compiler is very simple, and has only two primary steps, the second of which has two different types of output (IR vs final)

Step 1: Source code -> Ambients syntax

Compile source code from JavaScript (other languages TBD) to Ambient ASCII syntax. Users can choose to output ambient syntax by passing the --format ambient option to ambc

For example:

() => "hello"

func[
  open_|
  string[hello[]]
]|
open func

Step 2a: Ambients Syntax to intermediate representation (IR) AST

Users can choose to display an IR AST by passing the --format ir option to ambc.

func[
  open_|
  string[hello[]]
]|
open func

{ "type": "Parallel", "children": [
  { "type": "Ambient", "id": "func", "children": [
    { "type": "Parallel", "children": [
      { "type": "Open_", "id": "*" },
      { "type": "Ambient", "id": "string", "children": [
        { "type": "Noop", "id": "hello" }
      ]}
    ]},
    { "type": "Open", "id": "func" }
  ]}
]}

Step 2b: Ambients Syntax to final AST

This is the default output of the compiler, which encodes protocol primitives into the JSON.

func[
  open_|
  string[hello[]]
]|
open func

{
  "name": "",
  "children": [],
  "capabilities": [
    "in_ call",
    "open call",
    "create"
  ],
  "create": [
    {
      "name": "",
      "children": [],
      "capabilities": [
        "open return",
        "open_"
      ],
      "create": []
    }
  ]
}

Intermediate abstract syntax tree format

The IR AST exceedingly and intentionally naive. It simply encodes the ambient syntax directly using a recursive structure of nodes.

Each node has three fields:

  1. type: Required - the type of the ambient, a string enum which can be one of:
    • Parallel
    • Serial
    • Group
    • Ambient
    • In_
    • In
    • Out_
    • Open
    • Open_
  2. id: Optional - a string identifier
  3. children Optional - array of more child nodes

The idea here is that it is the simplest possible encoding that does not lose any of the data presented in the original ASCII syntax. Once the tree is generated it can be stored as a DAG on any compatible store. In development we simply use the in-memory structures to work with, but in practice we will likely use IPFS or IPLD.

Final abstract syntax tree format

The final AST format encodes protocol primitives into the JSON and is more meant for machine consumption. It has the following format. Note that all fields are required but initialized with default blank values.

Each node in the structure has three fields:

  1. name: The name of the ambient
  2. capabilities: The capabilities and co-capabilitie of the ambient. Each capability has three fields:
    1. op: The operation to take, one of:
      • in
      • in_
      • out
      • out_
      • open
      • open_
    2. target: The name of the ambient the capability refers to
    3. next: The action to take after the capability has completed
  3. children: array of one or more child ambients.
  4. create: used to encode group execution, ( ) in the ambient syntax.

Parallel computation is simply encoded using arrays, and serial computation is encoded using a tree structure, using the children field.

Compiler Output

If no output -o is specified, and the --display flag is not used, ambc will return a multihash from an ipfs dag put operation.

This hash will be used by the execution engine to run the code on a distributed, peer to peer network.

Contributing

Please do! Issues and PRs are very welcome.

If you're at all interested in this topic you should definitely seek us out on Gitter, open issues, and submit PRs.

To run the tests:

$ npm install
$ npm test

Contribution Notes:

  • npm test is mapped to make test and either command should produce identical output.
  • To edit the IR parser syntax, edit the grammar at src/ir/ambients.pegjs and then run make build to build the parser.js file (optimized for speed) and its little buddy the parser-tiny.js file, optimized for size.
  • To edit the final parser syntax, edit the js file at src/parser/index.js directly.

License

MIT © Haja Networks Oy