# Syntax

As I may have anticipated, **Choixe** features are enabled when a **directive** is found. **Directives** are special sub-structures that can appear in different forms:
- "compact"
- "call"
- "extended"
- "special"
- "key-value"

**Note**: some directives are available only in a subset of the previous forms.

## Compact Form

```yaml
$DIRECTIVE_NAME
``` 

Basically a `$` followed by a name. The name must follow the rules of python identifiers, so only alphanumeric characters and underscores ( `_` ), the name cannot start with a digit.

Examples:
-  `$index`
-  `$item`

Only directives without parameters can be expressed in the compact form.

## Call Form

```yaml
$DIRECTIVE_NAME(ARGS, KWARGS)
```

The call form extends the compact form with a pair of parenthesis containing the directive arguments. Arguments follow the rules of a plain python function call, in fact, they are parsed using the python interpreter.

Examples:
- `$var(x, default=hello, env=False)`
- `$for(object.list, x)`

The compact form is essentially a shortcut for the call form when no arguments are needed: `$model` is equivalent to `$model()`.

**Note**: due to some limitations of the current lexer, call forms can contain **at most** one set of parenthesis, meaning that you are **not** allowed to nest them like this:

- ~~`$directive(arg1=(1, 2, 3))`~~
- ~~`$directive(arg1="meow", arg2=$directive2(10, 20))`~~

If you really need to nest **directives**, you must use the **extended form**, introduced in the next paragraph.

## Extended Form

```yaml
$directive: DIRECTIVE_NAME
$args: LIST_OF_ARGS
$kwargs: DICT_OF_KWARGS
```

The extended form is a more verbose and more explicit alternative that allows to pass complex arguments that cannot be expressed with the current limitations of the call form. 

Examples:
- ```yaml
  $directive: var
  $args:
    - x
  $kwargs:
    default: hello
    env: false
  ```
- ```yaml
  $directive: sweep
  $args:
    - 10
    - [10, 20]
    - a: $var(x, default=30) # Directive nesting
      b: 60
  $kwargs: {}
  ```

## Special Form

Some **directives** are available only with special forms, i.e. some forms that do not have a schema, and depend from the specific **directive** used. Do not worry, they are just a few, they are detailed below and their schema is easy to remember.

Example:
```yaml
$model: package.MySuperCoolPydanticModel
$args: 
  foo: 10
  bar: 20
```

Here, the whole dictionary is recognized as a special form and parsed as a single block.

## Key-Value Form

When a directive is expressed in the key-value form, the key-value pair containing the directive is parsed as a single block, instead of having two separate parsings for the key and the value, as occurs normally.

Key-value forms are a lot like special forms, the only difference is that the parsing, instead of consuming the whole dictionary, it consumes only a the key-value pair containing the directive.

Example:
```yaml
$for(my_list): hello
```

Here, we have a dictionary with a single entry consisting of a key and value pair. The directive `$for` is recognized as a key-value form and thus, instead of parsing the key and the value separately, they are parsed as a single block. Contrary to the special and extended form, the dictioanry containing the pair is not consumed by the parsing operation. 

## String Bundles

**Directives** in compact or call form can also be mixed with plain strings, creating a "String Bundle":

`$var(animal.name) is a $var(animal.species) and their owner is $var(animal.owner, default="unknown")`

In this case, the string is tokenized into 5 parts:
1. `$var(animal.name)`
2. ` is a `
3. `$var(animal.species)`
4. ` and their owner is `
5. `$var(animal.owner, default="unknown")`

The result of the computation is the string concatenation of the result of each individual token: `Oliver is a cat and their owner is Alice`.


## Dict Bundles
A "Dict Bundle" is analogous to a "String Bundle" but with:
- Dictionary union instead of string concatenation
- Key-Value forms instead of compact/call forms
  
Just like Compact/Call forms can be mixed with plain strings, Key-Value forms can be mixed with plain key-value pairs in a dictionary:

```yaml
name: mario
$for(my_list, x): hello
age: 203
$for(my_list2, y): 
  - $item(y.foo)
```

## Directives table

| Directive | Compact | Call  | Extended | Special | Key-Value |
| :-------: | :-----: | :---: | :------: | :-----: | :-------: |
|   `var`   |    ❌    |   ✔️   |    ✔️     |    ❌    |     ❌     |
| `import`  |    ❌    |   ✔️   |    ✔️     |    ❌    |     ❌     |
|  `sweep`  |    ❌    |   ✔️   |    ✔️     |    ❌    |     ❌     |
| `symbol`  |    ❌    |   ✔️   |    ✔️     |    ❌    |     ❌     |
|  `call`   |    ❌    |   ❌   |    ❌     |    ✔️    |     ❌     |
|  `model`  |    ❌    |   ❌   |    ❌     |    ✔️    |     ❌     |
|   `for`   |    ❌    |   ❌   |    ❌     |    ❌    |     ✔️     |
| `switch`  |    ❌    |   ❌   |    ❌     |    ❌    |     ✔️     |
|  `item`   |    ✔️    |   ✔️   |    ✔️     |    ❌    |     ❌     |
|  `index`  |    ✔️    |   ✔️   |    ✔️     |    ❌    |     ❌     |
|  `uuid`   |    ✔️    |   ✔️   |    ✔️     |    ❌    |     ❌     |
|  `date`   |    ✔️    |   ✔️   |    ✔️     |    ❌    |     ❌     |
|   `cmd`   |    ❌    |   ✔️   |    ✔️     |    ❌    |     ❌     |
| `tmp_dir` |    ✔️    |   ✔️   |    ✔️     |    ❌    |     ❌     |