Skip to content

Instantly share code, notes, and snippets.

@yetanotherchris
Last active June 15, 2025 18:48
Show Gist options
  • Save yetanotherchris/c80d0fadb5a2ee5b4beb0a4384020dbf to your computer and use it in GitHub Desktop.
Save yetanotherchris/c80d0fadb5a2ee5b4beb0a4384020dbf to your computer and use it in GitHub Desktop.

Revisions

  1. yetanotherchris revised this gist Jun 15, 2025. No changes.
  2. yetanotherchris revised this gist Jun 15, 2025. 1 changed file with 46 additions and 0 deletions.
    46 changes: 46 additions & 0 deletions antlr-performance.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,46 @@
    _What are some ways to increase the performance of Antlr_

    Here are several effective ways to improve ANTLR performance:

    ## Parser Optimization

    **Use the SLL prediction mode first** - Set your parser to use `PredictionMode.SLL` initially, which is faster than the default LL mode. Fall back to LL mode only when SLL fails:
    ```java
    parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
    ```

    **Eliminate left recursion** - Direct and indirect left recursion can significantly slow parsing. Restructure your grammar rules to use right recursion or iterative patterns instead.

    **Minimize backtracking** - Reduce ambiguous grammar constructs that force the parser to backtrack. Use semantic predicates `{...}?` to guide parsing decisions when needed.

    ## Grammar Design

    **Optimize rule ordering** - Place more common alternatives first in your grammar rules, as ANTLR tries them in order.

    **Use lexer modes** - For complex tokenization scenarios, lexer modes can be more efficient than complex lexer rules with many alternatives.

    **Simplify complex rules** - Break down overly complex rules into smaller, more focused ones. This can improve both performance and maintainability.

    ## Memory and Caching

    **Reuse parser instances** - Creating new parser instances is expensive. Reuse them when possible, just reset the input stream.

    **Tune memory settings** - Increase JVM heap size if you're processing large files. ANTLR can be memory-intensive for complex grammars.

    **Use parse tree caching** - If parsing the same input multiple times, consider caching parse trees.

    ## Lexer Optimization

    **Order lexer rules carefully** - Put more specific tokens before general ones, and commonly used tokens first.

    **Avoid expensive lexer predicates** - Semantic predicates in the lexer can be costly since they're evaluated frequently.

    ## Advanced Techniques

    **Use visitor pattern over listener** - Visitors are generally faster than listeners for tree traversal since they don't use the call stack as heavily.

    **Profile your grammar** - Use ANTLR's profiling tools to identify bottlenecks in your specific grammar.

    **Consider two-pass parsing** - For very large files, sometimes a lightweight first pass to identify structure followed by detailed parsing can be more efficient.

    The most impactful optimizations are usually grammar restructuring to reduce ambiguity and using SLL prediction mode, so start with those approaches.
  3. yetanotherchris revised this gist Jun 12, 2025. 1 changed file with 214 additions and 0 deletions.
    214 changes: 214 additions & 0 deletions go-templates.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,214 @@
    # Go Text Template Directives - Implementation Specification for C#

    ## Overview
    This specification defines the behavior of `define`, `template`, and `block` directives from Go's text/template package for implementation in C#.

    ## Core Concepts

    ### Template Registry
    - Maintain a dictionary/map of template names to compiled template objects
    - Templates can be defined at parse time or runtime
    - Template lookup is case-sensitive
    - Nested template definitions are allowed

    ### Context Management
    - Each template execution has a data context (equivalent to Go's "dot" `.`)
    - Context can be passed explicitly to template invocations
    - Default context is the current execution context

    ## 1. `define` Directive

    ### Syntax
    ```
    {{define "templateName"}}content{{end}}
    ```

    ### Behavior
    - Registers a named template in the template registry
    - Does NOT execute the template immediately
    - Template content is parsed and compiled for later use
    - Can be defined anywhere in the template (top-level or nested)
    - Multiple definitions with the same name: last definition wins

    ### Implementation Requirements
    ```csharp
    // Pseudo-interface for implementation
    interface ITemplateDirective
    {
    void ParseDefine(string templateName, string templateContent);
    void RegisterTemplate(string name, CompiledTemplate template);
    }
    ```

    ### Example Processing
    Input: `{{define "header"}}<h1>{{.Title}}</h1>{{end}}`
    - Extract name: "header"
    - Extract content: `<h1>{{.Title}}</h1>`
    - Compile content as separate template
    - Register in template registry with key "header"

    ## 2. `template` Directive

    ### Syntax
    ```
    {{template "templateName"}}
    {{template "templateName" pipeline}}
    ```

    ### Behavior
    - Executes a previously defined template by name
    - If no pipeline provided, uses current context (`.`)
    - If pipeline provided, evaluates pipeline and uses result as context
    - Throws error if template name not found
    - Output is inserted at the current position

    ### Implementation Requirements
    ```csharp
    // Pseudo-interface for implementation
    interface ITemplateExecution
    {
    string ExecuteTemplate(string templateName, object context = null);
    bool TemplateExists(string templateName);
    }
    ```

    ### Context Handling
    - `{{template "name"}}` → Execute with current context
    - `{{template "name" .User}}` → Execute with `.User` as context
    - `{{template "name" "literal"}}` → Execute with string literal as context
    - `{{template "name" pipeline}}` → Execute with pipeline result as context

    ### Error Conditions
    - Template not found → Runtime error
    - Template execution error → Propagate error up

    ## 3. `block` Directive

    ### Syntax
    ```
    {{block "templateName" pipeline}}default content{{end}}
    ```

    ### Behavior
    - Combination of `define` + `template`
    - Defines a template with the given name and content
    - Immediately executes the template with the provided pipeline
    - If template with same name already exists, uses existing template instead of default content
    - Enables template inheritance/override pattern

    ### Implementation Requirements
    ```csharp
    // Pseudo-interface for implementation
    interface IBlockDirective
    {
    string ProcessBlock(string templateName, object context, string defaultContent);
    }
    ```

    ### Processing Logic
    ```csharp
    // Pseudo-code for block processing
    string ProcessBlock(string name, object context, string defaultContent)
    {
    if (TemplateRegistry.ContainsKey(name))
    {
    // Use existing template (override case)
    return ExecuteTemplate(name, context);
    }
    else
    {
    // Define and execute default template
    var compiledDefault = CompileTemplate(defaultContent);
    TemplateRegistry[name] = compiledDefault;
    return ExecuteTemplate(name, context);
    }
    }
    ```

    ## Implementation Details

    ### Template Compilation
    - Templates should be compiled to an intermediate representation
    - Support nested template calls
    - Handle variable scoping correctly
    - Preserve line numbers for error reporting

    ### Error Handling
    ```csharp
    public class TemplateError : Exception
    {
    public string TemplateName { get; set; }
    public int LineNumber { get; set; }
    public string DirectiveType { get; set; } // "template", "define", "block"
    }
    ```

    ### Thread Safety
    - Template registry should be thread-safe for concurrent access
    - Template execution should be thread-safe
    - Consider using ConcurrentDictionary for template storage

    ### Memory Management
    - Compiled templates should be cached efficiently
    - Consider template cleanup/eviction strategies for long-running applications

    ## Usage Patterns

    ### Basic Template Definition and Usage
    ```go
    // Go template equivalent
    {{define "greeting"}}Hello, {{.Name}}!{{end}}
    {{template "greeting" .User}}
    ```

    ### Template Inheritance with Blocks
    ```go
    // Base template
    {{block "title" .}}Default Title{{end}}
    {{block "content" .}}Default content{{end}}

    // Child template (parsed later)
    {{define "title"}}Custom Title: {{.PageTitle}}{{end}}
    {{define "content"}}Custom content: {{.Body}}{{end}}
    ```

    ### Expected C# API Usage
    ```csharp
    var engine = new GoTemplateEngine();

    // Parse template with definitions
    engine.ParseTemplate("base", baseTemplateContent);
    engine.ParseTemplate("child", childTemplateContent);

    // Execute with data
    var result = engine.ExecuteTemplate("base", new {
    PageTitle = "My Page",
    Body = "Content here"
    });
    ```

    ## Test Cases

    ### Define Directive
    - Define template and verify it's registered
    - Define template with same name twice (last wins)
    - Define nested templates
    - Define template with complex content including other directives

    ### Template Directive
    - Execute existing template with current context
    - Execute existing template with explicit context
    - Execute non-existent template (should error)
    - Execute template that calls other templates

    ### Block Directive
    - Block with no existing template (uses default)
    - Block with existing template (uses existing, ignores default)
    - Block with complex pipeline context
    - Nested blocks

    ### Integration Tests
    - Template inheritance scenarios
    - Circular template references (should error)
    - Deep nesting of template calls
    - Performance with large numbers of templates
  4. yetanotherchris revised this gist Jun 12, 2025. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions sprintf-implementation.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    _What are all the format options for sprintf
    _What are all the format options for sprintf_

    Could you provide this in the form of a prompt (with all the same information you just produced) that OpenAI Codex could implement as a class, and with test cases it can use for unit tests_
    _Could you provide this in the form of a prompt (with all the same information you just produced) that OpenAI Codex could implement as a class, and with test cases it can use for unit tests_

    # C# sprintf Implementation Prompt for OpenAI Codex

  5. yetanotherchris revised this gist Jun 12, 2025. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion sprintf-implementation.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,6 @@
    _Could you provide this in the form of a prompt (with all the same information you just produced) that OpenAI Codex could implement as a class, and with test cases it can use for unit tests_
    _What are all the format options for sprintf

    Could you provide this in the form of a prompt (with all the same information you just produced) that OpenAI Codex could implement as a class, and with test cases it can use for unit tests_

    # C# sprintf Implementation Prompt for OpenAI Codex

  6. yetanotherchris revised this gist Jun 12, 2025. 2 changed files with 3 additions and 1 deletion.
    2 changes: 2 additions & 0 deletions pipeline-functions.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    _What is a comprehensive list of built in functions_

    Go text templates support pipelines and chaining of actions, which are powerful features that allow you to process data through a series of transformations in a readable, left-to-right manner.

    ## Pipelines
    2 changes: 1 addition & 1 deletion sprintf-implementation.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    Could you provide this in the form of a prompt (with all the same information you just produced) that OpenAI Codex could implement as a class, and with test cases it can use for unit tests
    _Could you provide this in the form of a prompt (with all the same information you just produced) that OpenAI Codex could implement as a class, and with test cases it can use for unit tests_

    # C# sprintf Implementation Prompt for OpenAI Codex

  7. yetanotherchris revised this gist Jun 12, 2025. 1 changed file with 245 additions and 8 deletions.
    253 changes: 245 additions & 8 deletions sprintf-implementation.md
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,247 @@
    The prompt now includes comprehensive C# equivalents for each sprintf format specifier, providing OpenAI Codex with clear guidance on how to implement each format using native C# formatting capabilities. This includes:
    Could you provide this in the form of a prompt (with all the same information you just produced) that OpenAI Codex could implement as a class, and with test cases it can use for unit tests

    1. **Direct C# equivalents** for each sprintf format specifier
    2. **Multiple C# approaches** (string.Format, ToString, string interpolation)
    3. **Specific guidance** on handling special cases like octal formatting
    4. **Width and precision mapping** to C# formatting syntax
    5. **Flag implementation guidance** with C# equivalents
    6. **Reference table** showing exact C# syntax to use for each sprintf format
    # C# sprintf Implementation Prompt for OpenAI Codex

    This enhanced prompt gives Codex all the information needed to create a robust sprintf implementation that leverages C#'s built-in formatting capabilities while maintaining sprintf compatibility.
    Create a C# class called `SprintfFormatter` that implements C-style sprintf formatting functionality. The class should provide a static method `Format(string format, params object[] args)` that mimics the behavior of C's sprintf function.

    ## Required Format Specifiers to Implement

    ### Basic Integer Formats
    - `%d`, `%i` - signed decimal integer
    - C# equivalent: `{0}` or `{0:D}` or `.ToString()` or `.ToString("D")`
    - `%u` - unsigned decimal integer
    - C# equivalent: `{0}` or `{0:D}` or `.ToString()` or `.ToString("D")`
    - `%o` - unsigned octal integer
    - C# equivalent: No direct equivalent, use `Convert.ToString(value, 8)`
    - `%x` - unsigned hexadecimal (lowercase a-f)
    - C# equivalent: `{0:x}` or `.ToString("x")`
    - `%X` - unsigned hexadecimal (uppercase A-F)
    - C# equivalent: `{0:X}` or `.ToString("X")`

    ### Floating-Point Formats
    - `%f`, `%F` - decimal floating point
    - C# equivalent: `{0:F}` or `.ToString("F")`
    - `%e` - scientific notation (lowercase e)
    - C# equivalent: `{0:e}` or `.ToString("e")`
    - `%E` - scientific notation (uppercase E)
    - C# equivalent: `{0:E}` or `.ToString("E")`
    - `%g` - shortest of %f or %e
    - C# equivalent: `{0:G}` or `.ToString("G")`
    - `%G` - shortest of %F or %E
    - C# equivalent: `{0:G}` or `.ToString("G")`

    ### Character and String Formats
    - `%c` - single character
    - C# equivalent: `{0}` or `.ToString()`
    - `%s` - string of characters
    - C# equivalent: `{0}` or `.ToString()`
    - `%%` - literal percent sign
    - C# equivalent: `{{` or `}}` in string.Format, or literal `%` in interpolation

    ### Pointer Format
    - `%p` - pointer address (format as hexadecimal with 0x prefix)
    - C# equivalent: No direct equivalent, use custom formatting with IntPtr

    ## Width and Precision Modifiers
    - `%10d` - minimum width of 10 characters (right-aligned)
    - C# equivalent: `{0,10}` or `.ToString().PadLeft(10)`
    - `%-10d` - left-aligned in 10-character field
    - C# equivalent: `{0,-10}` or `.ToString().PadRight(10)`
    - `%010d` - zero-padded to 10 characters
    - C# equivalent: `{0:D10}` or `.ToString("D10")`
    - `%.2f` - 2 decimal places for floating point
    - C# equivalent: `{0:F2}` or `.ToString("F2")`
    - `%10.2f` - 10 characters wide, 2 decimal places
    - C# equivalent: `{0,10:F2}` or `.ToString("F2").PadLeft(10)`
    - `%-10.2f` - left-aligned, 10 characters wide, 2 decimal places
    - C# equivalent: `{0,-10:F2}` or `.ToString("F2").PadRight(10)`

    ## Flags to Support
    - `-` - left-justify
    - C# equivalent: Use negative width in string.Format `{0,-10}` or `.PadRight()`
    - `+` - always show sign for numbers
    - C# equivalent: Custom formatting with conditional logic, or use `ToString("+#;-#;0")`
    - ` ` (space) - space for positive numbers
    - C# equivalent: Custom formatting with conditional logic
    - `#` - alternate form (0x for hex, 0 for octal)
    - C# equivalent: Custom formatting, no direct equivalent
    - `0` - zero-pad numbers
    - C# equivalent: Use format specifiers like `D10` for integers or width padding

    ## Length Modifiers (Optional but Recommended)
    - `%ld` - long integer
    - C# equivalent: `{0}` or `.ToString()` (long is handled automatically in C#)
    - `%hd` - short integer
    - C# equivalent: `{0}` or `.ToString()` (short is handled automatically in C#)

    ## Implementation Requirements

    1. Create a `SprintfFormatter` class with a static `Format` method
    2. Parse the format string to identify format specifiers
    3. Handle all the format types listed above
    4. Support width, precision, and flag modifiers
    5. Throw appropriate exceptions for invalid format strings or argument mismatches
    6. Handle edge cases like null arguments, overflow conditions, etc.

    ## Example Usage
    ```csharp
    string result1 = SprintfFormatter.Format("%d", 123); // "123"
    string result2 = SprintfFormatter.Format("%.2f", 3.14159); // "3.14"
    string result3 = SprintfFormatter.Format("%10s", "Hello"); // " Hello"
    string result4 = SprintfFormatter.Format("%-10d", 42); // "42 "
    string result5 = SprintfFormatter.Format("%#x", 255); // "0xff"
    string result6 = SprintfFormatter.Format("%+d", 42); // "+42"
    ```

    ## Unit Test Cases to Implement

    Create comprehensive unit tests covering all format specifiers and edge cases:

    ### Basic Integer Tests
    ```csharp
    [Test] public void TestBasicInteger() {
    Assert.AreEqual("123", SprintfFormatter.Format("%d", 123));
    Assert.AreEqual("123", SprintfFormatter.Format("%i", 123));
    Assert.AreEqual("123", SprintfFormatter.Format("%u", 123u));
    Assert.AreEqual("-123", SprintfFormatter.Format("%d", -123));
    }
    ```

    ### Hexadecimal Tests
    ```csharp
    [Test] public void TestHexadecimal() {
    Assert.AreEqual("ff", SprintfFormatter.Format("%x", 255));
    Assert.AreEqual("FF", SprintfFormatter.Format("%X", 255));
    Assert.AreEqual("0xff", SprintfFormatter.Format("%#x", 255));
    Assert.AreEqual("0XFF", SprintfFormatter.Format("%#X", 255));
    }
    ```

    ### Octal Tests
    ```csharp
    [Test] public void TestOctal() {
    Assert.AreEqual("377", SprintfFormatter.Format("%o", 255));
    Assert.AreEqual("0377", SprintfFormatter.Format("%#o", 255));
    }
    ```

    ### Floating Point Tests
    ```csharp
    [Test] public void TestFloatingPoint() {
    Assert.AreEqual("3.140000", SprintfFormatter.Format("%f", 3.14));
    Assert.AreEqual("3.14", SprintfFormatter.Format("%.2f", 3.14));
    Assert.AreEqual("3.1e+00", SprintfFormatter.Format("%.1e", 3.1));
    Assert.AreEqual("3.1E+00", SprintfFormatter.Format("%.1E", 3.1));
    Assert.AreEqual("3.14", SprintfFormatter.Format("%g", 3.14));
    Assert.AreEqual("3.14", SprintfFormatter.Format("%G", 3.14));
    }
    ```

    ### Width and Alignment Tests
    ```csharp
    [Test] public void TestWidthAndAlignment() {
    Assert.AreEqual(" 123", SprintfFormatter.Format("%6d", 123));
    Assert.AreEqual("123 ", SprintfFormatter.Format("%-6d", 123));
    Assert.AreEqual("000123", SprintfFormatter.Format("%06d", 123));
    Assert.AreEqual(" 3.14", SprintfFormatter.Format("%6.2f", 3.14));
    Assert.AreEqual("3.14 ", SprintfFormatter.Format("%-6.2f", 3.14));
    }
    ```

    ### Character and String Tests
    ```csharp
    [Test] public void TestCharacterAndString() {
    Assert.AreEqual("A", SprintfFormatter.Format("%c", 'A'));
    Assert.AreEqual("A", SprintfFormatter.Format("%c", 65));
    Assert.AreEqual("Hello", SprintfFormatter.Format("%s", "Hello"));
    Assert.AreEqual(" Hello", SprintfFormatter.Format("%10s", "Hello"));
    Assert.AreEqual("Hello ", SprintfFormatter.Format("%-10s", "Hello"));
    }
    ```

    ### Sign and Space Tests
    ```csharp
    [Test] public void TestSignsAndSpaces() {
    Assert.AreEqual("+123", SprintfFormatter.Format("%+d", 123));
    Assert.AreEqual("-123", SprintfFormatter.Format("%+d", -123));
    Assert.AreEqual(" 123", SprintfFormatter.Format("% d", 123));
    Assert.AreEqual("-123", SprintfFormatter.Format("% d", -123));
    }
    ```

    ### Special Cases Tests
    ```csharp
    [Test] public void TestSpecialCases() {
    Assert.AreEqual("%", SprintfFormatter.Format("%%"));
    Assert.AreEqual("0", SprintfFormatter.Format("%d", 0));
    Assert.AreEqual("0.000000", SprintfFormatter.Format("%f", 0.0));
    }
    ```

    ### Multiple Arguments Tests
    ```csharp
    [Test] public void TestMultipleArguments() {
    Assert.AreEqual("Hello 123 3.14", SprintfFormatter.Format("%s %d %.2f", "Hello", 123, 3.14159));
    Assert.AreEqual("Value: 42, Hex: 2a", SprintfFormatter.Format("Value: %d, Hex: %x", 42, 42));
    }
    ```

    ### Error Cases Tests
    ```csharp
    [Test] public void TestErrorCases() {
    Assert.Throws<ArgumentException>(() => SprintfFormatter.Format("%d")); // Missing argument
    Assert.Throws<ArgumentException>(() => SprintfFormatter.Format("%d", "not a number")); // Wrong type
    Assert.Throws<FormatException>(() => SprintfFormatter.Format("%q", 123)); // Invalid format
    }
    ```

    ### Pointer Tests (if implementing %p)
    ```csharp
    [Test] public void TestPointer() {
    IntPtr ptr = new IntPtr(0x12345678);
    string result = SprintfFormatter.Format("%p", ptr);
    Assert.IsTrue(result.StartsWith("0x"));
    Assert.IsTrue(result.Contains("12345678"));
    }
    ```

    ## Implementation Notes

    1. Use regular expressions or state machine parsing to identify format specifiers
    2. Handle type conversion carefully - integers should work with various numeric types
    3. For floating point formats, pay attention to precision and scientific notation thresholds
    4. Consider thread safety if needed
    5. Provide clear error messages for invalid formats or argument mismatches
    6. Handle null arguments gracefully
    7. Consider performance optimization for frequently used format patterns

    ## C# Format Reference for Implementation

    When implementing each sprintf format, use these C# equivalents as the underlying mechanism:

    | sprintf Format | C# string.Format | C# ToString() | C# Interpolation |
    |---------------|------------------|---------------|------------------|
    | `%d`, `%i` | `{0}` or `{0:D}` | `.ToString()` or `.ToString("D")` | `$"{value}"` |
    | `%u` | `{0}` or `{0:D}` | `.ToString()` or `.ToString("D")` | `$"{value}"` |
    | `%o` | Custom logic | `Convert.ToString(value, 8)` | `$"{Convert.ToString(value, 8)}"` |
    | `%x` | `{0:x}` | `.ToString("x")` | `$"{value:x}"` |
    | `%X` | `{0:X}` | `.ToString("X")` | `$"{value:X}"` |
    | `%f`, `%F` | `{0:F}` | `.ToString("F")` | `$"{value:F}"` |
    | `%e` | `{0:e}` | `.ToString("e")` | `$"{value:e}"` |
    | `%E` | `{0:E}` | `.ToString("E")` | `$"{value:E}"` |
    | `%g` | `{0:G}` | `.ToString("G")` | `$"{value:G}"` |
    | `%G` | `{0:G}` | `.ToString("G")` | `$"{value:G}"` |
    | `%c` | `{0}` | `.ToString()` | `$"{value}"` |
    | `%s` | `{0}` | `.ToString()` | `$"{value}"` |
    | `%10d` | `{0,10}` | `.ToString().PadLeft(10)` | `$"{value,10}"` |
    | `%-10d` | `{0,-10}` | `.ToString().PadRight(10)` | `$"{value,-10}"` |
    | `%010d` | `{0:D10}` | `.ToString("D10")` | `$"{value:D10}"` |
    | `%.2f` | `{0:F2}` | `.ToString("F2")` | `$"{value:F2}"` |

    ## Bonus Features (Optional)
    - Support for positional arguments like `%2$d` (argument 2)
    - Support for `*` width and precision specifiers from arguments
    - Additional length modifiers (`ll`, `h`, `hh`)
    - Better error reporting with position information

    The implementation should be robust, well-tested, and handle edge cases appropriately while maintaining compatibility with standard C sprintf behavior.
  8. yetanotherchris revised this gist Jun 12, 2025. 1 changed file with 10 additions and 0 deletions.
    10 changes: 10 additions & 0 deletions sprintf-implementation.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    The prompt now includes comprehensive C# equivalents for each sprintf format specifier, providing OpenAI Codex with clear guidance on how to implement each format using native C# formatting capabilities. This includes:

    1. **Direct C# equivalents** for each sprintf format specifier
    2. **Multiple C# approaches** (string.Format, ToString, string interpolation)
    3. **Specific guidance** on handling special cases like octal formatting
    4. **Width and precision mapping** to C# formatting syntax
    5. **Flag implementation guidance** with C# equivalents
    6. **Reference table** showing exact C# syntax to use for each sprintf format

    This enhanced prompt gives Codex all the information needed to create a robust sprintf implementation that leverages C#'s built-in formatting capabilities while maintaining sprintf compatibility.
  9. yetanotherchris revised this gist Jun 12, 2025. 1 changed file with 99 additions and 0 deletions.
    99 changes: 99 additions & 0 deletions pipeline-functions.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,99 @@
    Go text templates support pipelines and chaining of actions, which are powerful features that allow you to process data through a series of transformations in a readable, left-to-right manner.

    ## Pipelines

    A pipeline in Go templates uses the pipe operator `|` to pass the output of one action as input to the next. The basic syntax is:

    ```
    {{ value | function1 | function2 | function3 }}
    ```

    The value flows from left to right through each function. Here's a simple example:

    ```go
    {{ .Name | printf "Hello, %s!" | print }}
    ```

    This takes the `.Name` field, passes it to `printf` to format it, then passes the result to `print`.

    ## Chaining Actions

    You can chain multiple template actions together using pipelines. Common patterns include:

    **String manipulation:**
    ```go
    {{ .Title | lower | title }} // Convert to lowercase, then title case
    {{ .Content | html | printf "<p>%s</p>" }} // HTML escape, then wrap in tags
    ```

    **Conditional processing:**
    ```go
    {{ .Value | default "N/A" | printf "Result: %s" }}
    ```

    **Multiple transformations:**
    ```go
    {{ .Price | printf "%.2f" | printf "$%s" }} // Format as decimal, then add dollar sign
    ```

    ## Built-in Functions in Pipelines

    Go templates provide several built-in functions that work well in pipelines:

    - `printf` - Format strings (like `fmt.Sprintf`)
    - `print`, `println` - Output functions
    - `html` - HTML escape
    - `js` - JavaScript escape
    - `urlquery` - URL query escape
    - `len` - Length of arrays, slices, maps, strings
    - `index` - Get element at index
    - `slice` - Create slice from array/slice

    ## Custom Functions

    You can register custom functions for use in pipelines:

    ```go
    funcMap := template.FuncMap{
    "upper": strings.ToUpper,
    "reverse": func(s string) string {
    runes := []rune(s)
    for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
    runes[i], runes[j] = runes[j], runes[i]
    }
    return string(runes)
    },
    }

    tmpl := template.New("example").Funcs(funcMap)
    ```

    Then use them in pipelines:
    ```go
    {{ .Name | upper | reverse | printf "Transformed: %s" }}
    ```

    ## Complex Pipeline Examples

    **Processing lists:**
    ```go
    {{ range .Items }}
    {{ . | printf "Item: %s" | println }}
    {{ end }}
    ```

    **Conditional formatting:**
    ```go
    {{ if .IsActive }}
    {{ .Status | upper | printf "STATUS: %s" }}
    {{ else }}
    {{ "inactive" | printf "STATUS: %s" }}
    {{ end }}
    ```

    **Nested data access:**
    ```go
    {{ .User.Email | printf "mailto:%s" | printf "<a href='%s'>Contact</a>" | html }}
    ```

    Pipelines make Go templates more readable and allow you to build complex data transformations by composing simple functions. The key is that data flows left-to-right through the pipeline, with each function receiving the output of the previous one as its final argument.
  10. yetanotherchris created this gist Jun 11, 2025.
    198 changes: 198 additions & 0 deletions go-template-parser.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,198 @@
    # Go Text/Template Parser Implementation with ANTLR

    Implement a basic Go text/template parser using ANTLR that supports core template functionality. The parser should handle variable interpolation, conditional statements, and loops while maintaining compatibility with Go's template syntax.

    ## Core Requirements

    ### 1. Variable Interpolation
    - Support `{{ .Field }}` syntax for accessing struct fields
    - Support nested field access: `{{ .User.Name }}`
    - Support array/slice indexing: `{{ .Items[0] }}`
    - Support map access: `{{ .Data.key }}`
    - Handle whitespace control with `{{- }}` and `{{ -}}`

    ### 2. Conditional Statements
    - Support `{{ if condition }}...{{ end }}` blocks
    - Support `{{ if condition }}...{{ else }}...{{ end }}`
    - Support `{{ if condition }}...{{ else if condition2 }}...{{ end }}`
    - Conditions should support:
    - Boolean fields: `{{ if .IsActive }}`
    - Comparisons: `{{ if eq .Status "active" }}`
    - Existence checks: `{{ if .User }}`

    ### 3. Loop Statements
    - Support `{{ range .Items }}...{{ end }}` for iterating over slices/arrays
    - Support `{{ range $index, $value := .Items }}...{{ end }}` with variables
    - Support `{{ range .Map }}...{{ end }}` for iterating over maps
    - Support `{{ range $key, $value := .Map }}...{{ end }}` with key-value variables
    - Handle empty collections with `{{ range .Items }}...{{ else }}...{{ end }}`

    ### 4. Built-in Functions (Basic Set)
    - `eq`: equality comparison `{{ if eq .Status "active" }}`
    - `ne`: not equal `{{ if ne .Count 0 }}`
    - `lt`, `le`, `gt`, `ge`: numeric comparisons
    - `and`, `or`: logical operations `{{ if and .IsActive .IsValid }}`
    - `not`: logical negation `{{ if not .IsHidden }}`

    ### 5. Comments
    - Support `{{/* comment */}}` syntax
    - Comments should be completely ignored in output

    ## Grammar Structure (ANTLR4)

    Your ANTLR grammar should define:
    - Template root with mixed text and actions
    - Action blocks (`{{ ... }}`)
    - Field access with dot notation
    - Conditional blocks with proper nesting
    - Range blocks with optional variable assignments
    - Function calls with arguments
    - String and numeric literals
    - Whitespace control tokens

    ## Edge Cases to Handle

    ### Variable Access Edge Cases
    ```go
    // Nested field access
    {{ .User.Profile.Avatar.URL }}

    // Array indexing with variables
    {{ .Items[.CurrentIndex] }}

    // Map access with string keys containing special characters
    {{ .Data["key-with-dashes"] }}

    // Accessing fields that might not exist (should not panic)
    {{ .MaybeNil.Field }}
    ```

    ### Conditional Edge Cases
    ```go
    // Nested conditions
    {{ if .User }}
    {{ if .User.IsActive }}
    Active user: {{ .User.Name }}
    {{ else }}
    Inactive user
    {{ end }}
    {{ end }}

    // Complex boolean expressions
    {{ if and (eq .Status "active") (gt .Count 0) }}
    Status is active and count is positive
    {{ end }}

    // Zero value checks
    {{ if .Count }}Count: {{ .Count }}{{ else }}No items{{ end }}
    ```

    ### Loop Edge Cases
    ```go
    // Empty slice handling
    {{ range .Items }}
    Item: {{ . }}
    {{ else }}
    No items found
    {{ end }}

    // Nested loops
    {{ range .Categories }}
    Category: {{ .Name }}
    {{ range .Items }}
    - {{ .Title }}
    {{ end }}
    {{ end }}

    // Range with index over empty slice
    {{ range $i, $item := .EmptySlice }}
    Never executed
    {{ else }}
    Empty slice message
    {{ end }}
    ```

    ### Whitespace Control Edge Cases
    ```go
    // Trimming leading whitespace
    {{- .Field }}

    // Trimming trailing whitespace
    {{ .Field -}}

    // Trimming both
    {{- .Field -}}

    // In loops and conditions
    {{ range .Items -}}
    {{- .Name }}
    {{- end }}
    ```

    ## Test Cases for Implementation

    ### Basic Variable Tests
    ```go
    // Test data
    data := struct {
    Name string
    Count int
    Active bool
    Items []string
    User *User
    }{
    Name: "Test",
    Count: 42,
    Active: true,
    Items: []string{"a", "b", "c"},
    User: &User{Name: "John", Age: 30},
    }

    // Test cases
    "Hello {{ .Name }}""Hello Test"
    "Count: {{ .Count }}""Count: 42"
    "User: {{ .User.Name }}""User: John"
    "First: {{ .Items[0] }}""First: a"
    ```

    ### Conditional Tests
    ```go
    "{{ if .Active }}Active{{ else }}Inactive{{ end }}""Active"
    "{{ if .Count }}Has items{{ end }}""Has items"
    "{{ if eq .Name \"Test\" }}Match{{ end }}""Match"
    "{{ if and .Active (gt .Count 10) }}Both true{{ end }}""Both true"
    ```

    ### Loop Tests
    ```go
    "{{ range .Items }}{{ . }} {{ end }}""a b c "
    "{{ range $i, $v := .Items }}{{ $i }}:{{ $v }} {{ end }}""0:a 1:b 2:c "
    "{{ range .EmptySlice }}Never{{ else }}Empty{{ end }}""Empty"
    ```

    ### Error Handling Tests
    ```go
    // Should not panic, should render empty or default
    "{{ .NonExistent }}"""
    "{{ .User.NonExistent }}"""
    "{{ .NilPointer.Field }}"""
    ```

    ## Implementation Guidelines

    1. **Error Handling**: The parser should gracefully handle missing fields and nil pointers without panicking
    2. **Type Safety**: Implement proper type checking for comparisons and operations
    3. **Performance**: Cache field lookups and compiled templates where possible
    4. **Memory Safety**: Avoid infinite recursion in nested templates
    5. **Whitespace**: Preserve original whitespace unless explicitly trimmed with `{{- -}}`

    ## Output Format

    Provide:
    1. ANTLR4 grammar file (.g4)
    2. Go code for the template engine
    3. Unit tests covering all edge cases mentioned above
    4. Example usage showing how to parse and execute templates
    5. Error handling examples

    The implementation should be production-ready for basic use cases while remaining simple enough to understand and extend.