Skip to content

Commit ae2f5c1

Browse files
reintroduce parsing of string interpolations nested deeper than 2 times (originally implemented by @weaversam8 in #177) and fixed STRING_CHARS regex to treat escaped interpolation as a regular string
1 parent d4bfac8 commit ae2f5c1

File tree

6 files changed

+13
-24
lines changed

6 files changed

+13
-24
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77

88
## \[Unreleased\]
99

10+
### Added
11+
12+
- Possibility to parse deeply nested interpolations (formerly a Limitation), Thanks again, @weaversam8 ([#223](https://github.com/amplify-education/python-hcl2/pull/223))
13+
1014
### Fixed
1115

1216
- Issue parsing ellipsis in a separate line within `for` expression ([#221](https://github.com/amplify-education/python-hcl2/pull/221))

README.md

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -87,24 +87,6 @@ We’ll try to answer any PR’s promptly.
8787

8888
## Limitations
8989

90-
### Error parsing string interpolations nested more than 2 times
91-
92-
- Parsing following example is expected to throw out an exception and fail:
93-
```terraform
94-
locals {
95-
foo = "foo"
96-
name = "prefix1-${"prefix2-${"${local.foo}-bar"}"}" //should interpolate into "prefix1-prefix2-foo-bar" but fails
97-
}
98-
```
99-
We recommend working around this by modifying the configuration in the following manner:
100-
```terraform
101-
locals {
102-
foo = "foo"
103-
foo_bar = "${local.foo}-bar"
104-
name = "prefix1-${"prefix2-${local.foo_bar}"}" //interpolates into "prefix1-prefix2-foo-bar"
105-
}
106-
```
107-
10890
### Using inline expression as an object key
10991

11092
- Object key can be an expression as long as it is wrapped in parentheses:

hcl2/hcl2.lark

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
start : body
22
body : (new_line_or_comment? (attribute | block))* new_line_or_comment?
33
attribute : identifier EQ expression
4-
block : identifier (identifier | STRING_LIT)* new_line_or_comment? "{" body "}"
4+
block : identifier (identifier | STRING_LIT | string_with_interpolation)* new_line_or_comment? "{" body "}"
55
new_line_or_comment: ( NL_OR_COMMENT )+
66
NL_OR_COMMENT: /\n[ \t]*/ | /#.*\n/ | /\/\/.*\n/ | /\/\*(.|\n)*?(\*\/)/
77

@@ -45,6 +45,7 @@ expr_term : LPAR new_line_or_comment? expression new_line_or_comment? RPAR
4545
| float_lit
4646
| int_lit
4747
| STRING_LIT
48+
| string_with_interpolation
4849
| tuple
4950
| object
5051
| function_call
@@ -59,10 +60,10 @@ expr_term : LPAR new_line_or_comment? expression new_line_or_comment? RPAR
5960
| for_tuple_expr
6061
| for_object_expr
6162

62-
STRING_LIT : "\"" (STRING_CHARS | INTERPOLATION)* "\""
63-
STRING_CHARS : /(?:(?!\${)([^"\\]|\\.))+/+ // any character except '"" unless inside a interpolation string
64-
NESTED_INTERPOLATION : "${" /[^}]+/ "}"
65-
INTERPOLATION : "${" (/(?:(?!\${)([^}]))+/ | NESTED_INTERPOLATION)+ "}"
63+
STRING_LIT : "\"" STRING_CHARS? "\""
64+
STRING_CHARS : /(?:(?!\${)([^"\\]|\\.|\$\$))+/ // any character except '"', including escaped $$
65+
string_with_interpolation: "\"" (STRING_CHARS)* interpolation_maybe_nested (STRING_CHARS | interpolation_maybe_nested)* "\""
66+
interpolation_maybe_nested: "${" expression "}"
6667

6768

6869
int_lit : NEGATIVE_DECIMAL? DECIMAL+ | NEGATIVE_DECIMAL+
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"locals": [{"simple_interpolation": "prefix:${var.foo}-suffix", "embedded_interpolation": "(long substring without interpolation); ${module.special_constants.aws_accounts[\"aaa-${local.foo}-${local.bar}\"]}/us-west-2/key_foo", "escaped_interpolation": "prefix:$${aws:username}-suffix"}]}
1+
{"locals": [{"simple_interpolation": "prefix:${var.foo}-suffix", "embedded_interpolation": "(long substring without interpolation); ${module.special_constants.aws_accounts[\"aaa-${local.foo}-${local.bar}\"]}/us-west-2/key_foo", "deeply_nested_interpolation": "prefix1-${\"prefix2-${\"prefix3-${local.foo}\"}\"}", "escaped_interpolation": "prefix:$${aws:username}-suffix"}]}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
locals {
22
simple_interpolation = "prefix:${var.foo}-suffix"
33
embedded_interpolation = "(long substring without interpolation); ${module.special_constants.aws_accounts["aaa-${local.foo}-${local.bar}"]}/us-west-2/key_foo"
4+
deeply_nested_interpolation = "prefix1-${"prefix2-${"prefix3-${local.foo}"}"}"
45
escaped_interpolation = "prefix:$${aws:username}-suffix"
56
}

test/unit/test_builder.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def test_locals_embedded_interpolation_tf(self):
7373
"simple_interpolation": "prefix:${var.foo}-suffix",
7474
"embedded_interpolation": "(long substring without interpolation); "
7575
'${module.special_constants.aws_accounts["aaa-${local.foo}-${local.bar}"]}/us-west-2/key_foo',
76+
"deeply_nested_interpolation": 'prefix1-${"prefix2-${"prefix3-${local.foo}"}"}',
7677
"escaped_interpolation": "prefix:$${aws:username}-suffix",
7778
}
7879

0 commit comments

Comments
 (0)