# Template Engine Tour

This is a comprehensive guide to the Snippy template engine syntax. The template engine provides powerful text generation capabilities with variable substitution, conditionals, loops, expressions, and more.

## Quick Start

Snippy templates are plain text files with special syntax for dynamic content. The engine processes templates and produces final output by evaluating expressions and statements.

### Basic Syntax Overview

The template engine uses three types of delimiters:

- `{{ expression }}` - **Expressions**: Output values, variables, and calculations
- `{% statement %}` - **Statements**: Control flow, variable assignment, and commands
- `{# comment #}` - **Comments**: Documentation that doesn't appear in output

## 1. Plain Text and Comments

Templates can contain regular text that passes through unchanged:

```
Hello World!
This is plain text.
```

Comments are ignored during processing:

```
{# This is a comment #}
Text before comment
{# Another comment
   spanning multiple lines #}
Text after comment
```

**Output:**
```
Text before comment

Text after comment
```

## 2. Variables and Expressions

### Variable Output

Use double braces to output variable values:

```
Hello {{ name }}!
Welcome to {{ place }}.
```

With variables `name="Alice"` and `place="Wonderland"`:
```
Hello Alice!
Welcome to Wonderland.
```

### Setting Variables

Use the `{% set %}` statement to define variables:

```
{% set name "John" %}
{% set greeting "Hello" %}

{{ greeting }} {{ name }}!
```

**Output:**
```
Hello John!
```

### Dot Notation for Namespaced Variables

Variables can have hierarchical names using dots:

```
{% set config.database.host "localhost" %}
{% set config.database.port "5432" %}

Database: {{ config.database.host }}:{{ config.database.port }}
```

**Output:**
```
Database: localhost:5432
```

### Clearing Variables

Use the `{% clear %}` statement to remove variables from memory:

```
{% set message "Hello World" %}
{% set items.first "apple" %}
{% set items.second "banana" %}

Before clear: {{ message }}
Items: {{ items.first }}, {{ items.second }}

{% clear message %}
{% clear items %}

After clear: {{ message }}
Items: {{ items.first }}, {{ items.second }}
```

**Output:**
```
Before clear: Hello World
Items: apple, banana

After clear:
Items: ,
```

