Home » Blog » Nodable » Nodable v0.9

Nodable v0.9

What’s new?

  • Startup screen
  • Visualize an abstract graph
  • Conditional structure layout improved
  • Simpler graph
  • Whole file edition / isolation mode
  • Handle integers
  • Improve reflection system

Short video of Nodable 0.9

You don’t know Nodable? check this out: Nodable website

I will discuss about those features in two distinct parts and I will end with a small conclusion including potential future improvements.

For the users

Startup menu

A startup menu has been added to offer a single-click experience to a Nodable file. The user can create a file, open a file, or an example easily.

Figure – Nodable startup screen.

As soon as a file is open, a side panel is available to access help, file information, settings, and virtual machine UI.

Figure – Example file for-loop.cpp is open, and the side panel has the selected node properties tab selected.

Visualize an abstract graph

Nodable can generate an abstract graph, even if it is incomplete (missing declarations). This feature is useful to edit a program even if can’t (or doesn’t need to) be executed.

Fig. – The graph isolated (line 6) is generated even if variables f and g are not declared in this context

If we try to compile the abstract graph, we get an error regarding to the lack of declaration for f and g variables. You can notice we also got warnings during parsing phase.

Fig. – The compilation for the isolated graph failed.

Conditional structures

The conditional structure’s layout has been improved to better understand what’s going on, even with multiple else.

Fig. – linked if/else if/else blocs

In the previous figure, we can notice the last instruction at the very bottom could be positioned a bit lower to avoid crossing the green line, or we could draw green lines differently by using floating adjustable connectors (cf. Unreal blueprints).

To see more or less detail, I introduced the functionality expand/fold (double click). As you can see below, conditional blocs can be folded to adjust the level of details.

Fig. – the user expand/fold a node to see more or fewer details.

Edges and Variable references

In order to reduce the edge (referred as wire in previous versions of Nodable) count visible on the screen, I decided to hide edges when their length is too long. In such case, to keep the information visible I display the variable name in each inputs where it is connected to. Although, when the user selects a node, we always show the related edges. With that technique, the user gets detailed information only for the focused node.

Fig. – the operator * uses the variable g, but its edge to it is hidden.
Fig. – Operator * is now selected, the wire to g is visible.
Fig. – Variable a is not selected, related edges are hidden.
Fig. – Variable a is selected, its related edges are visible.

The next figure shows another example to illustrate the importance of changing edge visibility depending on the context. The node msg is connected to 4 operators (in orange), displaying them constantly would reduce readability. But of course, when the user selects msg, it is useful to get such information.

Fig. – The node msg is selected, by consequence, Nodable shows any connection (in white) related to this node.

Whole file edition / isolation mode

In the version 0.9 and inferior, Nodable was always focused on current selection (if any), or by default on the current line. Now, when a file is opened, the whole code is parsed, and if possible the abstract graph is generated and displayed.

Fig. – File opened with a full graph generated

User can still isolate selection using isolation mode toggle (CTRL + I) or tool button:

Fig. – Isolation button at the right side of the tool bar.

If isolation mode is turned ON, we get the following behavior:

Fig. – Same file with the isolation mode ON while caret is on line 5.

User can selected any portion to visualize its graph (and may compile and run it).

Fig. – Portion of code (line 8) in isolation mode

Technically

Integers

Nodable now handles 32bits integers. It may seem simple, but introducing integers from a software handling only double was not easy. Introducing a new number type involved to provide implicit cast to have a less verbose code and also to reuse existing (double-based) functions. I had to define how implicit cast would work and how to resolve function signatures.

In the next figure, we assign an integer (42) to the variable a which is a double. You can see in the graph, the literal 42 has a type int while variable d is a double.

Fig. – An integer literal is connected to a variable with type double.

After compiling and running, the variable d has the value 42 as a double.

Fig. – After execution, the integer literal is cast to a double.

Headless tests

Nodable now passes more complex tests, in the next figure you can see a conditional structure nested in a for a loop.

Fig. – Nodable test source code: a test using loop, conditions, and integers.

End to end tests

End to end tests can be run locally (hardware rendering) and on the GitHub CI (macOS, software rendering), reducing the number of manual operations required to test a minimum amount of the features.

Fig. – Example of an end to end test running Nodable and opening the 4 example files before to shutdown.
Fig. – Screenshots are taken during tests to control the UI look afterwards.

Version number

In order to check which version of Nodable runs, the CMake script adds build information during the build configuration. Nodable is now aware of its tag and its git commit hash.

The version is accessible on the startup menu, easy to get the right version of the source code to debug.

Operator bindings

In order to facilitate operator’s implementation binding (link a C++ function to a nodable function), I added a minimalist concept of operator ( symbol, type, and precedence). For example, in Fig. 1 I define the binary operator « + ». An operator is abstract, and is only useful to generate a correct graph, once we want to compile and run our program, we have to give an implementation for any couple of parameters we want to handle. You can see these implementations in Fig. 2. Then we bind the implementations to the operator by using the reflection system (highly inspired by RTTR), by specifying the function, the operator symbol, and the signature as arguments (since functions are polymorphic and/or uses templates, we have to give the exact signature).

Fig. 1 – Line 107, the binary operator + is added to the language.
Fig. 2 – Implementations for the binary operator +.
Fig. 3 – Binding implementations to the corresponding operator symbol « + »

Conclusion

This version of Nodable does not contains major features from a user’s perspective, however the source code has been refactored to adapt to many situations (polymorphism, native function binding). I didn’t mentioned it, but the source code is now divided in 2 big sub-projects: a framework and nodable. This helped to setup end-to-end tests involving GUI and will allow me to make more reusable code.

Since there is now a small application framework in the repository, I am thinking in developing many small tools involving nodes based on it in the future.

From a technical perspective, I would like to get rid of any getters/setters, inheritance, and smart pointers unless it is the only choice. I also see the limits of implementing my own parser and virtual machine, but I found out fun to learn it by practice, as my goal is not to make a production tool, I might want to continue this way…

Download: https://github.com/berdal84/nodable/releases/tag/v0.9.12

Sources: https://github.com/berdal84/nodable/tree/v0.9.12

Laisser un commentaire