### ----------------------------------------------------
### -- Config::BINDish
### -- Licenses: Artistic-2.0
### -- Authors: Vadim Belman <vrurg@lflat.org>
### -- File: docs/md/Config/BINDish/Grammar.md
### ----------------------------------------------------
### -- Chunk 2 of 2
 location => { :in<pdf-collection image-collection>, :type(Str), :type-name<file-path> }
            );
```

With this declaration the following config is incorrect:

``` 
pdf-collection "user uploads" {
    location "/mnt/cloud-data/uploads/pdf"
}
```

Yet, same as with the `type` key, `type-name` is used as smartmatch operator RHS. Therefore if we replace it with: `:type-name(/^ [ "file-path" | .. "-string" ] $/)` or `:type-name(any <file-path sq-string dq-string>)` – then the above snipped will become valid.

#### `value-sym`

This key defines an exact list of allowed grammar rules/tokens of `value:sym<...>` candidates to be tried when a value is parsed. The list must contain the words used between `< >` symbols of `:sym` adverb. I.e. for the `multiplier` option from a previous example we can explicitly make the grammar even don't attempt matching on anything but the numeric values:

``` 
multiplier => { :value-sym<num rat int>, ... }
```

With this pre-declaration the grammar will attempt only tokens `value:sym<num>`, `value:sym<rat>`, `value:sym<int>`. In this case the following example will throw with `Config::BINDish::X::Parse::General` instead of `Config::BINDish::X::Parse::ValueType`:

``` 
multiplier "3.1415926";
```

When the grammar iterates over `value-sym` items it sets `$*CFG-SPECIFIC-VALUE-SYM` dynamic to the currently attempted item. This allows the candidate token to know that it is being expected to succeed and some additional measures could be taken to fulfill the expectations.

For example, if we expect an option to be a file system path then the following example is likely not to parse correctly because the value can be considered both a keyword or a single path element:

``` 
pathy etc;
```

For this reason `value:sym<file-path>` candidate does not attempt parsing something as a path unless it finds a slash separator. I.e. for the above example to work it must look like:

``` 
pathy /etc;
```

or

``` 
pathy etc/;
```

But if we pre-declare the option like:

``` 
pathy => { :value-sym<file-path>, ... }
```

Then `value:sym<file-path>` would know that `etc` would not be tried as a keyword and it can safely consider it a file/directory name.

#### `named`

Block-only key. If *True* then block must have a name. If *False* then block must not be named. Omitting this key allows the name to be optional.

#### `classified`

Block-only. Similar to `named` but for block class. Only makes sense if `named` is true or optional and block name is specified. Otherwise this key is ignored.

#### `value-only`

Block-only. If this key is set to *True* then the block can not contain options, only values are allowed. I.e. with a declaration like:

``` 
foo => { :value-only }
```

The following config would be an error:

``` 
foo { option 42 }
```

But the following example will work:

``` 
foo { 13; 42; 3.1415926 }
```

Note that within a value-only block keywords are treated as keyword values, not as boolean options:

``` 
foo { value1; value2 } # Two string values with type name 'keyword'
bar { value1; value2 } # Two True options because bar is not pre-declared
```

Here is an example of how this peculiarity can be used:

``` 
acl office { 192.168.42.0/24; 192.168.13.0/24 }
acl data-center { 10.42.0.0/16 }
acl customers { 172.10.0.0/16 }
acl any { 0.0.0.0/0 }
network "internal" {
    access-rules {
        allow { office; data-center } # 'allow' is a value-only block
        disable { any }; # value-only block too
    }
}
network "public" {
    access-rules { allow { any } }
}
```

#### `no-values`

Block-only. This property is a direct opposite to `value-only` as blocks declared with it can not hold any values. So, a declaration like this:

``` 
foo => { :no-values }
```

will cause the following to throw:

``` 
foo { "bar"; }
```

Since the property is clearly conflicting with `value-only` use of both within a block declaration will result in an exception thrown.

#### `default`

Specifies the default value of a statement. When used with a block declaration then multiple values can be used.

``` 
blocks => (
    :server => %( :in<.TOP> ),
    :services => %( :default<api login files>, :type(Str), :in<server> ),
),
options => (
    :server-iface<interface> => { :type(Str), :default<*>, :in<server> },
    :server-port<port> => { :type(Int), :default(80), :in<server> },
)
```

Default values are not verified against pre-declaration `type` constrain.

#### `where`

This property meaning is the same, as [`where`](https://docs.raku.org/type/Signature#Type_constraints) clause in Raku: it defines a constraint on the allowed values. The property is used as smartmatch RHS. Consider the examples:

``` 
foo => { :type(Int), :where(* > 10) }
bar => { :type(Str), :where(any <debug info error>) }
```

**Note** that similar outcome could be achieved by using a [`subset`](https://docs.raku.org/language/typesystem#index-entry-subset-subset) with `type` property. But `where` is more obvious on many occasions.

#### `why`

This property must be a short string to be used within error message of the exception thrown when `where` constraint is not met. For example, if there is an option declaration:

``` 
min => { :type(Int), :where(* >= 10), :why('must be 10 or more') }
```

Then defining the option as `min 1;` in a configuration file would produce output similar to the following:

``` 
Option 'min' expects a (Int) value (must be 10 or more) but got 1
  at line 2
    ⏏min 1;
