From 76804b3d201ea05ef1d287d907665d985d463fd4 Mon Sep 17 00:00:00 2001 From: Sam Weaver Date: Mon, 14 Oct 2024 14:45:40 -0400 Subject: [PATCH] Better handle nested interpolation (fixes #173) (breaks some reconstruction tests, tackling that next) --- hcl2/hcl2.lark | 12 ++++++------ hcl2/transformer.py | 11 +++++++++++ .../multi_level_interpolation.json | 10 ++++++++++ .../terraform-config/multi_level_interpolation.tf | 7 +++++++ 4 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 test/helpers/terraform-config-json/multi_level_interpolation.json create mode 100644 test/helpers/terraform-config/multi_level_interpolation.tf diff --git a/hcl2/hcl2.lark b/hcl2/hcl2.lark index d26acc1..cbb8218 100644 --- a/hcl2/hcl2.lark +++ b/hcl2/hcl2.lark @@ -1,7 +1,7 @@ start : body body : (new_line_or_comment? (attribute | block))* new_line_or_comment? attribute : identifier EQ expression -block : identifier (identifier | STRING_LIT)* new_line_or_comment? "{" body "}" +block : identifier (identifier | STRING_LIT | string_with_interpolation)* new_line_or_comment? "{" body "}" new_line_and_or_comma: new_line_or_comment | "," | "," new_line_or_comment new_line_or_comment: ( NL_OR_COMMENT )+ NL_OR_COMMENT: /\n[ \t]*/ | /#.*\n/ | /\/\/.*\n/ | /\/\*(.|\n)*?(\*\/)/ @@ -28,6 +28,7 @@ expr_term : "(" new_line_or_comment? expression new_line_or_comment? ")" | float_lit | int_lit | STRING_LIT + | string_with_interpolation | tuple | object | function_call @@ -42,11 +43,10 @@ expr_term : "(" new_line_or_comment? expression new_line_or_comment? ")" | for_tuple_expr | for_object_expr - -STRING_LIT : "\"" (STRING_CHARS | INTERPOLATION)* "\"" -STRING_CHARS : /(?:(?!\${)([^"\\]|\\.))+/+ // any character except '"" unless inside a interpolation string -NESTED_INTERPOLATION : "${" /[^}]+/ "}" -INTERPOLATION : "${" (/(?:(?!\${)([^}]))+/ | NESTED_INTERPOLATION)+ "}" +STRING_LIT : "\"" (STRING_CHARS)* "\"" +STRING_CHARS : /(?:(?!\${)([^"\\]|\\.))+/+ // any character except '"' unless inside a interpolation string +string_with_interpolation: "\"" (STRING_CHARS)* interpolation_maybe_nested (STRING_CHARS | interpolation_maybe_nested)* "\"" +interpolation_maybe_nested: "${" expression "}" int_lit : DECIMAL+ !float_lit: DECIMAL+ "." DECIMAL+ (EXP_MARK DECIMAL+)? diff --git a/hcl2/transformer.py b/hcl2/transformer.py index c3a2686..c7434df 100644 --- a/hcl2/transformer.py +++ b/hcl2/transformer.py @@ -277,6 +277,13 @@ def for_object_expr(self, args: List) -> str: # e.g. f"{2 + 2} {{2 + 2}}" == "4 {2 + 2}" return f"{{{for_expr}}}" + def string_with_interpolation(self, args: List) -> str: + return '"' + ("".join(args)) + '"' + + def interpolation_maybe_nested(self, args: List) -> str: + # return "".join(args) + return "${" + ("".join(args)) + "}" + def strip_new_line_tokens(self, args: List) -> List: """ Remove new line and Discard tokens. @@ -287,6 +294,10 @@ def strip_new_line_tokens(self, args: List) -> List: def to_string_dollar(self, value: Any) -> Any: """Wrap a string in ${ and }""" if isinstance(value, str): + # if it's already wrapped, pass it unmodified + if value.startswith("${") and value.endswith("}"): + return value + if value.startswith('"') and value.endswith('"'): value = str(value)[1:-1] return self.process_escape_sequences(value) diff --git a/test/helpers/terraform-config-json/multi_level_interpolation.json b/test/helpers/terraform-config-json/multi_level_interpolation.json new file mode 100644 index 0000000..ab2af72 --- /dev/null +++ b/test/helpers/terraform-config-json/multi_level_interpolation.json @@ -0,0 +1,10 @@ +{ + "block": [ + { + "a": "${\"${\"${\"a\"}\"}\"}" + }, + { + "b": "${var.b}" + } + ] +} diff --git a/test/helpers/terraform-config/multi_level_interpolation.tf b/test/helpers/terraform-config/multi_level_interpolation.tf new file mode 100644 index 0000000..22ef7f5 --- /dev/null +++ b/test/helpers/terraform-config/multi_level_interpolation.tf @@ -0,0 +1,7 @@ +block { + a = "${"${"${"a"}"}"}" +} + +block { + b = "${var.b}" +} \ No newline at end of file