Skip to content

Commit

Permalink
oprions push and pop was implemented and documented, also there is a …
Browse files Browse the repository at this point in the history
…more extensive test for options

options also has now an alias option singular
  • Loading branch information
verhas committed Aug 24, 2023
1 parent 6568963 commit 2d7d86f
Show file tree
Hide file tree
Showing 16 changed files with 305 additions and 143 deletions.
1 change: 1 addition & 0 deletions RELEASES.jim
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ You can find some bare release numbers in the documentation even though the exis
{@define ! RELEASE:SZIKSZO=1.7.3}
{@define ! RELEASE:LUZERN=1.7.4}
{@define ! RELEASE:BASEL=1.7.6}
{@define ! RELEASE:CHICHAGO=1.7.8}
{@define ! RELEASE:OBERGLATT=1.9.0}
{@define ! RELEASE:EMBRACH=1.9.1}
{@define ! RELEASE:ZOLLIKOFEN=1.11.0}
Expand Down
2 changes: 1 addition & 1 deletion documentation/PAROPS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ As we have seen, the `include` macro with the parops
uses the `[` and `]` characters.

The built-in core macros use these separator characters.
Currently 11 built-in core macros have parops.
Currently 12 built-in core macros have parops.

The class `Scanner` provides the tools to ease parop parsing.

Expand Down
121 changes: 74 additions & 47 deletions documentation/macros/options.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ since version `1.0.3`
{@options o1 ~o2}

The `options` macro can be used to alter the behavior of Jamal.
The options can be listed `|` or space separated as an argument to the macro.
The options can be listed `|` or space separated after the macro name `options`.
Using the `~` character in front of the option name will switch off the option.

You can also use the `option` (singular) alias, which makes sense when you set or reset only a single option.

== History

since 2.1.0 it is possible to query the values of options.
* Since the release 2.1.0 it is possible to query the values of options.
* Since the release 2.4.1-SNAPSHOT options can be pushed and popped.

== Description

Expand All @@ -30,7 +33,7 @@ For example the following macro sets three options:
{@options lenient|failfast|mySpecialOption}
----

The first one is used by many core macros not to raise an error if the number of parameters does not match the number of arguments.
The first one is used by many core macros not to raise an error if the number of the parameters does not match the number of arguments.
It is used by Jamal itself and by the `for` macro.
The second will instruct the Jamal engine not to try to recover from errors.
The third one is a custom option that can be used by any other macro.
Expand Down Expand Up @@ -90,74 +93,98 @@ It is possible to export the options to higher layers the same way as you can ex
An option can be switched off using the `~` character in front of the options name.
There can be no space between the `~` character and the name of the option.

Similar to user defined macros, options containing a `:` are global.
Similar to the user defined macros, options containing a `:` are global.
You can define a global value for an option using the `:` prefix in front of the name of the option.
This character will be removed from the name, the same way as it is removed from the name of global user defined macros.
If the `:` is inside the name, then it remains part of the name, and it is not possible to have a local definition for the option.

The options implemented currently:

=== `:lenient`
== Pushing and Popping options

In the lenient mode, the number of the arguments to a user-defined macro do not need to be exactly the same as it is defined.
If there are fewer values provided, then the rest of the arguments will be an empty string in the lenient mode.
Similarly, if there are more arguments than needed the extra arguments will be ignored.
The option `lenient` is global.
Nothing will stop you to redefined the option in a local scope, but macro evaluation will use the global value even in that scope.
With the release 2.4.1-SNAPSHOT it is possible to push and pop options.
This is useful when you want to set an option for a short time without opening a new evaluation scope.
The format of pushing new values for options is the same as setting except the parop `push` is used.

The lenient mode also applies to the multi variable for loops.
In lenient mode there may be more or less actual values than the number of loop variables.
{@options [push] o1 ~o2}

=== `omasalgotm` (since 1.2.0 < 1.10.0)
When you pop the old value you do not specify the value of the option, the names of the options are simply a list.
Because of that it is an error to precede an option name with the `~` character when popping.

Jamal 1.2.0 changed a lot from 1.0.0 in the way how macros are evaluated.
The version 1.2.0 is safer and more flexible and is compatible with the older versions in most of the cases.
There may be some cases when the macros are not compatible with the old version.
In this case, it is recommended to alter the macros so that they do not rely on the old evaluation algorithm.
In the meantime, it is possible to use the option `omasalgotm` to force Jamal to the old evaluation style.
{@options [pop] o1 o2}