```

### Reservations

#### Names

All keywords and IDs starting with a dot are reserved for internal use. Any use of dot-started names/IDs like *.foo* is discouraged.

#### Option And Block Keywords

The grammar reserves the following keywords for internal use:

  - `include`

  - `use`

#### Blocks

Two blocks are used internally by the grammar: `.TOP` and `.ANYWHERE`. The first one is a kind of global context, where all top-level blocks and options are installed. The name can also be use in a pre-declaration to specify that a statement can be used at the top-level:

``` 
options => ( foo => { :in<.TOP> } )
```

`.ANYWHERE` is used in pre-declaration context to keep track of pre-declared statements which do not have `in` key and therefore can be used literally anywhere in a config file.

Note that no keyword can start with a dot. Therefore there is no way to accidentally declare `.TOP { }` or `.ANYWHERE { }`, even though technically and formally the config file looks like:

``` 
.TOP {
    include "your-config.cfg"
}
```

#### IDs

As it was stated in the [Names](#Names) section any ID string starting with a dot is reserved. Use method `autogen-id` if you need a unique one.

# EXTENSIONS

This section provides tips for writing own grammar extensions. See [`Config::BINDish::Actions`](Actions.md) to find more about action extensions.

## Context

The grammar maintains current parsing context as a way to validate various aspects of config file syntax. In this task it relies upon:

  - `Config::BINDish::Grammar::Context` class

  - `$*CFG-CTX` and `$*CFG-PARENT-CTX` variables containing instances of the `Context` class

  - roles `Config::BINDish::Grammar::StatementProps`, `Config::BINDish::Grammar::ContainerProps` and classes consuming them: `Config::BINDish::Grammar::OptionProps` and `Config::BINDish::Grammar::BlockProps`

  - Raku call stack

Most of the context implementation mechanics are not standardized and subject for change. Yet, a few elements are rather unlikely to change. Among those are:

  - A context has a type, stored in the same-named attribute of the `Context` class. The currently used types are: *"TOP"*, *"BLOCK"*, and *"OPTION"*

  - Except for the *"TOP"* context, all other contexts keep track of their enclosing context via `$.parent` attribute of the `Context` class

  - A context's primary purpose is to provide properties of the currently begin parsed syntax element. Those properties are provided by `props` attribute of the `Context` class and expected to consume `StatementProps` role

If you plan to implement a grammar extension with a rule or token providing own context then it'd make sense to follow the steps taken by `statement:sym<option>` or `statement:sym<block>` rules.

## Extending The Grammar

[`Config::BINDish`](../BINDish.md) contains general information about writing extensions. Here we provide only grammar-specific details.

Only the rules and tokens documented in corresponding section above are guaranteed to be supported and not be changed or removed without deprecation.

The most common way to extend the grammar would be to add a new kind of statement or value type. This must be as easy as adding new rules or tokens akin to the following example:

``` 
role MyExtension is BINDish-grammar {
    ...
    multi rule statement:sym<your-statement> {
        # Your statement syntax rules
    }
    multi token value:sym<your-type> {
        # Your value syntax rules
    }
    ...
}
```

# SEE ALSO

  - [`Config::BINDish`](../BINDish.md)

  - [`Config::BINDish::Grammar::Strictness`](Grammar/Strictness.md)

  - [`Config::BINDish::Grammar::StatementProps`](Grammar/StatementProps.md)

  - [`Config::BINDish::Grammar::ContainerProps`](Grammar/ContainerProps.md)

  - [`Config::BINDish::Grammar::OptionProps`](Grammar/OptionProps.md)

  - [`Config::BINDish::Grammar::BlockProps`](Grammar/BlockProps.md)

  - [`README`](../../../../README.md)

  - [`INDEX`](../../../../INDEX.md)

# COPYRIGHT

(c) 2023, Vadim Belman <vrurg@cpan.org>

# LICENSE

Artistic License 2.0

See the [*LICENSE*](../../../../LICENSE) fi