The clear statement can:
- Clear individual variables: `{% clear variable_name %}`
- Clear entire namespaces: `{% clear namespace %}` removes all variables starting with `namespace.`
- Safely handle non-existent variables (no error if the variable doesn't exist)

### Capture Statement

The `{% capture %}` statement allows you to capture template output within a specific scope and store it in a variable. This is useful for generating complex content that you want to reuse or process further.

```
{% set name "Alice" %}
{% set count 3 %}

{% capture greeting_message %}
Hello {{ name }}! You have {{ count }} new messages.
{% if count > 1 %}
That's quite a few!
{% endif %}
{% endcapture %}

Generated message: {{ greeting_message }}

{% set formatted_greeting "Message: " + greeting_message %}
Final output: {{ formatted_greeting }}
```

**Output:**
```
Generated message: Hello Alice! You have 3 new messages.
That's quite a few!

Final output: Message: Hello Alice! You have 3 new messages.
That's quite a few!
```

The capture statement:
- Captures all output (text, variables, expressions) within its scope
- Stores the captured content in the specified variable
- Can contain complex logic including conditionals, loops, and nested expressions
- Preserves formatting and newlines from the captured content
- Can be nested within other statements for advanced template composition

## 3. Arithmetic and Expressions

### Basic Arithmetic

The template engine supports standard mathematical operations with both integers and floating-point numbers:

```
Result: {{ 5 + 3 }}
Product: {{ 4 * 7 }}
Division: {{ 15 / 3 }}
Subtraction: {{ 10 - 2 }}
```

**Output:**
```
Result: 8
Product: 28
Division: 5
Subtraction: 8
```

### Float Arithmetic

Floating-point numbers are fully supported in calculations:

```
Float result: {{ 5.5 + 2.3 }}
Mixed: {{ 10 + 3.14 }}
Division: {{ 22.0 / 7.0 }}
Precision: {{ 1.5 * 2.0 }}
```

**Output:**
```
Float result: 7.8
Mixed: 13.14
Division: 3.14286
Precision: 3.0
```

### Order of Operations and Parentheses

Mathematical precedence is respected, and parentheses can override it:

```
Order of operations: {{ 2 + 3 * 4 }}
With parentheses: {{ (2 + 3) * 4 }}
Complex: {{ ((1 + 2) * 3) + 4 }}
Mixed operations: {{ (10 / 2) + (3 * 4) }}
```

**Output:**
```
Order of operations: 14
With parentheses: 20
Complex: 13
Mixed operations: 17
```

### Type Casting

Convert between numeric types using `int()`:

```
{% set value 42.7 %}
Float value: {{ value }}
Integer value: {{ int(value) }}
Complex casting: {{ int((arg.a ?? 1.0) * 255) }}
```

**Output:**
```
Float value: 42.7
Integer value: 42
Complex casting: 255
```

## 4. String Operations

### String Concatenation

Use the `~` operator for string concatenation (different from arithmetic `+`):

```
{% set first "Hello" %}
{% set second "World" %}

{{ first ~ " " ~ second }}
{{ "Literal" ~ " " ~ "concatenation" }}
```

**Output:**
```
Hello World
Literal concatenation
```

**String Concatenation vs Addition:**
```
{% set str1 "Hello" %}
{% set str2 "World" %}

Concatenation: {{ str1 ~ str2 }}
Addition: {{ str1 + str2 }}
```

**Output:**
```
Concatenation: HelloWorld
Addition: HelloWorld
```

Both `~` and `+` work for string concatenation, but `~` is explicitly for strings while `+` also handles arithmetic. Use `~` when you want to be explicit about string concatenation.

**Complex Concatenation:**
```
{{ arg0 ~ " " ~ arg1 ~ " " ~ arg2 }}
{{ "Result: " ~ (5 + 3) ~ " items" }}
```

### String Literals

Strings can be defined with double quotes:

```
{{ "This is a string literal" }}
{{ "Strings can contain spaces and symbols!" }}
```

**Output:**
```
This is a string literal
Strings can contain spaces and symbols!
```

## 5. Null Coalescing

Use `??` to provide fallback values for undefined variables:

```
Default: {{ missing ?? "fallback value" }}
Found: {{ name ?? "no name" }}
```

With variable `name="Alice"` (and `missing` undefined):
```
Default: fallback value
Found: Alice
```

Complex null coalescing with expressions:

```
Complex: {{ (arg.a ?? 1.0) * 255 }}
```

## 6. Ternary Operator

Use the ternary operator `condition ? true_value : false_value` for conditional expressions:

```
{% set status "active" %}
{% set name "World" %}
{% set priority "" %}

Status check: {{ status ? "enabled" : "disabled" }}
Greeting: {{ name ? "Hello " ~ name : "Anonymous user" }}
Priority level: {{ priority ? priority : "normal" }}
```

**Output:**
```
Status check: enabled
Greeting: Hello World
Priority level: normal
```

### Ternary with Filters

Combine ternary operators with filters for powerful conditional transformations:

```
{% set name "world" %}
{% set status "active" %}
{% set missing "" %}

With filters on true branch: {{ name ? name|upper : "unknown" }}
With filters on false branch: {{ missing ? "found" : "not found"|upper }}
With filters on both branches: {{ status ? "active"|upper : "inactive"|lower }}
```

**Output:**
```
With filters on true branch: WORLD
With filters on false branch: NOT FOUND
With filters on both branches: ACTIVE
```

### Nested Ternary Expressions

Ternary operators can be nested for complex conditional logic:

```
{% set priority "high" %}
{% set level "medium" %}

Nested ternary: {{ priority ? priority|upper : level ? level|lower : "none" }}
```

**Output:**
```
Nested ternary: HIGH
```

## 7. Filters and Pipes

Apply transformations to values using the pipe operator `|`:

```
{% set name "hello world" %}
Uppercase: {{ name | upper }}
Lowercase: {{ name | lower }}
Chain filters: {{ "MIXED Case" | lower | upper }}
```

**Output:**
```
Uppercase: HELLO WORLD
Lowercase: hello world
Chain filters: MIXED CASE
```

Available filters:
- `upper` - Convert to uppercase
- `lower` - Convert to lowercase
- `escape` - Convert special characters to escaped quoted string
- `quote` - Wrap in quotes and escape internal quotes/backslashes
- `join` - Join list elements with a separator

### Escape Filter

The `escape` filter converts strings with special characters into quoted strings with proper escape sequences:

```
{% set message "Line 1
Line 2" %}
{% set tab_text "before	after" %}
{% set quote_text "She said \"hello\"" %}

Escaped newline: {{ message | escape }}
Escaped tab: {{ tab_text | escape }}
Escaped quotes: {{ quote_text | escape }}
```

**Output:**
```
Escaped newline: "Line 1\nLine 2"
Escaped tab: "before\tafter"
Escaped quotes: "She said \"hello\""
```

The escape filter handles:
- `\n` - Newline characters
- `\t` - Tab characters
- `\r` - Carriage return characters
- `\"` - Double quote characters
- `\\` - Backslash characters
- `\0` - Null characters

The output is always wrapped in double quotes, making it suitable for generating code or configuration files.

### Quote Filter

The `quote` filter wraps strings in double quotes and escapes internal quotes and backslashes:

```
{% set simple "test" %}
{% set with_quote "test\"test" %}
{% set with_backslash "test\\test" %}

Simple: {{ simple | quote }}
With quote: {{ with_quote | quote }}
With backslash: {{ with_backslash | quote }}
Literal: {{ "hello" | quote }}
```

**Output:**
```
Simple: "test"
With quote: "test\"test"
With backslash: "test\\test"
Literal: "hello"
```

### Join Filter

The `join` filter combines list elements into a single string with a specified separator:

```
{% set keys ["KEY_A", "KEY_B", "KEY_X"] %}
Combined: {{ keys | join(" | ") }}
Comma separated: {{ keys | join(", ") }}
No separator: {{ keys | join("") }}
```

**Output:**
```
Combined: KEY_A | KEY_B | KEY_X
Comma separated: KEY_A, KEY_B, KEY_X
No separator: KEY_AKEY_BKEY_X
```

**Filter Chaining:**

Filters can be chained and work with string literals, variables, or complex expressions:

```
{% set name "John" %}
{% set greeting "Hello" %}

Basic variable: {{ name | upper }}
Chained filters: {{ "MiXeD" | lower | upper }}
Expression with filter: {{ (greeting ~ " World") | lower }}
Multiple chains: {{ "test" | upper | lower | upper }}
```

**Output:**
```
Basic variable: JOHN
Chained filters: MIXED
Expression with filter: hello world
Multiple chains: TEST
```

## 8. Conditional Logic

### Basic Conditionals

Use `{% if %}` statements for conditional content:

```
{% if enabled %}
Feature is enabled!
{% endif %}

{% if disabled %}
This won't show
{% endif %}
```

With variable `enabled="true"` (and `disabled` undefined):
```
Feature is enabled!
```

### If-Elif-Else Chains

Complex conditional logic with multiple branches:

```
{% if var1 %}
Variable 1 is set
{% elif var2 %}
Variable 2 is set
{% else %}
No variables set
{% end %}
```

Variables are considered "truthy" if they exist and have a non-empty value.

### Comparison Operators

Use comparison operators to create more sophisticated conditions:

```
{% if status == "active" %}
User is active
{% endif %}

{% if count != 0 %}
Has items
{% endif %}

{% if priority > 5 %}
High priority
{% endif %}

{% if score >= 90 %}
Excellent score
{% endif %}

{% if temperature < 32 %}
Below freezing
{% endif %}

{% if age <= 18 %}
Minor
{% endif %}
```

Available comparison operators:
- `==` - Equal to
- `!=` - Not equal to
- `>` - Greater than
- `>=` - Greater than or equal to
- `<` - Less than
- `<=` - Less than or equal to

Comparisons work with both numbers and strings:

```
{% if version == "2.0" %}
Version 2.0
{% endif %}

{% if count > 10 %}
Many items
{% endif %}
```

Numeric comparisons are performed when both sides are numbers, otherwise string comparison is used.

### Logical Operators

Combine multiple conditions using logical operators:

#### AND Operator

Use `and` to require all conditions to be true:

```
{% set enabled "true" %}
{% set valid "true" %}
{% set status "active" %}

{% if enabled and valid %}
Both enabled and valid
{% endif %}

{% if enabled and valid and status %}
All three conditions are true
{% endif %}
```

**Output:**
```
Both enabled and valid

All three conditions are true
```

#### OR Operator

Use `or` when any condition being true is sufficient:

```
{% set admin "false" %}
{% set moderator "true" %}
{% set owner "" %}

{% if admin or moderator %}
User has privileges
{% endif %}

{% if admin or moderator or owner %}
User has some level of access
{% endif %}
```

**Output:**
```
User has privileges

User has some level of access
```

#### Combining AND and OR

Use parentheses to group logical operations:

```
{% set user_active "true" %}
{% set is_admin "false" %}
{% set is_moderator "true" %}
{% set has_permission "true" %}

{% if user_active and (is_admin or is_moderator) %}
Active user with elevated privileges
{% endif %}

{% if (is_admin or is_moderator) and has_permission %}
Privileged user with permissions
{% endif %}
```

**Output:**
```
Active user with elevated privileges

Privileged user with permissions
```

#### Complex Logical Expressions

Logical operators work with any expressions, including comparisons:

```
{% set score 85 %}
{% set bonus_points 10 %}
{% set is_member "true" %}

{% if (score > 80) and (bonus_points > 5) %}
High score with bonus
{% endif %}

{% if (score < 60) or (is_member and bonus_points > 0) %}
Either low score or member with bonus
{% endif %}
```

**Output:**
```
High score with bonus

Either low score or member with bonus
```

Logical operators follow standard precedence:
- `and` has higher precedence than `or`
- Use parentheses to override precedence when needed
- Both operators are left-associative (evaluated left to right)

### Comparison with Expressions

Comparison operators can be combined with arithmetic and other expressions:

```
{% if (count + 1) == 6 %}
Count plus one equals six
{% endif %}

{% if items.length > 0 %}
Has items
{% endif %}

{% if (value * 2) <= 100 %}
Doubled value is 100 or less
{% endif %}
```

### Conditional Syntax Variations

Both `{% endif %}` and `{% end %}` can close conditional blocks:

```
{% if condition %}
Content here
{% end %}

{% if another_condition %}
More content
{% endif %}
```

## 9. Loops

### Basic Loops

Repeat content a specific number of times:

```
{% loop 3 %}
Hello World!
{% end %}
```

**Output:**
```
Hello World!
Hello World!
Hello World!
```

### Variable-Driven Loops

Use variables to control loop count:

```
{% set iterations "5" %}
{% loop iterations %}
Iteration
{% end %}
```

### Foreach Loops

Iterate over namespaced variables:

```
{% set items.one "first" %}
{% set items.two "second" %}
{% set items.three "third" %}

{% foreach items %}
Key: {{ key }}, Value: {{ value }}
{% end %}
```

**Output:**
```
Key: one, Value: first
Key: two, Value: second
Key: three, Value: third
```

In `{% foreach %}` loops:
- `{{ key }}` contains the variable suffix (after the dot)
- `{{ value }}` contains the variable's value

### Nested Foreach

Handle multiple namespaced variable sets:

```
{% set users.alice "admin" %}
{% set users.bob "user" %}
{% set products.laptop "$999" %}
{% set products.mouse "$25" %}

Users:
{% foreach users %}
{{ key }}: {{ value }}
{% end %}

Products:
{% foreach products %}
{{ key }}: ${{ value }}
{% end %}
```

## 10. Lists

### Basic List Creation

Create ordered lists using square bracket syntax:

```
{% set fruits ["apple", "banana", "cherry"] %}
First fruit: {{ fruits.0 }}
Second fruit: {{ fruits.1 }}
Third fruit: {{ fruits.2 }}
```

**Output:**
```
First fruit: apple
Second fruit: banana
Third fruit: cherry
```

Lists are zero-indexed, so the first element is accessed with `.0`, second with `.1`, etc.

### Mixed Data Types in Lists

Lists can contain different types of values including variables, numbers, and strings:

```
{% set mixed [var0, 1, 2, "string"] %}
Index 0: {{ mixed.0 }}
Index 1: {{ mixed.1 }}
Index 2: {{ mixed.2 }}
Index 3: {{ mixed.3 }}
```

With variable `var0="default_value"`:
```
Index 0: default_value
Index 1: 1
Index 2: 2
Index 3: string
```

### Lists with Expressions

List elements can be complex expressions:

```
{% set numbers [1, 2, 3, 4, 5] %}
{% set expressions [1 + 2, 4 * 2, 10 / 2] %}

First number: {{ numbers.0 }}
Calculated result: {{ expressions.1 }}
```

**Output:**
```
First number: 1
Calculated result: 8
```

### Iterating Over Lists with Foreach

Lists work seamlessly with `{% foreach %}` loops:

```
{% set items ["first", "second", "third"] %}
{% foreach items %}
Item {{ key }}: {{ value }}
{% end %}
```

**Output:**
```
Item 0: first
Item 1: second
Item 2: third
```

In list iteration:
- `{{ key }}` contains the numeric index (0, 1, 2, ...)
- `{{ value }}` contains the list element value

### Empty Lists

Empty lists can be created and handled gracefully:

```
{% set empty_list [] %}
Before foreach
{% foreach empty_list %}
This will not appear
{% end %}
After foreach
```

**Output:**
```
Before foreach
After foreach
```

### Comprehensive List Example

Combining multiple list features:

```
{% set numbers [1, 2, 3, 4, 5] %}
{% set expressions [1 + 2, 4 * 2, 10 / 2] %}

Numbers:
{% foreach numbers %}
{{ key }}: {{ value }}
{% end %}

Expressions:
{% foreach expressions %}
{{ key }}: {{ value }}
{% end %}

Direct access: {{ numbers.0 }}, {{ expressions.1 }}
```

**Output:**
```
Numbers:
0: 1
1: 2
2: 3
3: 4
4: 5

Expressions:
0: 3
1: 8
2: 5

Direct access: 1, 8
```

## 11. Dictionaries and Objects

Create key-value structures using dictionary syntax:

```
{% set config { host: "localhost", port: 8080, name: "MyApp" } %}
Server: {{ config.host }}:{{ config.port }}
Application: {{ config.name }}
```

**Output:**
```
Server: localhost:8080
Application: MyApp
```

Dictionary values can be strings, numbers, or variables:

```
{% set debug true %}
{% set settings {
  environment: "development",
  debug_mode: debug,
  max_users: 100,
  version: 1.2
} %}

Environment: {{ settings.environment }}
Debug: {{ settings.debug_mode }}
Max users: {{ settings.max_users }}
```

## 12. List Operations

### Append List Statement

Add items to existing lists using `{% append_list %}`:

```
{% set keys [] %}
{% if arg.a %}{% append_list keys "KEY_A" %}{% endif %}
{% if arg.b %}{% append_list keys "KEY_B" %}{% endif %}
{% if arg.x %}{% append_list keys "KEY_X" %}{% endif %}

{% if keys.0 %}
Keys found: {{ keys | join(", ") }}
{% endif %}
```

With variables `arg.a=true`, `arg.b=false`, `arg.x=true`:
```
Keys found: KEY_A, KEY_X
```

The `append_list` statement dynamically adds elements to lists, making it useful for conditional list building.

### Append Unique Sub Statement

Add content to a variable only if it doesn't already exist using `{% append_unique_sub %}`:

```
{% set list "item1" %}
{% append_unique_sub list "item2" %}
{% append_unique_sub list "item1" %}
{% append_unique_sub list "item3" %}
List: {{ list }}
```

**Output:**
```
List: item1item2item3
```

The `append_unique_sub` statement checks if the content already exists in the variable before appending it, preventing duplicates. This is useful for building strings where repeated content should be avoided.

### List with Join Filter in Practice

Combining list operations with filters for real-world use cases:

```
{% set buttons [] %}
{% if show_save %}{% append_list buttons "SAVE" %}{% endif %}
{% if show_cancel %}{% append_list buttons "CANCEL" %}{% endif %}
{% if show_help %}{% append_list buttons "HELP" %}{% endif %}

{% if buttons.0 %}
if (userInput & ({{ buttons | join(" | ") }})) {
    handleButtonPress();
}
{% endif %}
```

## 13. Unique Line Processing

Remove duplicate lines from content blocks:

```
{% unique_line %}
line1
line2
line1
line3
line2
{% end %}
```

**Output:**
```
line1
line2
line3
```

This is useful for generating lists where duplicates should be eliminated.

## 14. Attachments

Load external content into variables using the attachment system:

```
Before attachment
{% attachment "test_attachment" content %}
{{ content }}
After attachment
```

The attachment identifier (`"test_attachment"`) is resolved by the application's attachment resolver, which loads the content into the specified variable (`content`).

## 15. Macros

The macro system allows you to define reusable template fragments with parameters. Macros help reduce duplication and create modular, maintainable templates.

### Basic Macro Definition

Define a macro using `{% macro %}` and `{% endmacro %}`:

```
{% macro banner() -%}
banner motd ^
===========================================
|   This device is property of BigCorpCo  |
|   Unauthorized access is unauthorized   |
|  Unless you're authorized to access it  |
|  In which case play nice and stay safe  |
===========================================
^
{% endmacro -%}

{{ banner() }}
```

**Output:**
```
banner motd ^
===========================================
|   This device is property of BigCorpCo  |
|   Unauthorized access is unauthorized   |
|  Unless you're authorized to access it  |
|  In which case play nice and stay safe  |
===========================================
^
```

### Macros with Parameters

Macros can accept parameters to make them more flexible:

```
{% macro def_if_desc(if_role) -%}
Unused port, dedicated to {{ if_role }} devices
{%- endmacro -%}

{{ def_if_desc("Home Computer") }}
{{ def_if_desc("Server") }}
```

**Output:**
```
Unused port, dedicated to Home Computer devices
Unused port, dedicated to Server devices
```

### Multiple Parameters

Macros support multiple parameters separated by commas:

```
{% macro user_info(username, role, department) -%}
User: {{ username }}
Role: {{ role }}
Department: {{ department }}
{%- endmacro -%}

{{ user_info("jdoe", "Senior Developer", "Engineering") }}
```

**Output:**
```
User: jdoe
Role: Senior Developer
Department: Engineering
```

### Macros with Logic

Macros can contain any template constructs including conditionals and expressions:

```
{% macro format_status(status, priority) -%}
{% if priority == "high" -%}
🔴 HIGH: {{ status }}
{%- elif priority == "medium" -%}
🟡 MEDIUM: {{ status }}
{%- else -%}
🟢 {{ status }}
{%- endif -%}
{%- endmacro -%}

{{ format_status("Server Down", "high") }}
{{ format_status("Maintenance", "medium") }}
{{ format_status("All Good", "low") }}
```

**Output:**
```
🔴 HIGH: Server Down
🟡 MEDIUM: Maintenance
🟢 All Good
```

### Nested Macro Calls

Macros can call other macros:

```
{% macro format_name(first, last) -%}
{{ first }} {{ last }}
{%- endmacro -%}

{% macro employee_badge(emp_id, first_name, last_name, dept) -%}
ID: {{ emp_id }}
Name: {{ format_name(first_name, last_name) }}
Department: {{ dept }}
{%- endmacro -%}

{{ employee_badge("E001", "John", "Doe", "IT") }}
```

**Output:**
```
ID: E001
Name: John Doe
Department: IT
```

### Network Configuration Example

```
{% macro vlan_config(vlan_id, vlan_name, subnet, gateway) -%}
vlan {{ vlan_id }}
 name {{ vlan_name }}
!
interface vlan{{ vlan_id }}
 ip address {{ gateway }} {{ subnet }}
 no shutdown
{%- endmacro -%}

{{ vlan_config("100", "USERS", "255.255.255.0", "192.168.100.1") }}
{{ vlan_config("200", "SERVERS", "255.255.255.0", "192.168.200.1") }}
```

**Output:**
```
vlan 100
 name USERS
!
interface vlan100
 ip address 192.168.100.1 255.255.255.0
 no shutdown
vlan 200
 name SERVERS
!
interface vlan200
 ip address 192.168.200.1 255.255.255.0
 no shutdown
```

### Whitespace Control

Use `{%-` and `-%}` to control whitespace in macro output:

```
{% macro compact_list(item1, item2, item3) -%}
{{ item1 }}, {{ item2 }}, {{ item3 }}
{%- endmacro -%}

Items: {{ compact_list("apple", "banana", "cherry") }}
```

**Output:**
```
Items: apple, banana, cherry
```

### Macro Best Practices

1. **Use descriptive names**: `create_user_card()` instead of `card()`
2. **Keep macros focused**: One responsibility per macro
3. **Document parameters**: Use clear parameter names
4. **Handle edge cases**: Check for empty or missing parameters
5. **Use whitespace control**: Manage output formatting with `{%-` and `-%}`

## 16. Advanced Expression Examples

### Complex Expressions

Combine multiple features in sophisticated expressions:

```
Basic parentheses: {{ (2 + 3) * 4 }}
Nested parentheses: {{ ((1 + 2) * 3) + 4 }}
Multiple parentheses levels: {{ ((10 + 5) * 2) + ((8 - 3) * 4) }}
Complex null coalescing: {{ (missing.value ?? 2.5) * (factor ?? 10) }}
Type casting: {{ int((arg.a ?? 1.0) * 255) }}
Mixed operators with casting: {{ int((value ?? 3.14) * 100 + (offset ?? 0)) }}
Deeply nested: {{ (((a ?? 1) + (b ?? 2)) * ((c ?? 3) + (d ?? 4))) / 2 }}
Division with parentheses: {{ (numerator ?? 100) / (denominator ?? 4) }}
Null coalescing with zero: {{ (zero_value ?? 42) + 10 }}
```

**Output (with sample variables):**
```
Basic parentheses: 20
Nested parentheses: 13
Multiple parentheses levels: 50
Complex null coalescing: 25.0
Type casting: 255
Mixed operators with casting: 314
Deeply nested: 12
Division with parentheses: 25
Null coalescing with zero: 52
```

### String and Arithmetic Mixing

Combine string concatenation with arithmetic:

```
{% set a "10" %}
{% set b "3" %}

String concat: {{ "Value: " ~ (a + b) }}
Mixed operations: {{ "Result: " ~ ((a * 2) + b) ~ " units" }}
```

## 17. Error Handling and Edge Cases

### Empty Templates

Empty templates produce empty output:

```
(empty file)
```

**Output:**
```
(empty output)
```

### Undefined Variables

Undefined variables in expressions evaluate to empty strings or zero in arithmetic contexts:

```
Undefined in text: {{ undefined_var }}
Undefined in arithmetic: {{ undefined_var + 5 }}
With null coalescing: {{ undefined_var ?? "default" }}
```

**Output:**
```
Undefined in text:
Undefined in arithmetic: 5
With null coalescing: default
```

### Conditional Edge Cases

Variables are considered false if:
- They are undefined
- They are empty strings
- They contain only whitespace

```
{% if "" %}
Empty string is false
{% endif %}

{% if "any_value" %}
Non-empty string is true
{% endif %}
```

## 18. Best Practices

### Variable Naming

- Use descriptive names: `config.database.host` instead of `h`
- Use dots for hierarchical organization: `user.profile.name`
- Keep names readable: `max_items` instead of `mi`

### Template Organization

- Use comments to document complex logic
- Break complex expressions into multiple variables
- Group related variable assignments

### Performance Considerations

- Minimize deep nesting in expressions
- Use null coalescing for optional variables
- Prefer simple conditionals over complex boolean logic
- Use ternary operators for simple conditional values

### Example: Well-Structured Template

```
{# Configuration template for web server #}
{% set config.server.host "0.0.0.0" %}
{% set config.server.port "8080" %}
{% set config.database.enabled "true" %}
{% set config.database.host "localhost" %}
{% set config.database.port "5432" %}

# Server Configuration
Host: {{ config.server.host }}
Port: {{ config.server.port }}

{% if config.database.enabled %}
# Database Configuration
Database Host: {{ config.database.host }}
Database Port: {{ config.database.port }}
Connection String: {{ config.database.host ~ ":" ~ config.database.port }}
{% endif %}

{# Generate additional config based on environment #}
{% if env ?? "development" %}
Debug Mode: Enabled
Log Level: Debug
{% else %}
Debug Mode: Disabled
Log Level: Info
{% endif %}
```