Skip to content

Commit a94eb62

Browse files
authored
Parse ERB Nodes next to Text Content Nodes (#43)
This pull request improves the parsing of ERB tags next to text content nodes. Additionally, new test cases have been added to ensure the correct parsing of interpolated content within HTML elements. I also renamed the `parser_parse_literal` to `parser_build_node` so it can be used to build a node with a type and the name as a `char*`. Maybe this should live in `ast_node.c` or replace `ast_node_init`, but leaving this for now, since it's parser-specific enough.
1 parent eb6387d commit a94eb62

11 files changed

+121
-8
lines changed

β€Žsrc/parser.cβ€Ž

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ parser_T* parser_init(lexer_T* lexer) {
2626

2727
static void parser_parse_in_data_state(parser_T* parser, AST_NODE_T* element);
2828
static AST_NODE_T* parser_parse_erb_tag(parser_T* parser, AST_NODE_T* element);
29+
static AST_NODE_T* parser_build_node(parser_T* parser, ast_node_type_T type, char* name, AST_NODE_T* element);
2930

3031
static char* format_parser_error(const char* message, const char* expected, const char* actual) {
3132
int needed = snprintf(NULL, 0, "[Parser]: Unexpected Token %s (expected '%s', got: '%s')", message, expected, actual);
@@ -132,6 +133,15 @@ static AST_NODE_T* parser_parse_text_content(parser_T* parser, AST_NODE_T* eleme
132133
parser->current_token->type != TOKEN_HTML_TAG_START_CLOSE &&
133134
parser->current_token->type != TOKEN_HTML_COMMENT_START) {
134135
switch (parser->current_token->type) {
136+
case TOKEN_ERB_START: {
137+
if (buffer_length(&content) > 0) {
138+
parser_build_node(parser, AST_HTML_TEXT_NODE, buffer_value(&content), element);
139+
content = buffer_new();
140+
}
141+
142+
parser_parse_erb_tag(parser, element);
143+
} break;
144+
135145
case TOKEN_IDENTIFIER: {
136146
token_T* identifier = parser_consume(parser, TOKEN_IDENTIFIER, text_content_node);
137147

@@ -159,10 +169,13 @@ static AST_NODE_T* parser_parse_text_content(parser_T* parser, AST_NODE_T* eleme
159169
}
160170
}
161171
}
162-
163-
text_content_node->name = buffer_value(&content);
164-
165-
array_append(element->children, text_content_node);
172+
if (buffer_length(&content) > 0) {
173+
text_content_node->name = buffer_value(&content);
174+
array_append(element->children, text_content_node);
175+
} else {
176+
// TODO: implement ast_node_free()
177+
// ast_node_free(text_content_node);
178+
}
166179

167180
return text_content_node;
168181
}
@@ -181,8 +194,8 @@ static AST_NODE_T* parser_parse_html_attribute_name(parser_T* parser, AST_NODE_T
181194
return attribute_name;
182195
}
183196

184-
static AST_NODE_T* parser_parse_literal(parser_T* parser, char* name, AST_NODE_T* element) {
185-
AST_NODE_T* literal_node = ast_node_init(AST_LITERAL_NODE);
197+
static AST_NODE_T* parser_build_node(parser_T* parser, ast_node_type_T type, char* name, AST_NODE_T* element) {
198+
AST_NODE_T* literal_node = ast_node_init(type);
186199

187200
literal_node->name = name;
188201
array_append(element->children, literal_node);
@@ -207,7 +220,7 @@ static AST_NODE_T* parser_parse_html_attribute_value(parser_T* parser, AST_NODE_
207220
switch (parser->current_token->type) {
208221
case TOKEN_ERB_START: {
209222
if (buffer_length(&buffer) > 0) {
210-
parser_parse_literal(parser, buffer_value(&buffer), attribute_value);
223+
parser_build_node(parser, AST_LITERAL_NODE, buffer_value(&buffer), attribute_value);
211224
buffer = buffer_new();
212225
}
213226

@@ -222,7 +235,7 @@ static AST_NODE_T* parser_parse_html_attribute_value(parser_T* parser, AST_NODE_
222235
}
223236

224237
if (buffer_length(&buffer) > 0) {
225-
parser_parse_literal(parser, buffer_value(&buffer), attribute_value);
238+
parser_build_node(parser, AST_LITERAL_NODE, buffer_value(&buffer), attribute_value);
226239
}
227240

228241
token_T* close_quote = parser_consume(parser, TOKEN_QUOTE, attribute_value);

β€Žtest/parser/erb_test.rbβ€Ž

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ class ERBTest < Minitest::Spec
1414
assert_parsed_snapshot(%(<h1><%= hello %></h1>))
1515
end
1616

17+
test "interpolate in element body followed by text content" do
18+
assert_parsed_snapshot(%(<h1><%= Hello %> World</h1>))
19+
end
20+
21+
test "interpolate in element body after text content" do
22+
assert_parsed_snapshot(%(<h1>Hello <%= World %></h1>))
23+
end
24+
25+
test "interpolate in element body surrounded by text content" do
26+
assert_parsed_snapshot(%(<h1>Hello <%= World %> Hello</h1>))
27+
end
28+
1729
test "interpolate inside tag" do
1830
assert_parsed_snapshot(%(<h1 <%= "id=test" %>></h1>))
1931
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
@ DocumentNode (location: (0,0)-(0,0))
2+
β”œβ”€β”€ name: βˆ…
3+
└── children: (1)
4+
@ Element (location: (0,0)-(0,0))
5+
β”œβ”€β”€ name: βˆ…
6+
└── children: (3)
7+
@ OpenTag (location: (0,0)-(0,0))
8+
β”œβ”€β”€ name: "h1"
9+
└── children: (1)
10+
@ AttributeSet (location: (0,0)-(0,0))
11+
β”œβ”€β”€ name: βˆ…
12+
└── children: []
13+
14+
@ ElementBody (location: (0,0)-(0,0))
15+
β”œβ”€β”€ name: βˆ…
16+
└── children: (2)
17+
@ ERBContent (location: (0,0)-(0,0))
18+
β”œβ”€β”€ name: " Hello "
19+
└── children: []
20+
21+
@ TextContent (location: (0,0)-(0,0))
22+
β”œβ”€β”€ name: " World"
23+
└── children: []
24+
25+
@ CloseTag (location: (0,0)-(0,0))
26+
β”œβ”€β”€ name: "h1"
27+
└── children: []
28+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
@ DocumentNode (location: (0,0)-(0,0))
2+
β”œβ”€β”€ name: βˆ…
3+
└── children: (1)
4+
@ Element (location: (0,0)-(0,0))
5+
β”œβ”€β”€ name: βˆ…
6+
└── children: (3)
7+
@ OpenTag (location: (0,0)-(0,0))
8+
β”œβ”€β”€ name: "h1"
9+
└── children: (1)
10+
@ AttributeSet (location: (0,0)-(0,0))
11+
β”œβ”€β”€ name: βˆ…
12+
└── children: []
13+
14+
@ ElementBody (location: (0,0)-(0,0))
15+
β”œβ”€β”€ name: βˆ…
16+
└── children: (2)
17+
@ TextContent (location: (0,0)-(0,0))
18+
β”œβ”€β”€ name: "Hello "
19+
└── children: []
20+
21+
@ ERBContent (location: (0,0)-(0,0))
22+
β”œβ”€β”€ name: " World "
23+
└── children: []
24+
25+
@ CloseTag (location: (0,0)-(0,0))
26+
β”œβ”€β”€ name: "h1"
27+
└── children: []
28+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
@ DocumentNode (location: (0,0)-(0,0))
2+
β”œβ”€β”€ name: βˆ…
3+
└── children: (1)
4+
@ Element (location: (0,0)-(0,0))
5+
β”œβ”€β”€ name: βˆ…
6+
└── children: (3)
7+
@ OpenTag (location: (0,0)-(0,0))
8+
β”œβ”€β”€ name: "h1"
9+
└── children: (1)
10+
@ AttributeSet (location: (0,0)-(0,0))
11+
β”œβ”€β”€ name: βˆ…
12+
└── children: []
13+
14+
@ ElementBody (location: (0,0)-(0,0))
15+
β”œβ”€β”€ name: βˆ…
16+
└── children: (3)
17+
@ TextContent (location: (0,0)-(0,0))
18+
β”œβ”€β”€ name: "Hello "
19+
└── children: []
20+
21+
@ ERBContent (location: (0,0)-(0,0))
22+
β”œβ”€β”€ name: " World "
23+
└── children: []
24+
25+
@ TextContent (location: (0,0)-(0,0))
26+
β”œβ”€β”€ name: " Hello"
27+
└── children: []
28+
29+
@ CloseTag (location: (0,0)-(0,0))
30+
β”œβ”€β”€ name: "h1"
31+
└── children: []
32+

test/snapshots/parser/erb_test/test_0003_interpolate_inside_tag_eab2e64d663c26be3ae86f89610a672c.txt renamed to test/snapshots/parser/erb_test/test_0006_interpolate_inside_tag_eab2e64d663c26be3ae86f89610a672c.txt

File renamed without changes.

test/snapshots/parser/erb_test/test_0004_interpolate_inside_attribute_value_2e13bc9eabd550dcbe23f58ac7a01f99.txt renamed to test/snapshots/parser/erb_test/test_0007_interpolate_inside_attribute_value_2e13bc9eabd550dcbe23f58ac7a01f99.txt

File renamed without changes.

test/snapshots/parser/erb_test/test_0005_interpolate_after_attribute_name_871cced3d8488a845c21475c5f4a6bf1.txt renamed to test/snapshots/parser/erb_test/test_0008_interpolate_after_attribute_name_871cced3d8488a845c21475c5f4a6bf1.txt

File renamed without changes.

test/snapshots/parser/erb_test/test_0006_interpolate_inside_attribute_value_with_static_content_before_47cae9bfcf12e434a763c78aad910e38.txt renamed to test/snapshots/parser/erb_test/test_0009_interpolate_inside_attribute_value_with_static_content_before_47cae9bfcf12e434a763c78aad910e38.txt

File renamed without changes.

test/snapshots/parser/erb_test/test_0007_interpolate_inside_attribute_value_with_static_content_after_c840a0e926fd1dd829420021b6f5da39.txt renamed to test/snapshots/parser/erb_test/test_0010_interpolate_inside_attribute_value_with_static_content_after_c840a0e926fd1dd829420021b6f5da39.txt

File renamed without changes.

0 commit comments

Comments
Β (0)