Skip to content

Latest commit

 

History

History
198 lines (145 loc) · 7.95 KB

options.adoc

File metadata and controls

198 lines (145 loc) · 7.95 KB

options

since version 1.0.3

Syntax

{@options o1  ~o2}

The options macro can be used to alter the behavior of Jamal. 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 the release 2.1.0 it is possible to query the values of options.

  • Since the release 2.5.0 options can be pushed and popped.

Description

The options macro can be used to alter the behavior of Jamal. It simply defines named boolean values in the Jamal processing that the different built-in macros can query.

For example the following macro sets three options:

Jamal source
{@options lenient|failfast|mySpecialOption}

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. Since this third one is created for this example only it will not have any effect on the processing.

The macro does not check the option’s name.

If you type {@options lenuent} misspelled the options macro will not recognize it as an error. The option lenuent could be used by some other macros and the options macro just treats it as a new option. It stores the options specified, and they can be queried by any other built-in macros. Any extension can define and use any options it likes.

The scope of the options is local, or global the same way as the scope of user-defined macros.

Note

Technically, the options are stored along the user-defined macros. These objects can be evaluated. Their value is either true or false. For example,

Jamal source
{@options applePie|~humblePie}applePie is {?applePie}, humblePie is {?humblePie}

will result in the following output:

output
applePie is true, humblePie is false

It is possible to export the options to higher layers the same way as you can export macros.

Jamal source
{@define macro($a,$b,$c)=$a is $a, $b is $b{#if :$c:, and $c is $c}}\
{macro :apple:pie:truffle}{@comment if there are three arguments, we handle it}
{macro :apple:pie:}{@comment here we need : at end, default is not lenient}
{#ident {@options lenient}{macro :apple:pie:}}{@comment options is local, but lenient is a global option}
{macro :apple:pie:}{@comment here we must have the trailing : because we still do not have a globally defined option options is local}
{#ident {#ident {@options lenient}{macro :apple:pie:}{@export lenient}}{@comment local but gets exported one level up, still not global}
{macro :apple:pie:}{@comment still not global}}
{macro :apple:pie:}{@comment was not exported to this level, only to inside the outer ident block}
{@options lenient}{@comment now this is on the global level}{macro :apple:pie}{@comment nice and easy, global}
{@options ~lenient}{@comment and we can switch it off}
{macro :apple:pie:}
{@options any|option|can  | go | ~go | no go}

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 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.

Pushing and Popping options

With the release 2.5.0 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.

{@options [push] o1  ~o2}

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.

{@options [pop] o1 o2}

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:

  • Global options having : in their names are always updated in the top level scope and are not affected by the local scopes.

    1. Setting and pushing a local option creates a new option instance if the option was not defined in the current scope.

    2. 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

  • If the option was defined in the same or in a higher scope, then the option is updated.

The following example shows a complex use case that demonstrates the behavior of pushing and popping options mixed with different scopes.

Jamal source
{@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}

will result in:

output
true:true
true:true
true:true
false:false false:false
  false:false true:true
true:true
true:true
true:true

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.

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)

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. This helps the discovery of more syntax errors in the input. Prior to 1.7.8, 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.

Using this option, Jamal 1.7.8 and later revert to the old behavior.