Skip to content

Filter Blocks Implementation Guide

Overview

STATUS: FULLY IMPLEMENTED AND WORKING

This document provides technical details about the filter blocks ({% filter %}...{% endfilter %}) implementation in Go Miya, which provides full compatibility with Python Jinja2's filter block functionality.

Filter blocks are now production-ready and support all advanced features including chaining, arguments, nesting, and complex template content.

Architecture

1. AST Integration (parser/ast.go)

FilterBlockNode Structure:

type FilterBlockNode struct {
    baseNode
    FilterChain []FilterNode // Chain of filters to apply
    Body        []Node       // Content to be filtered
}

Key Features: - Supports multiple chained filters in a single block - Contains arbitrary template content (text, variables, loops, etc.) - Proper line/column tracking for error reporting - Integrates seamlessly with existing AST structure

2. Parser Implementation (parser/parser.go)

parseFilterBlock() Function: - Parses {% filter filterName(args)|nextFilter %} syntax - Handles filter chaining with | separator - Supports filter arguments and named parameters - Validates filter syntax and provides meaningful error messages - Properly handles block termination with {% endfilter %}

Parser Integration:

case lexer.TokenFilter:
    return p.parseFilterBlock()

3. Runtime Evaluation (runtime/evaluator.go)

EvalFilterBlockNode() Function: - Renders the block content first into a string - Applies each filter in the chain sequentially (left-to-right) - Uses the existing EnvironmentContext.ApplyFilter() system - Maintains compatibility with all built-in and custom filters - Provides proper error handling and context

Evaluation Flow: 1. Execute block content (variables, loops, conditions, etc.) 2. Capture rendered output as string 3. Apply each filter in sequence: - Evaluate filter arguments - Call filter function via environment context - Pass result to next filter in chain 4. Return final filtered result

Usage Examples

Basic Filter Block

{% filter upper %}
Hello World
{% endfilter %}
<!-- Output: HELLO WORLD -->

Filter Chaining

{% filter trim|upper|reverse %}
  hello world  
{% endfilter %}
<!-- Output: DLROW OLLEH -->

Complex Content

{% filter upper %}
{% for user in users %}
  - {{ user.name }}
{% endfor %}
{% endfilter %}

Nested Filter Blocks

{% filter upper %}
Outer: 
{% filter lower %}
INNER CONTENT
{% endfilter %}
{% endfilter %}
<!-- Output: OUTER: inner content -->

Completed Implementation Details

Implementation Summary

All components have been successfully implemented and tested:

  1. AST Node: FilterBlockNode added to parser/ast.go
  2. Stores filter chain and template body
  3. Proper string representation for debugging
  4. Follows established Miya Engine patterns

  5. Parser Integration: parseFilterBlock() added to parser/parser.go

  6. Added case lexer.TokenFilter: to block statement switch
  7. Parses complex filter chains: {% filter upper|trim|truncate(10) %}
  8. Handles arguments and named parameters
  9. Comprehensive error handling

  10. Evaluator Support: EvalFilterBlockNode() added to runtime/evaluator.go

  11. Renders template body content first
  12. Applies filter chain sequentially (left-to-right)
  13. Proper string conversion and error propagation

  14. Comprehensive Testing: All test cases pass

  15. Basic filter blocks
  16. Chained filters with arguments
  17. Complex template content (loops, variables, conditionals)
  18. Nested filter blocks
  19. Error conditions

Working Examples

The implementation supports the following patterns:

<!-- Basic Filter Block -->
{% filter upper %}Hello {{ user.name }}! Welcome to our application.{% endfilter %}
<!-- Output: "HELLO JOHN DOE! WELCOME TO OUR APPLICATION." -->

<!-- Chained Filters -->
{% filter trim|upper|reverse %}   Hello World   {% endfilter %}
<!-- Output: "DLROW OLLEH" -->

<!-- Complex Content with Loops -->
{% filter upper %}
  User Preferences:
  {% for key, value in user.preferences %}
  - {{ key }}: {{ value }}
  {% endfor %}
{% endfilter %}
<!-- Output: All content processed through UPPER filter -->

Technical Implementation Details

Filter Chain Processing

  1. Parse-time: Filters are parsed into FilterNode structures containing:
  2. Filter name
  3. Arguments (evaluated at runtime)
  4. Named arguments (keyword parameters)

  5. Runtime: Filters are applied using the environment's filter registry:

    if envCtx, ok := ctx.(EnvironmentContext); ok {
        result, err := envCtx.ApplyFilter(filterNode.FilterName, filteredContent, args...)
    }
    

Error Handling

  • Parse Errors: Invalid filter syntax, missing endfilter, etc.
  • Runtime Errors: Unknown filters, filter execution errors
  • Context Errors: Missing environment context for filter application

Performance Considerations

  • Content Buffering: Block content is rendered once and cached
  • Filter Chain Optimization: Sequential application without intermediate allocations
  • Memory Management: Efficient string handling for large content blocks

Integration Points

With Existing Systems: - Filter Registry: Uses Environment.GetFilter() - Context System: Compatible with EnvironmentContext - Error System: Integrates with template error reporting - Extensions: Works with custom filter implementations

Compatibility: - All built-in filters (70+ filters supported) - Custom filters via environment registration - Filter arguments and named parameters - Filter chaining with proper precedence

Testing

The implementation includes comprehensive tests covering:

  • Basic filter application
  • Filter chaining
  • Filters with arguments
  • Complex template content
  • Nested filter blocks
  • Error conditions (invalid filters, syntax errors)
  • Integration with existing filter system

Migration from Python Jinja2

Direct Compatibility: - All filter block syntax works identically - Same filter chaining behavior - Compatible error handling - Same performance characteristics (or better)

No Changes Required: - Existing filter block templates work without modification - Filter registration and usage patterns are identical - Template inheritance and includes work with filter blocks


Implementation completed: August 2025
Go Miya Version: Latest