Version 1.10.0 and later versions do not implement this option.
The code providing compatibility with the old evaluation style is not included in the distribution.
It is an error popping an option that was not pushed before.
The options keep their history in a boolean stack.
Pushing and popping can be mixed with evaluation scopes keeping the following simple rules in mind:

=== `nl` (since 1.3.0)
- Global options having `:` in their names are always updated in the top level scope and are not affected by the local scopes.

* 1.3.0 till 1.7.6 introduces the option `nl`.
* 1.7.7 removes this option
. Setting and pushing a local option creates a new option instance if the option was not defined in the current scope.

When this option is in effect, then all new-line characters are copied into the output.
This was the default and non-changeable behavior prior to 1.3.0.
. When a new option instance is created in the current scope it inherits the value of the option from the parent scopes.
This is an intermediary step before the set or push is executed and not visible from the outside.
However, if the option was defined `true` then the saved value

In versions 1.3.0, and later, it is possible to escape a newline character that is following a macro closing string.
For example, the macro `{@define z=1}` can be followed by a `\` character before the newline.
That way `{@define z=1}\` will tell Jamal that the next newline character is not needed in the output.
The backslash, the newline character following it and the spaces that may be between the two will be skipped.
- If the option was defined in the same or in a higher scope, then the option is updated.

The `\` character has to follow the macro closing string immediately, spaces are not allowed.
There can be spaces between the `\` character and the following new-line character.
The following example shows a complex use case that demonstrates the behavior of pushing and popping options mixed with different scopes.

.Jamal source
[source]
----
{@define z=1}\n <- new line will get into the output
{@define z=1}\\n <- the \ and new-line will be skipped, it does not get into the output
{@option w}true:{w}
{@option q}true:{q}
{@option r}true:{r}
{#ident {@undefine w}
{@option [push] ~w}false:{w} {@option [pop] w}false:{w}
{@option [push] ~q}false:{q} {@option [pop] q}true:{q}
{@option [push]~r}\
}\
true:{w}
true:{q}
true:{r}
----

{@define z=1}\ ... \n <- there can be spaces between the \ and the \n, still the
\ and new-line characters will be skipped
will result in:

{@define z=1} ... \\n <- nothing is skipped, there are spaces before the \ character
.output
[source]
----
true:true
true:true
true:true
false:false false:false
false:false true:true
true:true
true:true
true:true
----

A backslash in any other places is just a character and will not escape a newline.
This escaping works only following built-in and user defined macros.

NOTE: Since this is a slight behavioral change in the input processing, therefore it may break some of the source files.
We decided to change the default behavior because there is a little chance to have escaped new-line characters in existing `jam` files.
On the other hand, we envision that with the introduction of this feature most of the Jamal source files will use this feature.
We wanted to avoid starting every new Jamal source file with the `nl` option setting.
The option `w` and `q` are defined in the top level scope.
When we open a new scope using the macro link:ident[`ident`] the option `w` is undefined in the new scope.
Because of that the option `w` is created in the new scope.
On the other hand the option `q` is defined in the top level scope, so it is not created in the new scope.
When we redefined both of them using the push parop, the option `w` is created in the new scope, but the option `q` is updated in the top level scope.
When we pop the option `w` it gets the default `false` value, but the option `q` is updated in the value inherited from the top level scope.
When we leave the scope, both `q` and `w` has the same value as before.

With the release 1.7.7 this option is not available anymore.
The default behavior, skipping new lines after a `\` character that follows a macro close string cannot be switched off.
The definition of the option `r` demonstrates that the inner scope changes do not effect the value of the option in the outer scope.

== Jamal Core Options

In this section we list all the options which are currently used by the Jamal engine or the core macros.

The options implemented currently:

=== `:lenient`

In the lenient mode, the number of the arguments to a user-defined macro do not need to be exactly the same as it is defined.
If there are fewer values provided, then the rest of the arguments will be an empty string in the lenient mode.
Similarly, if there are more arguments than needed the extra arguments will be ignored.
The option `lenient` is global.
Nothing will stop you to redefined the option in a local scope, but macro evaluation will use the global value even in that scope.

The lenient mode also applies to the multi variable for loops.
In lenient mode there may be more or less actual values than the number of loop variables.

=== `failfast` (since 1.7.8)

Expand Down
119 changes: 67 additions & 52 deletions documentation/macros/options.adoc.jam
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
{@options o1 ~o2}

The `options` macro can be used to alter the behavior of Jamal.
The options can be listed `|` or space separated as an argument to the macro.
The options can be listed `|` or space separated after the macro name `options`.
Using the `~` character in front of the option name will switch off the option.

You can also use the `option` (singular) alias, which makes sense when you set or reset only a single option.

== History

since 2.1.0 it is possible to query the values of options.
* Since the release {%RELEASE:BERLIN%} it is possible to query the values of options.
* Since the release {%RELEASE:ROGACHEVO%} options can be pushed and popped.

== Description

Expand All @@ -25,7 +28,7 @@ For example the following macro sets three options:
{@options lenient|failfast|mySpecialOption}
%}

The first one is used by many core macros not to raise an error if the number of parameters does not match the number of arguments.
The first one is used by many core macros not to raise an error if the number of the parameters does not match the number of arguments.
It is used by Jamal itself and by the `for` macro.
The second will instruct the Jamal engine not to try to recover from errors.
The third one is a custom option that can be used by any other macro.
Expand Down Expand Up @@ -76,80 +79,92 @@ It is possible to export the options to higher layers the same way as you can ex
An option can be switched off using the `~` character in front of the options name.
There can be no space between the `~` character and the name of the option.

Similar to user defined macros, options containing a `:` are global.
Similar to the user defined macros, options containing a `:` are global.
You can define a global value for an option using the `:` prefix in front of the name of the option.
This character will be removed from the name, the same way as it is removed from the name of global user defined macros.
If the `:` is inside the name, then it remains part of the name, and it is not possible to have a local definition for the option.

The options implemented currently:

=== `:lenient`
== Pushing and Popping options

In the lenient mode, the number of the arguments to a user-defined macro do not need to be exactly the same as it is defined.
If there are fewer values provided, then the rest of the arguments will be an empty string in the lenient mode.
Similarly, if there are more arguments than needed the extra arguments will be ignored.
The option `lenient` is global.
Nothing will stop you to redefined the option in a local scope, but macro evaluation will use the global value even in that scope.
With the release {%RELEASE:ROGACHEVO%} it is possible to push and pop options.
This is useful when you want to set an option for a short time without opening a new evaluation scope.
The format of pushing new values for options is the same as setting except the parop `push` is used.

The lenient mode also applies to the multi variable for loops.
In lenient mode there may be more or less actual values than the number of loop variables.
{@options [push] o1 ~o2}

=== `omasalgotm` (since 1.2.0 < 1.10.0)
When you pop the old value you do not specify the value of the option, the names of the options are simply a list.
Because of that it is an error to precede an option name with the `~` character when popping.

Jamal 1.2.0 changed a lot from {%RELEASE:ZURICH%} in the way how macros are evaluated.
The version 1.2.0 is safer and more flexible and is compatible with the older versions in most of the cases.
There may be some cases when the macros are not compatible with the old version.
In this case, it is recommended to alter the macros so that they do not rely on the old evaluation algorithm.
In the meantime, it is possible to use the option `omasalgotm` to force Jamal to the old evaluation style.
{@options [pop] o1 o2}

Version 1.10.0 and later versions do not implement this option.
The code providing compatibility with the old evaluation style is not included in the distribution.
It is an error popping an option that was not pushed before.
The options keep their history in a boolean stack.
Pushing and popping can be mixed with evaluation scopes keeping the following simple rules in mind:

=== `nl` (since 1.3.0)
- Global options having `:` in their names are always updated in the top level scope and are not affected by the local scopes.

* 1.3.0 till 1.7.6 introduces the option `nl`.
* 1.7.7 removes this option
. Setting and pushing a local option creates a new option instance if the option was not defined in the current scope.

When this option is in effect, then all new-line characters are copied into the output.
This was the default and non-changeable behavior prior to 1.3.0.
. When a new option instance is created in the current scope it inherits the value of the option from the parent scopes.
This is an intermediary step before the set or push is executed and not visible from the outside.
However, if the option was defined `true` then the saved value

In versions 1.3.0, and later, it is possible to escape a newline character that is following a macro closing string.
For example, the macro `{@define z=1}` can be followed by a `\` character before the newline.
That way `{@define z=1}\` will tell Jamal that the next newline character is not needed in the output.
The backslash, the newline character following it and the spaces that may be between the two will be skipped.
- If the option was defined in the same or in a higher scope, then the option is updated.

The `\` character has to follow the macro closing string immediately, spaces are not allowed.
There can be spaces between the `\` character and the following new-line character.
The following example shows a complex use case that demonstrates the behavior of pushing and popping options mixed with different scopes.

{%sample/
{@define z=1}\n <- new line will get into the output
{@option w}true:{w}
{@option q}true:{q}
{@option r}true:{r}
{#ident {@undefine w}
{@option [push] ~w}false:{w} {@option [pop] w}false:{w}
{@option [push] ~q}false:{q} {@option [pop] q}true:{q}
{@option [push]~r}\
}\
true:{w}
true:{q}
true:{r}
%}

{@define z=1}\\n <- the \ and new-line will be skipped, it does not get into the output
will result in:

{@define z=1}\ ... \n <- there can be spaces between the \ and the \n, still the
\ and new-line characters will be skipped
{%output%}

{@define z=1} ... \\n <- nothing is skipped, there are spaces before the \ character
%}
The option `w` and `q` are defined in the top level scope.
When we open a new scope using the macro {%$ ident%} the option `w` is undefined in the new scope.
Because of that the option `w` is created in the new scope.
On the other hand the option `q` is defined in the top level scope, so it is not created in the new scope.
When we redefined both of them using the push parop, the option `w` is created in the new scope, but the option `q` is updated in the top level scope.
When we pop the option `w` it gets the default `false` value, but the option `q` is updated in the value inherited from the top level scope.
When we leave the scope, both `q` and `w` has the same value as before.

A backslash in any other places is just a character and will not escape a newline.
This escaping works only following built-in and user defined macros.
The definition of the option `r` demonstrates that the inner scope changes do not effect the value of the option in the outer scope.

NOTE: Since this is a slight behavioral change in the input processing, therefore it may break some of the source files.
We decided to change the default behavior because there is a little chance to have escaped new-line characters in existing `jam` files.
On the other hand, we envision that with the introduction of this feature most of the Jamal source files will use this feature.
We wanted to avoid starting every new Jamal source file with the `nl` option setting.
== Jamal Core Options

With the release 1.7.7 this option is not available anymore.
The default behavior, skipping new lines after a `\` character that follows a macro close string cannot be switched off.
In this section we list all the options which are currently used by the Jamal engine or the core macros.

The options implemented currently:

=== `:lenient`

In the lenient mode, the number of the arguments to a user-defined macro do not need to be exactly the same as it is defined.
If there are fewer values provided, then the rest of the arguments will be an empty string in the lenient mode.
Similarly, if there are more arguments than needed the extra arguments will be ignored.
The option `lenient` is global.
Nothing will stop you to redefined the option in a local scope, but macro evaluation will use the global value even in that scope.

The lenient mode also applies to the multi variable for loops.
In lenient mode there may be more or less actual values than the number of loop variables.

=== `{%@snip FAIL_FAST /":(.\w+)"/%}` (since 1.7.8)
=== `{%@snip FAIL_FAST /":(.\w+)"/%}` (since {%RELEASE:CHICHAGO%})

This option tells the Jamal processor to stop at the first error.
With the version 1.7.8 and later, the Jamal processor does not stop the processing at the first syntax error.
With the version {%RELEASE:CHICHAGO%} and later, the Jamal processor does not stop the processing at the first syntax error.
This helps the discovery of more syntax errors in the input.
Prior to 1.7.8, Jamal stopped at the first error.
Prior to {%RELEASE:CHICHAGO%}, Jamal stopped at the first error.
The user could fix the error, restart Jamal and repeat this process for each error one by one.
The feature introduced in 1.7.8 tries to collect all the errors and displays them at the end of the processing as an aggregate error.
The feature introduced in {%RELEASE:CHICHAGO%} tries to collect all the errors and displays them at the end of the processing as an aggregate error.

Using this option, Jamal 1.7.8 and later revert to the old behavior.
Using this option, Jamal {%RELEASE:CHICHAGO%} and later revert to the old behavior.
Loading

0 comments on commit 2d7d86f

Please sign in to comment.