{
    "scopeName": "source.dtl",
    "patterns": [
        { "include": "#dtl_entry" },
        { "include": "#dtl_single_entry" }
    ],
    "repository": {
        "dtl_entry": {
            "begin": "\"(?=\\(:)",
            "end": "(?<=:\\))\"",
            "name": "keyword.bracket.dtl.happytag",
            "patterns": [
                { "include": "#dtl_happy_tags" }
            ]
        },
        "dtl_single_entry": {
            "begin": "'(?=\\(:)",
            "end": "(?<=:\\))'",
            "name": "keyword.bracket.dtl.happytag",
            "patterns": [
                { "include": "#dtl_happy_tags" }
            ]
        },
        "dtl_happy_tags": {
            "name": "meta.interpolation.dtl",
            "begin": "(\\(:)",
            "end": ":\\)(?=[\"'`])",
            "beginCaptures": {
                "0": {
                "name": "punctuation.section.interpolation.begin.dtl "
                }
            },
            "endCaptures": { 
                "0": { "name": "punctuation.section.interpolation.end.dtl" }
            },
            "patterns": [

                { "include": "#dtl_expression" }
            ]
        },
        "dtl_expression": {
            "name": "meta.interpolation.dtl",
            "patterns": [
                { "include": "#dtl_error_happy_tags" },
                { "include": "#dtl_common_elements" }
            ]
        },
        "dtl_error_happy_tags": {
            "patterns": [
                {
                    "match": "(?<![\"'`])\\(:",
                    "name": "invalid.illegal.missing-quote-before-happytag.dtl"
                },
                {
                    "match": ":\\)",
                    "name": "invalid.illegal.missing-quote-after-happytag.dtl"
                }
            ]
        },
        "dtl_sub_single": {
            "name": "meta.interpolation.dtl",
            "begin": "'(\\(:)",
            "end": "(:\\))'",
            "beginCaptures": {
                "0": {
                "name": "keyword.bracket.happytag.begin.dtl punctuation.section.interpolation.begin.dtl "
                }
            },
            "endCaptures": { 
                "0": { "name": "keyword.bracket.happytag.end.dtl punctuation.section.interpolation.end.dtl" }
            },
            "patterns": [
                { "include": "#dtl_expression" }
            ]
        },
        "dtl_sub_backtick": {
            "name": "meta.interpolation.dtl",
            "begin": "`(\\(:)",
            "end": "(:\\))`",
            "beginCaptures": {
                "0": {
                "name": "keyword.bracket.happytag.begin.dtl punctuation.section.interpolation.begin.dtl "
                }
            },
            "endCaptures": { 
                "0": { "name": "keyword.bracket.happytag.end.dtl punctuation.section.interpolation.end.dtl" }
            },
            "patterns": [
                { "include": "#dtl_expression" }
            ]
        },
        "dtl_common_elements": {
            "patterns": [
                { "include": "#dtl_comments" },
                { "include": "#dtl_helper" },
                { "include": "#dtl_braces" },
                { "include": "#dtl_numbers" },
                { "include": "#dtl_sub_single"},
                { "include": "#dtl_sub_backtick"},
                { "include": "#dtl_strings" },     
                { "include": "#dtl_transform_shortcut" },
                { "include": "#dtl_operators" },
                { "include": "#dtl_boolean" },
                { "include": "#dtl_undef" },            
                { "include": "#dtl_variable" },
                { "include": "#dtl_variable_dot_attributes" },
                { "include": "#dtl_parenthesized" },
                { "include": "#dtl_barewords" }

            ]
        },
        "dtl_containers": {
            "patterns": [
                
                { "include": "#dtl_expression" },
                { "include": "#dtl_helper" }
            ]
        },
        "dtl_numbers": {
            "patterns": [
                { "include": "#dtl_number_alternate_base" },
                { "include": "#dtl_number_int" },
                { "include": "#dtl_number_decimal" }
            ]
        },
        "dtl_number_int": {
            "name": "constant.numeric.integer.dtl",
            "match": "[\\+\\-]?[0-9]+"
        },
        "dtl_number_decimal": {
            "name": "constant.numeric.float.decimal.dtl",
            "match": "[\\+\\-]?(\\d+\\.\\d*|\\.\\d+)([eE][\\+\\-]?\\d+)?"
        },
        "dtl_number_alternate_base": { 
            "name": "constant.numeric.dtl",
            "patterns": [
                { 
                    "name": "constant.numeric.octal.dtl",
                    "match": "0o[0-7]+"
                },
                {   
                    "name": "constant.numeric.binary.dtl",
                    "match": "0b[0-1]+"
                },
                {             
                    "name": "constant.numeric.hex.dtl",
                    "match": "0x[0-9a-fA-F]+"
                }
            ]
        },
        "dtl_strings": {
            "patterns": [
                { "include": "#dtl_string_single" },
                { "include": "#dtl_string_backtick" }
            ]
        },
        "dtl_string_single":  {
            "begin": "'",
            "end": "'",
            "name": "entity.other.string.single.dtl"
        },
        "dtl_string_backtick":  {
            "begin": "`",
            "end": "`",
            "name": "entity.other.string.single.dtl"
        },
        "dtl_transform_shortcut": { 
            "match": "(\\-\\>)\\s*['`]?([a-zA-Z0-9_\\.]+)['`]?",
            "captures": {
                "1": {
                "name": "punctuation.separator.method.period.dtl keyword.operator.arrow.dtl"
                },
                "2": {
                "name": "storage.type.function.dtl meta.function-call"
                }
                
            }
        },
        "dtl_operators": {
            "name": "keyword.operator",
            "patterns": [
                { 
                    "name": "keyword.operator.comparison.dtl",
                    "match": "(>|<|=>|<=|!=|==|<=>)"
                },
                { 
                    "name": "keyword.operator.logical.dtl",
                    "match": "(\\|\\||&&)"
                },
                { 
                   "name": "keyword.operator.dtl",
                   "match": "[!+\\-\\/*\\|&]"
                }
            ]
            
        },
        "dtl_boolean": {
            "name": "constant.language.dtl.boolean",
            "match": "(true|false)"
        },
        "dtl_undef": {
            "name": "constant.language.dtl.undef",
            "match": "(undef|undefined)"
        },
        "dtl_helper": {
            "begin": "([a-zA-Z0-9_#&\\?@\\^]+)\\(",
            "end": "(\\))",
            "beginCaptures": {
                "0": {
                "name": "support.function.dtl"
                }
            },
            "endCaptures": {
                "0": {
                "name": "support.function.dtl"
                }
            },
            "patterns": [
                {  
                    "name": "invalid.illegal.comma",
                    "match": ","
                },
                { "include": "#dtl_common_elements" }
            ]
        },
        "dtl_barewords": {
            "name": "invalid.illegal.character_not_allowed_here",
            "match": "\\w+"
        },
        "dtl_comments": {
            "patterns": [
                {
                    "name": "comment.block.dtl",
                    "begin": "(/\\*)",
                    "end": "(\\*/)"
                },
                {
                    "contentName": "comment.line.double-slash.dtl",
                    "begin": "(//)",
                    "end": "(?=:\\)|$)",
                    "beginCaptures": {
                        "0": {
                        "name": "comment.line.double-slash.dtl"
                        }
                    }
                }
            ]
        },
        "dtl_braces": {
            "patterns": [
                { "include": "#dtl_curly_braces" },
                { "include": "#dtl_square_brackets" }
            ]
        },
        "dtl_curly_braces": {
                "contentName": "meta.structure.dictionary",
                "begin": "({)",
                "end": "(})",
                "beginCaptures": {
                    "0": {
                    "name": "keyword.bracket.begin.curly.dtl punctuation.definition.dictionary.begin"
                    }
                },
                "endCaptures": { 
                    "0": { "name": "keyword.bracket.end.curly.dtl puctuation.definition.dictionary.end" }
                },
                "patterns": [
                    { "include": "#dtl_common_elements" }
                ]
        },
        "dtl_square_brackets": {
                "contentName": "meta.structure.list",
                "begin": "(\\[)",
                "end": "(\\])",
                "beginCaptures": {
                    "0": {
                    "name": "keyword.bracket.begin.dtl punctuation.definition.list.begin"
                    }
                },
                "endCaptures": { 
                    "0": { "name": "keyword.bracket.end.dtl puctuation.definition.list.end" }
                },
                "patterns": [
                    { "include": "#dtl_common_elements" }
                ]
        },

        "dtl_parenthesized": {
                "name": "meta.expression.parenthesized",
                "begin": "\\((?![:]|\\))",
                "end": "(?<![:])\\)",
                "patterns": [
                    { "include": "#dtl_common_elements" },
                    { 
                        "name": "invalid.illegal.comma",
                        "match": ","
                    }
                ]
        },
        "dtl_variable": {
            "name": "variable.other.dtl",
            "match": "\\$(\\.?[a-zA-Z0-9_])+"
        },
        "dtl_variable_dot_attributes": {
           "name": "variable.other.dtl",
           "match": "(?<=[\\)\\]])(\\.[a-zA-Z0-9_]+)"
        }
        
    }
}