diff --git a/CHANGELOG.md b/CHANGELOG.md index 20bf52f..ef9791d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +0.3.13 (2019-06-25) +------------------ +* Updated for terraform v0.12 syntax + 0.2.1 (2016-04-14) ------------------ * Fixes for mutliple configuration blocks with same name diff --git a/README.rst b/README.rst index de17f6b..f9a49a0 100644 --- a/README.rst +++ b/README.rst @@ -12,6 +12,11 @@ The grammar and many of the tests/fixtures were copied/ported from the golang parser into pyhcl. All releases are tested with a variety of python versions from Python 2.7 onward. +This version has been modified to work with terraform 0.12 syntax. +It should be backward compatible with earlier versions. +It doesn't cover every situation. See discussion in pull request: +https://github.com/virtuald/pyhcl/pull/57 + Installation ============ diff --git a/src/hcl/lexer.py b/src/hcl/lexer.py index 176d7dc..de02865 100644 --- a/src/hcl/lexer.py +++ b/src/hcl/lexer.py @@ -36,7 +36,10 @@ class Lexer(object): 'IDENTIFIER', 'EQUAL', 'STRING', + 'ADD', 'MINUS', + 'MULTIPLY', + 'DIVIDE', 'LEFTBRACE', 'RIGHTBRACE', 'LEFTBRACKET', @@ -44,6 +47,17 @@ class Lexer(object): 'PERIOD', 'EPLUS', 'EMINUS', + 'LEFTPAREN', + 'RIGHTPAREN', + 'QMARK', + 'COLON', + 'ASTERISK_PERIOD', + 'GT', + 'LT', + 'EQ', + 'NE', + 'LE', + 'GE', ) states = ( @@ -63,7 +77,7 @@ def t_EMINUS(self, t): return t def t_EPLUS(self, t): - r'(?<=\d|\.)[eE]\+?' + r'(?<=\d)[eE]\+?|(?<=\d\.)[eE]\+?' return t def t_FLOAT(self, t): @@ -91,6 +105,42 @@ def t_COMMA(self, t): r',' return t + def t_QMARK(self, t): + r'\?' + return t + + def t_COLON(self, t): + r':' + return t + + def t_ASTERISK_PERIOD(self, t): + r'\*\.' + return t + + def t_GT(self, t): + r'(?)>(?!>|=)' + return t + + def t_LT(self, t): + r'(?=' + return t + def t_IDENTIFIER(self, t): r'[^\W\d][\w.-]*' t.value = text_type(t.value) @@ -259,13 +309,12 @@ def t_heredoc_eof(self, t): t_tabbedheredoc_ignoring = t_heredoc_ignoring t_tabbedheredoc_eof = t_heredoc_eof - t_EQUAL = r'=' - t_MINUS = r'-' - t_LEFTBRACE = r'\{' t_RIGHTBRACE = r'\}' t_LEFTBRACKET = r'\[' t_RIGHTBRACKET = r'\]' + t_LEFTPAREN = r'\(' + t_RIGHTPAREN = r'\)' def t_COMMENT(self, t): r'(\#|(//)).*' @@ -283,6 +332,12 @@ def t_newline(self, t): t_ignore = ' \t\r\f\v' + t_EQUAL = r'(?"), + ("LT", "<"), + ("EQ", "=="), + ("NE", "!="), + ("LE", "<="), + ("GE", ">="), + ("ASTERISK_PERIOD", "*."), # Bools ("BOOL", "true"), @@ -382,6 +396,7 @@ def test_tokens(token, input_string): # other token COMPLEX_TOKEN_FIXTURES = [ # EPLUS + (["IDENTIFIER", "EQUAL", "LEFTBRACKET", "IDENTIFIER", "LEFTBRACKET", "NUMBER", "RIGHTBRACKET", "PERIOD", "IDENTIFIER", "RIGHTBRACKET", ], "records = [aws_elasticsearch_domain.elasticsearch[0].endpoint]"), (["FLOAT", "EPLUS"], "0.e"), (["FLOAT", "EPLUS"], "1.e+"), (["NUMBER", "EPLUS"], "0e"), diff --git a/tests/test_load_dump.py b/tests/test_load_dump.py new file mode 100644 index 0000000..5984541 --- /dev/null +++ b/tests/test_load_dump.py @@ -0,0 +1,99 @@ +# +# These tests are taken from hcl/parse_test.go +# + +from __future__ import print_function + +from os.path import join, dirname +import hcl +import json + +import pytest + +PARSE_FIXTURE_DIR = join(dirname(__file__), 'lex-fixtures') +PARSE_FIXTURES = [ + ( + "assign_colon.hcl", + False, + ), + ( + "comment.hcl", + False, + ), + ( + "list_comma.hcl", + False, + ), + ( + "list_of_maps.hcl", + False, + ), + ( + "multiple.hcl", + False, + ), + ( + "structure.hcl", + False, + ), + ( + "structure_basic.hcl", + False, + ), + ( + "structure_empty.hcl", + False, + ), + ( + "complex.hcl", + False, + ), + ( + "assign_deep.hcl", + False, + ), + ( + "types.hcl", + False, + ), + ( + "structure_comma.hcl", + False, + ), + ( + "terraform0.12syntax.hcl", + False, + ), + ( + "conditional_operator.hcl", + False, + ), +] + +@pytest.mark.parametrize("hcl_fname,invalid", PARSE_FIXTURES) +def test_parser_bytes(hcl_fname, invalid): + + with open(join(PARSE_FIXTURE_DIR, hcl_fname), 'rb') as fp: + + input = fp.read() + print(input) + + if not invalid: + hcl.loads(input) + else: + with pytest.raises(ValueError): + hcl.loads(input) + +@pytest.mark.parametrize("hcl_fname,invalid", PARSE_FIXTURES) +def test_parser_str(hcl_fname, invalid): + + with open(join(PARSE_FIXTURE_DIR, hcl_fname), 'r') as fp: + + input = fp.read() + print(input) + + if not invalid: + hcl.loads(input) + else: + with pytest.raises(ValueError): + hcl.loads(input) diff --git a/tests/test_parser.py b/tests/test_parser.py index 56e3b71..5984541 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -14,7 +14,7 @@ PARSE_FIXTURES = [ ( "assign_colon.hcl", - True, + False, ), ( "comment.hcl", @@ -60,6 +60,14 @@ "structure_comma.hcl", False, ), + ( + "terraform0.12syntax.hcl", + False, + ), + ( + "conditional_operator.hcl", + False, + ), ] @pytest.mark.parametrize("hcl_fname,invalid", PARSE_FIXTURES)