Skip to content

Parser error in v0.8.0 when using if inside else of a case block #860

@kozy4324

Description

@kozy4324

It seems that herb v0.8.0 fails to parse valid ERB when an if statement is placed inside the else branch of a case block.
This issue does not occur in v0.7.5.

Example template

<% case %>
<% when true %>
  1
<% else %>
  <% if true %>
    2
  <% end %>
<% end %>

Output on v0.8.0

$ herb _0.8.0_ --version
herb gem v0.8.0, libprism v1.6.0, libherb v0.8.0 (Ruby C native extension)

$ herb _0.8.0_ parse a.html.erb 
@ DocumentNode (location: (1:0)-(10:0))
└── children: (4 items)
    ├── @ ERBCaseNode (location: (1:0)-(7:11))
    │   ├── tag_opening: "<%" (location: (1:0)-(1:2))
    │   ├── content: " case " (location: (1:2)-(1:8))
    │   ├── tag_closing: "%>" (location: (1:8)-(1:10))
    │   ├── children: (1 item)
    │   │   └── @ HTMLTextNode (location: (1:10)-(2:0))
    │   │       └── content: "\n"
    │   │       
    │   ├── conditions: (1 item)
    │   │   └── @ ERBWhenNode (location: (2:0)-(2:15))
    │   │       ├── tag_opening: "<%" (location: (2:0)-(2:2))
    │   │       ├── content: " when true " (location: (2:2)-(2:13))
    │   │       ├── tag_closing: "%>" (location: (2:13)-(2:15))
    │   │       └── statements: (1 item)
    │   │           └── @ HTMLTextNode (location: (2:15)-(4:0))
    │   │               └── content: "\n  1\n"
    │   │               
    │   │
    │   ├── else_clause: 
    │   │   └── @ ERBElseNode (location: (4:0)-(4:10))
    │   │       ├── tag_opening: "<%" (location: (4:0)-(4:2))
    │   │       ├── content: " else " (location: (4:2)-(4:8))
    │   │       ├── tag_closing: "%>" (location: (4:8)-(4:10))
    │   │       └── statements: (2 items)
    │   │           ├── @ HTMLTextNode (location: (4:10)-(5:2))
    │   │           │   └── content: "\n  "
    │   │           │   
    │   │           └── @ ERBIfNode (location: (5:2)-(7:2))
    │   │               ├── errors: (1 error)
    │   │               │   └── @ MissingERBEndTagError (location: (5:2)-(5:15))
    │   │               │       ├── message: "`<% if %>` started here but never closed with an end tag. The end tag may be in a different scope."
    │   │               │       └── keyword: "`<% if %>`"
    │   │               │       
    │   │               ├── tag_opening: "<%" (location: (5:2)-(5:4))
    │   │               ├── content: " if true " (location: (5:4)-(5:13))
    │   │               ├── tag_closing: "%>" (location: (5:13)-(5:15))
    │   │               ├── statements: (1 item)
    │   │               │   └── @ HTMLTextNode (location: (5:15)-(7:2))
    │   │               │       └── content: "\n    2\n  "
    │   │               │       
    │   │               ├── subsequent: ∅
    │   │               └── end_node: ∅
    │   │               
    │   │
    │   └── end_node: 
    │       └── @ ERBEndNode (location: (7:2)-(7:11))
    │           ├── tag_opening: "<%" (location: (7:2)-(7:4))
    │           ├── content: " end " (location: (7:4)-(7:9))
    │           └── tag_closing: "%>" (location: (7:9)-(7:11))
    │
    │
    ├── @ HTMLTextNode (location: (7:11)-(8:0))
    │   └── content: "\n"
    │   
    ├── @ ERBContentNode (location: (8:0)-(8:9))
    │   ├── errors: (1 error)
    │   │   └── @ ERBControlFlowScopeError (location: (8:0)-(8:9))
    │   │       ├── message: "`<% end %>` appears outside its control flow block. Keep ERB control flow statements together within the same HTML scope (tag, attribute, or content)."
    │   │       └── keyword: "`<% end %>`"
    │   │       
    │   ├── tag_opening: "<%" (location: (8:0)-(8:2))
    │   ├── content: " end " (location: (8:2)-(8:7))
    │   ├── tag_closing: "%>" (location: (8:7)-(8:9))
    │   ├── parsed: true
    │   └── valid: false
    │
    └── @ HTMLTextNode (location: (8:9)-(10:0))
        └── content: "\n\n"
        

