Jstream

Jstream

  • Docs
  • API
  • Help
  • Editor
  • Blog

›Parser

Parser

  • Syntax
  • Examples

    • Example 1

Syntax

Parser can be used as a mathematical tool to generate graphs from simple text. It has a minimal and powerful syntax which takes the advantage of repeating patterns inside your graph to minimize the time you waste on writing it.

We will start with a simple representaiton of the following graphs:

flowactual graphnotes
a:ba->b
a:b:ca->b->c
a:b:aa<->b
a:b,ca->b, a->c
a:b,c:aa<->b, a<->c
a:b,c,d:ea->b, a->c, a->d, b,c,d->e
a:[b:c:d],ea->b->c->d, a->e[..] will return the first defined node
a:[b:c],[d:e]:fa->b->c, a->d->e b,d->f

Before we continue, Please use the Live Editor for practice.

Flow

Definition 1.1. A simple graph is a graph which is;

  • Not a multigraph, i.e. there is no more than one edge between each pair of vertices;
  • Not a loop-graph, i.e. there are no loops, that is, edges which start and end at the same vertex;

**Definition 1.2. ** A Flow is a directed-simple graph with a single entry-point (head) such that there is a path from the fist node to every other node in the graph (there may not be a path from every node to any other node).

type Flow = {
  name: string // optional
  graph: string | string[]
}

For example:

{
  "name": "flow0",
  "graph": ["a:b", "b:c"] // same as "a:b:c"
}
name: flow0
a->b->c

To give each node a unique key, a prefix will be added to every node - the flow's name (if there is):

name: flow0
flow0/a -> flow0/b -> flow0/c

Composition

A flow can contain multiple flows just by naming them as a ragular nodes in the graph. The parser will find those flows in the graph and replace them with all their nodes.

[
  {
    "name": "flow0"
    // ....
  },
  {
    "name": "flow1"
    // ....
  },
  {
    "name": "composed-flow",
    "graph": "flow0:flow1"
  }
]

There is only one problem in the above example, if flow0 contains multiple nodes, which node from flow0 did you intend to be the bridge between those flows? To solve this problem, we will need to tell the parser who is that node:

[
  {
    "name": "flow0",
    "graph": "a:b",
    "default_path": "a"
  },
  {
    "name": "flow1",
    "graph": "c"
    // rule: if you have more than one node in a graph,
    //       "default_path" must be specified.
  },
  "flow0:flow1"
]

The above example , will produce a graph representation for every flow. Our nameless-flow will look like this:

flow0/a -> flow0/b
        \
         -> flow1/c

If we will change the default_path to b, it will look like this:

flow0/a -> flow0/b -> flow1/c

To be more precise, the parser will create a flow object for every node that he didn't see yet. The reason is for being able to reuse flows that you already defined.

For the above example, the parser will create the following flows, each with it's graph: a,b,flow0,c,flow1, nameless-flow (flow0:flow1).

You can even change the "default_path" while defining the last flow by explicitly specifing it:

flowactual graphnotes
flow0/a:flow1flow0/a -> flow0/b, flow0/a -> flow1/csame as the first output
flow0/b:flow1flow0/a -> flow0/b -> flow1/csame as the second output

Auto-filling / Auto-inferring

The parser can receive a graph with references to other flows and it will build the output graph based on those flows.

Let's have a look at this parser-configuration:

[
  {
    "name": "flow0",
    "graph": "a:b:c",
    "default_path": "c"
  },
  {
    "name": "flow1",
    "graph": "d:e:f",
    "default_path": "f"
  },
  "flow0:a:flow1"
]

"flow0:a:flow1" will produce the following graph:

flow0/a -> flow0/b -> flow0/c -> a -> flow1/d -> flow1/e -> flow1/f

while "flow0:a:flow1/a", "flow0:a:flow1/b", "flow0:a:flow1/c" will not produce different graph compired to "flow0:a:flow1". That is because the <flow-1>/<flow-2>:<flow-3> syntax means - build <flow-1> but replace it's default_path to be equal to <flow-2>. It means that the node that is linking between <flow-1>/<flow-2> and <flow-3> is <flow-2> inside <flow-1>.

If we won't provide <flow-2>, we don't tell what is the next node/flow we want a edge to. so this syntax, in this case, will not have any effect:

if the graph (or the last node in the graph) is <flow-1>/<flow-2>:<flow-3>, then <flow-1>/<flow-2> equals to <flow-1>.

Note: You need to remember that for every flow you define in the parser-configuration, there will be only a single entry point. Also, if a graph contains multiple flows, each flow will still have a single entry point; inside every graph, no flow is allowed to pass edges from any node inside <flow-1> to any internal (non-head) nodes of <flow-2>.

For example, for the following flows:

[
  {
    "name": "flow0",
    "graph": "a:b:c",
    "default_path": "c"
  },
  {
    "name": "flow1",
    "graph": "d:e:f",
    "default_path": "f"
  }
]

The parser can't produce a new flow based on flow0 and flow1 such that flow0 will have an edge to flow1/e nor flow1/f. If you want that, you will need to use directly e and f or define a composition over them (or manually and explicitly define all the nodes in the graph).

Note: You can use any other string instead of / by specify it in the head of the parser configuration:

{
  "splitters": {
    "extends": "_!!!_"
  },
  "flows": [
    {
      "name": "flow1",
      "graph": "a:b",
      "default_path": "b"
    },
    "a:b:c:d:flow1_!!!_b:a"
  ]
}

Extending (Expending)

The parser can create flow which will extend other flow.

{
  "name": "flow0",
  "graph": "a:b:c",
  "default_path": "c",
  "extends_flows": ["d:e"]
}

"d:e" will produce the following graph: (which node extends flow0)

d/flow0/a -> d/flow0/b -> d/flow0/c -> e/flow0/a -> e/flow0/a -> e/flow0/a

As you can see, "default_path": "c" has an important role; "default_path": "c" defined which node in the extended d will have edge to the head of the extended e.

Note: A flow can extend only a single flow.

Last updated on 8/29/2019 by stavalfi
Example 1 →
  • Flow
  • Composition
  • Auto-filling / Auto-inferring
  • Extending (Expending)
Jstream
Docs
Getting Started (or other categories)Guides (or other categories)API Reference (or other categories)
Community
User ShowcaseStack OverflowProject ChatTwitter
More
BlogGitHubStar
Facebook Open Source
Copyright © 2019 Stav Alfi