Beta implementation
Following the First Round Of Brainstorming, some functionalities have been implemented in last beta (V1.2019.4beta14)
We have somehow changed our mind since the First Round Of Brainstorming. Instead of having scripts features that would have been executed after the existing preprocessing, we have decided to completely rewrite the preprocessor with all new functionalities. The idea is to keep ascending compatibilies with the current (legacy now) preprocessor.
-
You have to switch to the new preprocessor using a special directive
!preprocessorV2
-
Error management is very basic
Things are now working fine. The idea is to let people play with this beta to see if we are on the right path, talking about syntax.
Variable definition
Although this is not mandotary, we highly suggest that variable name start with a $
.
There are two kind of data:
* Integer number
* String, that must be surrended by simple quote or double quote.
@startuml !preprocessorV2 !$ab = "foo1" !$cd = "foo2" !$ed = $ab + $cd Alice -> Bob : $ab Alice -> Bob : $cd Alice -> Bob : $ef @enduml
Conditions
-
You can use expression in condition.
-
else is also implemented
@startuml !preprocessorV2 !$a = 10 !$ijk = "foo" Alice -> Bob : A !if ($ijk == "foo") && ($a+10>=4) Alice -> Bob : yes !else Alice -> Bob : This should not appear !endif Alice -> Bob : B @enduml
Void function
-
Function name should start by a
$
-
Argument names should start by a
$
-
Void functions can call other void functions
Example:
@startuml !preprocessorV2 !function msg($source, $destination) $source --> $destination !endfunction !function init_class($name) class $name { $addCommonMethod() } !endfunction !function $addCommonMethod() toString() hashCode() !endfunction init_class("foo1") init_class("foo2") msg("foo1", "foo2") @enduml
Return function
A return function does not ouput any text. It just define a function that you can call: * directly in variable definition or in diagram text * from other return function * from other void function
-
Function name should start by a
$
-
Argument names should start by a
$
@startuml !preprocessorV2 !function $double($a) !return $a + $a !endfunction Alice -> Bob : The double of 3 is $double(3) @enduml
It is possible to shorten simple function definition in one line:
@startuml !preprocessorV2 !function $double($a) return $a + $a Alice -> Bob : The double of 3 is $double(3) Alice -> Bob : $double("This work also for strings.") @enduml
Default argument value
In both return and void function, you can define default value for argument.
@startuml !preprocessorV2 !function $inc($value, $step=1) !if $step==0 !return $value !endif !return $value + $step !endfunction Alice -> Bob : Just one more $inc(3) Alice -> Bob : Add two to three : $inc(3, 2) @enduml
Objectives
Currently, users are doing more and more complex stuff with the preprocessor.
The goal of this page is to discuss about a future implementation within PlantUML of some scripting feature within diagram text. Those scripts feature will be executed after preprocessing.
A good start would be to scope the feature. What should the new functionality handle and what not, e.g.
* Variable initialization * Substitution of variable * Substrings and replace parts * Conditions (if, else) * arithmetic-based * string-based * file-based * condition concatenation || and && * Loops (for, while) * Length of a variable
IMHO we should restrict the scope as much as it makes sense.
You can edit this page to add your through and suggestions. We will wait until the design is complete before implementing anything.
Here a first example :
@startuml $i = 0 Alice -> Bob : The value of "i" is $i 'It prints: The value of "i" is 0 $i = $i+1 Alice -> Bob : The value of "i" is now $i 'It prints: The value of "i" is now 1 $if ( $i > 0) Alice -> Bob : this is printed because i value is $i $endif $for ($i=0; $i<10; $i++) Alice -> Bob : in the for loop, "i" value is $i $endfor ' If a variable is not known, it's simply ignored, and the $ is printed as usually. ' This allows to not break compatibility with previous diagrams. Alice -> Bob : The $price is in USD @enduml
I think the first example looks promising. Putting $ in front of a variable to initialize and to access it is a good choice. The $if/$endif/$for/$endfor scopes the condition/loop, I guess? -→ Yes
If a variable is undefined, then it is simply ignored. MG-→ Will there be a test if a variable is undefined or null? About variable testing, we could also test if a variable is undefined:
$ifdef $j Alice -> Bob : The variable j is defined and its value is $j $else Alice -> Bob : I don't know any j variable $endif
MG-→ For sake of the stability yes, maybe a log should be written here in case one need to bugfix the own diagrams. However, think about two cases: . The variable is used as text substitution for the void function, here you can just treat is as text. -→ Yes, agree . How do you want to handle the return function variables that are not defined? .. Do you ignore the whole function? -→ No .. Do you add a "note" with the error? -→ Not exactly. Return function should be syntaxically correct. Otherwhise we print an error message like http://www.plantuml.com/plantuml/png/SoWkIImgAStDuV98BKfLICnJI2qgoYyYWUUGcfS2r0y0 MG-→Printing the error message is perfect. I think this way the user gets the hint to correct it.
Return function
A function doing some computation and returning a result is called return function.
Return function should be syntaxically correct. Otherwhise we print an error message like http://www.plantuml.com/plantuml/png/SoWkIImgAStDuV98BKfLICnJI2qgoYyYWUUGcfS2r0y0
Example:
@startuml $function square($i) $return $i*$i $endfunction $function inc($i) $return $i+1 $endfunction $function abs($i) $if $i>0 then $return $i $else $return -$i $endfunction Alice -> Bob : The price is $square($inc($abs(-9))) ' print The price is 100 @enduml
Void function
A void function does not contain any return. It’s used to generate some part of a text diagram.
Example:
@startuml $function msg($source, $destination) $source --> $destination $endfunction $function init_class($name) class $name { init() toString() hashCode() } $endfunction init_class(foo1) init_class(foo2) msg(foo1, foo2) @enduml
void function can call return function but the other way is not possible.
so you can have:
@startuml $function msg2($source, $destination, $price) $source --> $destination : the price is $square($inc($abs($price))) $endfunction msg2(foo1, foo2, 30) @enduml
Visibility scope of variables
-
Did you think about visibility of variables?
-
-→ Not really :-)
-
-
Is there something like local and global space for those variables or do you want to work with global visibility of variables only?
Here is our proposal: * variables defined in return or void function are local : they are not know outside the function * variables defined outside of function are global : they are visible everywhere, including from function
MG → Sounds consistent. Restricting local variables sounds perfect. Think about how to handle errors that are related to global-local overrides, meaning somebody defines first a global variable and later a local variable with the same name in the function.
[chillin] Keep it simple. Forbid redefinition of a function or variable (with scope visibility). In case this happens, show a clear error message of the redefinition line, the name of the variable, and the line of the original function/variable definition (include the file name if it’s a different (library) file). The target should be to cover most use cases while keeping the implementation and usage as simple a possible. Note: the scope of !included functions/variables shall depend on the location of the !include line.
[SW].OK to forbid redefinition of a function or variable. In order to avoid problems with identical variable names, it would be wise to propose to prefix global variables with _<libname>\_ (or something else). It would be a great pity to define global variables such as i or j (idem for functions).
Data types and arithmethic expressions
Supported data types are:
-
String
-
Integer [SW](32-64 bits?)
-
Boolean
-
Float [SW](32-64 bits?)
Proposal [chillin]: define boolean states by built-in global variables $true and $false. This makes a clear and easy distinction of a boolean and string definition.
When using arithmetic functions the following cases for data types are possible, e.g.: * String + String = concatenated string (no implicit conversion needed) * String + Integer = concatenated string (implicitly does "string + str(integer)") * String + Float = concatenated string (implicitly does "string + str(float)") * Integer + Integer = Integer * Float + Float = Float * [SW]Integer + Float = Float * [SW]Float + Integer = Float
Example:
$a = "a_string" $b = "and a non-string operation always results in " $i = 1 $z_final = " string" A -> B : $a + $b + $i + $z_final 'results in: A -> B : a_string and a non-string operation always results in 1 string
Support the following operators:
-
strings: + (concatenation)
-
float: all normal mathematical operators
-
integer: all normal mathematical operators, [SW](included % as reminder), shift and bitwise operators
-
boolean: all normal boolean operators (and, or, not, xor)
An operation on the built-in $undefined symbol shall always yield $undefined.
Implicit conversions and their results:
-
integer to string (if one of the operands is a string, python-like str() conversion)
-
float to string (if one of the operands is a string, python-like str() conversion)
-
boolean to string (if one of the operands is a string, python-like str() conversion)
-
undefined to string (if one of the operands is a string, the $undefined state results in the 'undefined' string)
-
boolean to integer (if the other operand is an integer the boolean is converted to 1 (if $true), or 0 (if $false))
-
boolean to float (if the other operand is a float the boolean is converted to 1.0 (if $true), or 0.0 (if $false))
-
[SW]integer to float
Explicit conversions:
-
to string: via built-in function $str()
-
to boolean: via built-in function $bool()
-
from string: $false (if the string is empty or whitespace only), or $true otherwise
-
from integer: $true if non-zero, or $false otherwise
-
from float: $true if non-zero, or $false otherwise
-
-
[SW]to integer: via built-in function $int()
-
[SW]to float: via built-in function $float()
Evaluation order is from left to right and can be controlled through parentheses.
Examples:
$a = "implicit conversion results: " $b = 1 $c = 0 $d = $true A -> B : $a + $b + $c 'results in: A -> B : implicit conversion results: 10 A -> B : $a + ($b + $c) 'results in: A -> B : implicit conversion results: 1 A -> B : $a + ($b + $d) 'results in: A -> B : implicit conversion results: 2 A -> B : $a + $b + $d 'results in: A -> B : implicit conversion results: 1 true
Allowed function and variable names
Any function and variable name shall be constructed from the symbol set [A-Zaz0-9\_]. An additional constraint is that a name shall not start with a digit. Function and variable names are case sensitive.
This seems sufficient for most use cases and does not conflict with existing PlantUML naming conventions.
Builtin functions
Some functions are defined by default. Their name starts by %
Name | Description | Example | Return |
---|---|---|---|
|
Calculate the length of a String |
|
|
|
Extract a substring. Takes 2 or 3 arguments |
|
|
|
Search a substring in a string |
|
4 (position of |
|
Check if a file exists on the local filesystem |
|
|
|
Retrieve environment variable value |
|
The value of |
|
Retrieve current dirpath |
|
Current path without ending path separator |
|
Retrieve current filename |
|
Current filename |
|
Retrieve current date. You can provide an optional format for the date |
|
Current date |