erykmroczek / mofmt Goto Github PK
View Code? Open in Web Editor NEWModelica code formatter
License: Mozilla Public License 2.0
Modelica code formatter
License: Mozilla Public License 2.0
If functions are used in array definitions, newlines with spaces are added to every row of the array.
Moreover, every item of the array is indented with 2 spaces too much.
The issue can be reproduced by running this code through mofmt:
model f_in_array
import Modelica.Math;
Real v1[:] = {1, 2};
Real v2[:] = {2, 3};
Real m[:,:] = Math.Matrices.sort(
[
Math.Vectors.length(v1),
Math.Vectors.length(v2);
Math.Vectors.length(v1 + v2),
Math.Vectors.length(v2 - v1)
]);
end f_in_array;
Which gives for the matrix m
:
Real m[:,:] = Math.Matrices.sort(
[
Math.Vectors.length(v1),
Math.Vectors.length(v2);
Math.Vectors.length(v1 + v2),
Math.Vectors.length(v2 - v1)]);
Similar to #31, annotation indent is too high if the model only contains an annotation (like for documentation classes or extendable icons).
This code for example:
partial model Example
"Icon for runnable examples"
annotation (Icon(graphics = {Ellipse(extent = {{-100, -100}, {100, 100}})}));
end Example;
Produces:
partial model Example
"Icon for runnable examples"
annotation (Icon(graphics = {Ellipse(extent = {{-100, -100}, {100, 100}})}));
end Example;
The error does not occur when the model comment is deleted or if variable declarations are added.
Tested with mofmt 0.5.0 and 0.4.2.
mofmt 0.4.1 stores all changed files with LF line endings, also for files using Windows-style CRLF.
To reproduce, perform the following steps (e.g. with Git Bash on Windows):
$ printf "model M\r\nextends X;\r\nend M;" > M.mo
$ file M.mo
M.mo: ASCII text, with CRLF line terminators
$ mofmt M.mo
$ file M.mo
M.mo: ASCII text
Moreover, line endings in HTML code are not changed, which results in mixed line endings on Windows.
A simple test is to store this code as Doc.mo
with CRLF:
model Doc
annotation (
Documentation(
info = "<html>
Foo
Bar
</html>"));
end Doc;
Then run it through mofmt.
cat -e
shows us that the updated file uses LF for the lines with regular Modelica code and CRLF in the HTML section:
$ cat -e Doc.mo
model Doc$
annotation ($
Documentation($
info = "<html>^M$
Foo^M$
Bar^M$
</html>"));$
$
end Doc;$
Similar to #19, the indentation is broken when a Boolean expression contains newlines.
For every newline the indent is increased by one level .
This is what we get since v0.3.3:
function foo
input Real u1, u2, u3, u4;
output Boolean y;
algorithm
y := u1 > 0
and u2 > 0
and u3 > 0
and u4 > 0;
end foo;
Currently there is no quick way to get the current version of mofmt on the command line.
With mofmt --version
, mofmt tries to format a file named --version
.
Even though it was not defined in the Modelica Language Specification (MLS), Dymola allows to do the following since many years:
Real smallest = (Modelica.Math.Vectors.sort({4, 2, 5, 1}))[1];
We only need the first element of the vector returned by sort
, so this syntax allows to access it without defining an intermediate variable.
As it is no valid Modelica code today, mofmt does not understand this (neither does OpenModelica in its current version 1.22.1).
However, the syntax will make it to the next MLS version 3.7: General subscripting.
Moreover, multiple libraries are already using this, according to comments in the related issue Subscripting of general expressions
Therefore, I suggest to support it sooner or later.
Since v0.3.3 the following code is not understood anymore:
function firstChar
input String s = "foo.bar";
output String c = Modelica.Utilities.Strings.substring(s, startIndex=1, endIndex=1);
algorithm
end firstChar;
It aborts with:
firstChar.mo:3:70: mismatched input '=' expecting ')'
firstChar.mo:3:84: extraneous input ')' expecting ';'
errors met while parsing firstChar.mo. Formatter will not modify it
The reason is the mixing of positional and named arguments in the function call.
The following two variants work:
// only named args
output String c = Modelica.Utilities.Strings.substring(string=s, startIndex=1, endIndex=1);
// only positional args
output String c = Modelica.Utilities.Strings.substring(s, 1, 1);
Modelica allows to have spaces and double quotes in Q-IDENTS (see https://specification.modelica.org/maint/3.6/lexical-structure.html#identifiers for details).
However, mofmt cannot format code when it contains such Q-IDENTS:
model 'foo bar'
end 'foo bar';
block '"foo"'
end '"foo"';
Looking at Q-CHAR in ModelicaLexer.g4 it seems like ' '
is missing, same for '"'
.
Is this an error or a known limitation of mofmt?
Both cases are very rare, so I think it would be enough to mention in the docs that this is not supported (unless it's easy to fix).
Fixing #3 resulted in a regression: Now whitespaces are added to the statement in the line before lines with global paths.
Format this with mofmt v0.3.2:
block Foo
import Modelica.Units.SI;
.Modelica.Blocks.Interfaces.BooleanInput b;
end Foo;
A single whitespace character is added to the line with the import statement:
⋅⋅⋅⋅import⋅Modelica.Units.SI;⋅
(Using ⋅ to make whitespaces visible).
mofmt v0.3.6 supported dropping function return values.
In this exemplary code we ignore the first output ms
of getTime
:
function time
output Integer sec;
output Integer min;
output Integer hour;
algorithm
(, sec, min, hour) := Modelica.Utilities.System.getTime();
end time;
The code can be formatted with mofmt 0.3.6. However, mofmt 0.5.0 says:
Syntax errors detected:
time.mo:6:6: expected IDENTIFIER, found ','
Older Dymola versions had the bad habit to store in modelica code in UTF8 encoding with BOM.
If such a file is formatted, mofmt crashes with:
thread 'main' panicked at C:\Users\ME\.cargo\registry\src\index.crates.io-6f17d22bba15001f\moparse-0.1.4\src\lexing.rs:349:38:
byte index 1 is not a char boundary; it is inside '\u{feff}' (bytes 0..3) of `within MyLibrary.UsersGuide;
...
To reproduce, add a BOM to an UTF8-encoded .mo-file, e.g. with
sed -i '1s/^/\xef\xbb\xbf/' myfile.mo
then run mofmt on it.
Meanwhile Dymola does not store with BOM any more. Therefore, I think a note in the mofmt doc would be enough that only UTF8 encoded files without BOM are supported.
If global class paths are used, the whitespace in front of the path is removed.
Running mofmt on this:
model AbsolutePaths
extends .Modelica.Fluid.Examples.NonCircularPipes(
redeclare package Medium = .Modelica.Media.Water.StandardWaterOnePhase);
end AbsolutePaths;
Gives:
...
extends.Modelica.Fluid.Examples.NonCircularPipes(
redeclare package Medium =.Modelica.Media.Water.StandardWaterOnePhase);
...
Note the missing whitespaces before both global paths starting with .Modelica
.
This is no issue in OpenModelica, but Dymola does not like the missing whitespace between extends
and the class path and automatically reformats the code with a newline:
extends
.Modelica.Fluid.Examples.NonCircularPipes(
redeclare package Medium =.Modelica.Media.Water.StandardWaterOnePhase);
With mofmt 0.4.1 annotations of local class definitions in empty sections (equation, algorithm, protected) are indented one level too much:
Exemplary input:
model M
protected
model X
equation
annotation (revisionId = "c04e23a0d");
end X;
end M;
Output:
model M
protected
model X
equation
annotation (revisionId = "c04e23a0d");
end X;
end M;
I found two cases with similar syntax where running mofmt a second time produces new output:
Format this code with mofmt v0.3.5:
model X
parameter Integer control = 0 annotation (choices(choice = 0 "Foo", choice = 1 "Bar"));
annotation (__Dymola_Commands(file = "modelica://MyLib/Resources/plot.mos" "plot"));
end X;
First run gives:
model X
parameter Integer control = 0
annotation (choices(choice = 0
"Foo", choice = 1
"Bar"));
annotation (__Dymola_Commands(file = "modelica://MyLib/Resources/plot.mos"
"plot"));
end X;
Second run:
model X
parameter Integer control = 0
annotation (
choices(
choice = 0
"Foo",
choice = 1
"Bar"));
annotation (
__Dymola_Commands(
file = "modelica://MyLib/Resources/plot.mos"
"plot"));
end X;
Running it a third time does not give a new result.
mofmt 0.4.1 does not support redeclare replaceable
.
Here is a minimum example:
model M
extends X(
redeclare replaceable Sine x);
end M;
mofmt crashes with this message:
thread 'main' panicked at C:\Users\ME\.cargo\registry\src\index.crates.io-6f17d22bba15001f\mofmt-0.4.1\src\formatting.rs:1025:22:
internal error: entered unreachable code
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
When the keyword replaceable
is removed, the code can be formatted.
A more complex real-world example is e.g. Modelica.Fluid.Valves.ValveVaporizing
.
The selective model extension, which mofmt supports since #6, is not formatted correct.
This code:
model NewPlant
extends System(
break controller,
break reference);
end NewPlant;
Is formatted as:
model NewPlant
extends System(
break controller ,
break reference );
end NewPlant;
Note the extra white spaces at the end of each break statement.
mofmt currently formats the code below as follows:
function sign
input Real u;
output Real y;
algorithm
y :=
if i == 0 then
0
elseif i >= 0 then
1
else
-1;
end sign;
In my opinion the if-expression should be indented by one level:
y :=
if i == 0 then
0
elseif i >= 0 then
1
else
-1;
Try formatting the code below, where a long string passed to a function is joined with +
:
function f1
algorithm
Modelica.Utilities.Streams.print(
"fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
+ "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar"
+ "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz");
annotation (Documentation(info = "<html>Fooo</html>"));
end f1;
In mofmt v0.3.3 and v0.3.4 this gives:
function f1
algorithm
Modelica.Utilities.Streams.print(
"fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
+ "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar"
+ "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz");
annotation (Documentation(info = "<html>Fooo</html>"));
end f1;
Note that everything after the first +
is indented by 1 level too much.
With v0.3.2 it works as expected.
Modelica Language Specificaton 3.6 introduced two new features involving the existing break
keyword, which are not formatted correct by mofmt:
Here is an example using those new features:
partial model ConditionalExtends
extends Modelica.Blocks.Examples.PID_Controller(
break loadTorque,
inertia1(J=break),
break connect(speedSensor.w, PI.u_m));
end ConditionalExtends;
Running it through mofmt 0.3.1 gives no errors, but the output is not satisfying:
partial model ConditionalExtends
extends Modelica.Blocks.Examples.PID_Controller(break loadTorque,
inertia1(J = break), break connect(speedSensor.w, PI.u_m));
end ConditionalExtends;
mofmt usually formats arrays nicely.
However, it has problems with line breaks in row definitions, which is especially a problem for Dymola users.
Here we see what Dymola generates when you define a matrix of size 2x16 via the GUI (with the default maximum line length of 80):
model array
parameter Real a[:,:]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1; 2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2];
end array;
Running the code through mofmt gives:
model array
parameter Real a[:,:] = [
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1;
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2];
end array;
Consider the below model:
model TestComments
// Single-line comment
/*
Multi-line comment 1
Multi-line comment 2
*/
end TestComments;
If formatter is run on such file, the output has incorrect syntax:
model TestComments
// Single-line comment/*
Multi-line comment 1
Multi-line comment 2
*/
end TestComments;
Suprisingly, is blank line between comments is removed, the output has correct syntax, although the result is not desirable, as indentation of lines 3 and 4 is removed:
model TestComments
// Single-line comment
/*
Multi-line comment 1
Multi-line comment 2
*/
end TestComments;
Since mofmt v0.3.3 unnecessary whitespaces are introduced when arrays are passed to functions:
String A = toString([2.12, -4.34; -2.56, -1.67]);
This gives in v0.3.3 and v0.3.4:
String A = toString( [2.12, -4.34; -2.56, -1.67]);
Note the extra space before the array.
Before switching to Rust parser, formatter printed out path of the file that could not be formatted properly (due to e.g. incorrect syntax). Now it is not printed making it hard to find the problematic file when formatting directories.
pre-commit
script invokes mofmt.exe
passing list of files as an argument to the hook. Since mofmt
accepts only single argument, when multiple files are selected by pre-commit
script (e.g. when multiple files are commited) it results in an error:
mofmt....................................................................Failed
- hook id: mofmt
- duration: 0.19s
- exit code: 1
mofmt takes only one argument (file/directory path)
Running mofmt .
is a very convenient way to format all .mo files in a folder.
For git repositories one usually likes to exclude submodules.
Therefore it would be nice if mofmt
has a option to skip all submodules (maybe even active by default).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.