Errors (2 total)

  1. MissingERBEndTagError at a.html.erb:5:2
     `<% if %>` started here but never closed with an end tag. The end tag may be in a different scope.

  2. ERBControlFlowScopeError at a.html.erb:8:0
     `<% end %>` appears outside its control flow block. Keep ERB control flow statements together within the same HTML scope (tag, attribute, or content).

Output on v0.7.5

$ herb _0.7.5_ --version
herb gem v0.7.5, libprism v1.5.1, libherb v0.7.5 (Ruby C native extension)

$ herb _0.7.5_ parse a.html.erb 
@ DocumentNode (location: (1:0)-(10:0))
└── children: (4 items)
    ├── @ ERBCaseNode (location: (1:0)-(7:11))
    │   ├── tag_opening: "<%" (location: (1:0)-(1:2))
    │   ├── content: " case " (location: (1:2)-(1:8))
    │   ├── tag_closing: "%>" (location: (1:8)-(1:10))
    │   ├── children: (1 item)
    │   │   └── @ HTMLTextNode (location: (1:10)-(2:0))
    │   │       └── content: "\n"
    │   │
    │   ├── conditions: (1 item)
    │   │   └── @ ERBWhenNode (location: (2:0)-(2:15))
    │   │       ├── tag_opening: "<%" (location: (2:0)-(2:2))
    │   │       ├── content: " when true " (location: (2:2)-(2:13))
    │   │       ├── tag_closing: "%>" (location: (2:13)-(2:15))
    │   │       └── statements: (1 item)
    │   │           └── @ HTMLTextNode (location: (2:15)-(4:0))
    │   │               └── content: "\n  1\n"
    │   │
    │   │
    │   ├── else_clause:
    │   │   └── @ ERBElseNode (location: (4:0)-(4:10))
    │   │       ├── tag_opening: "<%" (location: (4:0)-(4:2))
    │   │       ├── content: " else " (location: (4:2)-(4:8))
    │   │       ├── tag_closing: "%>" (location: (4:8)-(4:10))
    │   │       └── statements: (3 items)
    │   │           ├── @ HTMLTextNode (location: (4:10)-(5:2))
    │   │           │   └── content: "\n  "
    │   │           │
    │   │           ├── @ ERBContentNode (location: (5:2)-(5:15))
    │   │           │   ├── tag_opening: "<%" (location: (5:2)-(5:4))
    │   │           │   ├── content: " if true " (location: (5:4)-(5:13))
    │   │           │   ├── tag_closing: "%>" (location: (5:13)-(5:15))
    │   │           │   ├── parsed: true
    │   │           │   └── valid: false
    │   │           │
    │   │           └── @ HTMLTextNode (location: (5:15)-(7:2))
    │   │               └── content: "\n    2\n  "
    │   │
    │   │
    │   └── end_node:
    │       └── @ ERBEndNode (location: (7:2)-(7:11))
    │           ├── tag_opening: "<%" (location: (7:2)-(7:4))
    │           ├── content: " end " (location: (7:4)-(7:9))
    │           └── tag_closing: "%>" (location: (7:9)-(7:11))
    │
    │
    ├── @ HTMLTextNode (location: (7:11)-(8:0))
    │   └── content: "\n"
    │
    ├── @ ERBContentNode (location: (8:0)-(8:9))
    │   ├── tag_opening: "<%" (location: (8:0)-(8:2))
    │   ├── content: " end " (location: (8:2)-(8:7))
    │   ├── tag_closing: "%>" (location: (8:7)-(8:9))
    │   ├── parsed: true
    │   └── valid: false
    │
    └── @ HTMLTextNode (location: (8:9)-(10:0))
        └── content: "\n\n"

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcparser

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions