Skip to content

Commit a7b43db

Browse files
fix parsing of objects elements; (#197)
this fixes: * #71 * #77 * #140 * #147 * #149 * #163
1 parent fbbd7b6 commit a7b43db

File tree

7 files changed

+30
-31
lines changed

7 files changed

+30
-31
lines changed

hcl2/hcl2.lark

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ start : body
22
body : (new_line_or_comment? (attribute | block))* new_line_or_comment?
33
attribute : identifier EQ expression
44
block : identifier (identifier | STRING_LIT | string_with_interpolation)* new_line_or_comment? "{" body "}"
5-
new_line_and_or_comma: new_line_or_comment | "," | "," new_line_or_comment
65
new_line_or_comment: ( NL_OR_COMMENT )+
76
NL_OR_COMMENT: /\n[ \t]*/ | /#.*\n/ | /\/\/.*\n/ | /\/\*(.|\n)*?(\*\/)/
87

@@ -70,8 +69,9 @@ EXP_MARK : ("e" | "E") ("+" | "-")? DECIMAL+
7069
EQ : /[ \t]*=(?!=|>)/
7170

7271
tuple : "[" (new_line_or_comment* expression new_line_or_comment* ",")* (new_line_or_comment* expression)? new_line_or_comment* "]"
73-
object : "{" new_line_or_comment? (object_elem (new_line_and_or_comma object_elem )* new_line_and_or_comma?)? "}"
74-
object_elem : (identifier | expression) ( EQ | ":") expression
72+
object : "{" new_line_or_comment? (new_line_or_comment* (object_elem | (object_elem ",")) new_line_or_comment*)* "}"
73+
object_elem : object_elem_key ( EQ | ":") expression
74+
object_elem_key : float_lit | int_lit | identifier | STRING_LIT
7575

7676

7777
heredoc_template : /<<(?P<heredoc>[a-zA-Z][a-zA-Z0-9._-]+)\n?(?:.|\n)*?\n\s*(?P=heredoc)\n/

hcl2/reconstructor.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -396,15 +396,7 @@ def _is_string_wrapped_tf(interp_s: str) -> bool:
396396

397397
return True
398398

399-
def _newline(self, level: int, comma: bool = False, count: int = 1) -> Tree:
400-
# some rules expect the `new_line_and_or_comma` token
401-
if comma:
402-
return Tree(
403-
Token("RULE", "new_line_and_or_comma"),
404-
[self._newline(level=level, comma=False, count=count)],
405-
)
406-
407-
# otherwise, return the `new_line_or_comment` token
399+
def _newline(self, level: int, count: int = 1) -> Tree:
408400
return Tree(
409401
Token("RULE", "new_line_or_comment"),
410402
[Token("NL_OR_COMMENT", f"\n{' ' * level}") for _ in range(count)],
@@ -561,20 +553,27 @@ def _transform_value_to_expr_term(self, value, level) -> Union[Token, Tree]:
561553
for i, (k, dict_v) in enumerate(value.items()):
562554
if k in ["__start_line__", "__end_line__"]:
563555
continue
564-
identifier = self._name_to_identifier(k)
556+
565557
value_expr_term = self._transform_value_to_expr_term(dict_v, level + 1)
566558
elems.append(
567559
Tree(
568560
Token("RULE", "object_elem"),
569-
[identifier, Token("EQ", " ="), value_expr_term],
561+
[
562+
Tree(
563+
Token("RULE", "object_elem_key"),
564+
[Tree(Token("RULE", "identifier"), [Token("NAME", k)])],
565+
),
566+
Token("EQ", " ="),
567+
value_expr_term,
568+
],
570569
)
571570
)
572571

573572
# add indentation appropriately
574573
if i < len(value) - 1:
575-
elems.append(self._newline(level + 1, comma=True))
574+
elems.append(self._newline(level + 1))
576575
else:
577-
elems.append(self._newline(level, comma=True))
576+
elems.append(self._newline(level))
578577
return Tree(
579578
Token("RULE", "expr_term"), [Tree(Token("RULE", "object"), elems)]
580579
)
@@ -630,7 +629,7 @@ def _transform_value_to_expr_term(self, value, level) -> Union[Token, Tree]:
630629
if parsed_value.data == Token("RULE", "expr_term"):
631630
return parsed_value
632631

633-
# wrap other types of syntax as an expression (in parenthesis)
632+
# wrap other types of syntax as an expression (in parentheses)
634633
return Tree(Token("RULE", "expr_term"), [parsed_value])
635634

636635
# otherwise it's just a string.

hcl2/transformer.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,13 @@ def tuple(self, args: List) -> List:
9999
def object_elem(self, args: List) -> Dict:
100100
# This returns a dict with a single key/value pair to make it easier to merge these
101101
# into a bigger dict that is returned by the "object" function
102-
key = self.strip_quotes(args[0])
102+
key = self.strip_quotes(str(args[0].children[0]))
103103
if len(args) == 3:
104-
value = self.to_string_dollar(args[2])
104+
value = args[2]
105105
else:
106-
value = self.to_string_dollar(args[1])
106+
value = args[1]
107107

108+
value = self.to_string_dollar(value)
108109
return {key: value}
109110

110111
def object(self, args: List) -> Dict:
@@ -136,9 +137,6 @@ def provider_function_call(self, args: List) -> str:
136137
def arguments(self, args: List) -> List:
137138
return args
138139

139-
def new_line_and_or_comma(self, args: List) -> _DiscardType:
140-
return Discard
141-
142140
@v_args(meta=True)
143141
def block(self, meta: Meta, args: List) -> Dict:
144142
*block_labels, block_body = args

test/helpers/terraform-config/backend.tf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ terraform {
1919
backend "gcs" {}
2020
required_providers {
2121
aws = {
22-
source = "hashicorp/aws"
22+
source = "hashicorp/aws",
2323
}
2424
null = {
25-
source = "hashicorp/null"
25+
source = "hashicorp/null",
2626
}
2727
template = {
28-
source = "hashicorp/template"
28+
source = "hashicorp/template",
2929
}
3030
}
3131
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
locals {
22
terraform = {
3-
channels = (local.running_in_ci ? local.ci_channels : local.local_channels)
4-
authentication = []
3+
channels = (local.running_in_ci ? local.ci_channels : local.local_channels),
4+
authentication = [],
55
}
66
}

test/helpers/terraform-config/s3.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ resource "aws_s3_bucket" "name" {
1212
}
1313

1414
transition = {
15-
days = 30
16-
storage_class = "GLACIER"
15+
days = 30,
16+
storage_class = "GLACIER",
1717
}
1818
}
1919

test/unit/test_hcl2_syntax.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,9 @@ def test_tuple(self):
104104
def test_object(self):
105105
object_ = """object = {
106106
key1: identifier, key2: "string", key3: 100,
107-
key4: true == false,
107+
key4: true == false // comment
108108
key5: 5 + 5, key6: function(),
109+
key7: value == null ? 1 : 0
109110
}"""
110111
result = self.load_to_dict(object_)
111112
self.assertDictEqual(
@@ -118,6 +119,7 @@ def test_object(self):
118119
"key4": "${true == false}",
119120
"key5": "${5 + 5}",
120121
"key6": "${function()}",
122+
"key7": "${value == None ? 1 : 0}",
121123
}
122124
},
123125
)

0 commit comments

Comments
 (0)