diff --git a/CHANGES b/CHANGES index d74fe4c8a0..eaf4273499 100644 --- a/CHANGES +++ b/CHANGES @@ -11,6 +11,7 @@ Version 2.14.0 * GAP session (#2211) * func (#2232) + * Jsonnet (#2239) * MIPS (#2228) * Phix (#2222) * World of Warcraft TOC format (#2244) diff --git a/pygments/lexers/_mapping.py b/pygments/lexers/_mapping.py index 540b3f934d..a1248d6861 100644 --- a/pygments/lexers/_mapping.py +++ b/pygments/lexers/_mapping.py @@ -238,6 +238,7 @@ 'JsonBareObjectLexer': ('pygments.lexers.data', 'JSONBareObject', (), (), ()), 'JsonLdLexer': ('pygments.lexers.data', 'JSON-LD', ('jsonld', 'json-ld'), ('*.jsonld',), ('application/ld+json',)), 'JsonLexer': ('pygments.lexers.data', 'JSON', ('json', 'json-object'), ('*.json', 'Pipfile.lock'), ('application/json', 'application/json-object')), + 'JsonnetLexer': ('pygments.lexers.jsonnet', 'Jsonnet', ('jsonnet',), ('*.jsonnet', '*.libsonnet'), ()), 'JspLexer': ('pygments.lexers.templates', 'Java Server Page', ('jsp',), ('*.jsp',), ('application/x-jsp',)), 'JuliaConsoleLexer': ('pygments.lexers.julia', 'Julia console', ('jlcon', 'julia-repl'), (), ()), 'JuliaLexer': ('pygments.lexers.julia', 'Julia', ('julia', 'jl'), ('*.jl',), ('text/x-julia', 'application/x-julia')), diff --git a/pygments/lexers/jsonnet.py b/pygments/lexers/jsonnet.py new file mode 100644 index 0000000000..356191fe33 --- /dev/null +++ b/pygments/lexers/jsonnet.py @@ -0,0 +1,178 @@ +""" + pygments.lexers.jsonnet + ~~~~~~~~~~~~~~~~~~~~~~~ + + Lexer for Jsonnet data templating language. + + :copyright: Copyright 2006-2022 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" +from pygments.lexer import ( + include, + RegexLexer, + words, +) +from pygments.token import ( + Comment, + Keyword, + Name, + Number, + Operator, + Punctuation, + String, + Text, + Whitespace, +) + +__all__ = ['JsonnetLexer'] + +jsonnet_token = r'[^\W\d]\w*' +jsonnet_function_token = jsonnet_token + r'(?=\()' + + +def string_rules(quote_mark): + return [ + (r"[^{}\\]".format(quote_mark), String), + (r"\\.", String.Escape), + (quote_mark, String, '#pop'), + ] + + +def quoted_field_name(quote_mark): + return [ + (r'([^{quote}\\]|\\.)*{quote}'.format(quote=quote_mark), + Name.Variable, 'field_separator') + ] + + +class JsonnetLexer(RegexLexer): + name = 'Jsonnet' + aliases = ['jsonnet'] + filenames = ['*.jsonnet', '*.libsonnet'] + url = "https://jsonnet.org" + tokens = { + # Not used by itself + '_comments': [ + (r'(//|#).*\n', Comment.Single), + (r'/\*\*([^/]|/(?!\*))*\*/', String.Doc), + (r'/\*([^/]|/(?!\*))*\*/', Comment), + ], + 'root': [ + include('_comments'), + (r"@'.*'", String), + (r'@".*"', String), + (r"'", String, 'singlestring'), + (r'"', String, 'doublestring'), + (r'\|\|\|(.|\n)*\|\|\|', String), + # Jsonnet has no integers, only an IEEE754 64-bit float + (r'[+-]?[0-9]+(.[0-9])?', Number.Float), + # Omit : despite spec because it appears to be used as a field + # separator + (r'[!$~+\-&|^=<>*/%]', Operator), + (r'\{', Punctuation, 'object'), + (r'\[', Punctuation, 'array'), + (r'local\b', Keyword, ('local_name')), + (r'assert\b', Keyword, 'assert'), + (words([ + 'assert', 'else', 'error', 'false', 'for', 'if', 'import', + 'importstr', 'in', 'null', 'tailstrict', 'then', 'self', + 'super', 'true', + ], suffix=r'\b'), Keyword), + (r'\s+', Whitespace), + (r'function(?=\()', Keyword, 'function_params'), + (r'std\.' + jsonnet_function_token, Name.Builtin, 'function_args'), + (jsonnet_function_token, Name.Function, 'function_args'), + (jsonnet_token, Name.Variable), + (r'[\.()]', Punctuation), + ], + 'singlestring': string_rules("'"), + 'doublestring': string_rules('"'), + 'array': [ + (r',', Punctuation), + (r'\]', Punctuation, '#pop'), + include('root'), + ], + 'local_name': [ + (jsonnet_function_token, Name.Function, 'function_params'), + (jsonnet_token, Name.Variable), + (r'\s+', Whitespace), + ('(?==)', Whitespace, ('#pop', 'local_value')), + ], + 'local_value': [ + (r'=', Operator), + (r';', Punctuation, '#pop'), + include('root'), + ], + 'assert': [ + (r':', Punctuation), + (r';', Punctuation, '#pop'), + include('root'), + ], + 'function_params': [ + (jsonnet_token, Name.Variable), + (r'\(', Punctuation), + (r'\)', Punctuation, '#pop'), + (r',', Punctuation), + (r'\s+', Whitespace), + (r'=', Operator, 'function_param_default'), + ], + 'function_args': [ + (r'\(', Punctuation), + (r'\)', Punctuation, '#pop'), + (r',', Punctuation), + (r'\s+', Whitespace), + include('root'), + ], + 'object': [ + (r'\s+', Whitespace), + (r'local\b', Keyword, 'object_local_name'), + (r'assert\b', Keyword, 'object_assert'), + (r'\[', Operator, 'field_name_expr'), + (fr'(?={jsonnet_token})', Text, 'field_name'), + (r'\}', Punctuation, '#pop'), + (r'"', Name.Variable, 'double_field_name'), + (r"'", Name.Variable, 'single_field_name'), + include('_comments'), + ], + 'field_name': [ + (jsonnet_function_token, Name.Function, + ('field_separator', 'function_params') + ), + (jsonnet_token, Name.Variable, 'field_separator'), + ], + 'double_field_name': quoted_field_name('"'), + 'single_field_name': quoted_field_name("'"), + 'field_name_expr': [ + (r'\]', Operator, 'field_separator'), + include('root'), + ], + 'function_param_default': [ + (r'(?=[,\)])', Whitespace, '#pop'), + include('root'), + ], + 'field_separator': [ + (r'\s+', Whitespace), + (r'\+?::?:?', Punctuation, ('#pop', '#pop', 'field_value')), + include('_comments'), + ], + 'field_value': [ + (r',', Punctuation, '#pop'), + (r'\}', Punctuation, '#pop:2'), + include('root'), + ], + 'object_assert': [ + (r':', Punctuation), + (r',', Punctuation, '#pop'), + include('root'), + ], + 'object_local_name': [ + (jsonnet_token, Name.Variable, ('#pop', 'object_local_value')), + (r'\s+', Whitespace), + ], + 'object_local_value': [ + (r'=', Operator), + (r',', Punctuation, '#pop'), + (r'\}', Punctuation, '#pop:2'), + include('root'), + ], + } diff --git a/tests/examplefiles/jsonnet/example.jsonnet b/tests/examplefiles/jsonnet/example.jsonnet new file mode 100644 index 0000000000..74e2e45993 --- /dev/null +++ b/tests/examplefiles/jsonnet/example.jsonnet @@ -0,0 +1,74 @@ +/* Multiline / +comment */ +local x = 100; +/* Multiline +comment */ + +/** + * Docs + **/ + + +local i = import 'foo'; +local foo = 'bar'; +local lambda = function(foo, bar) ['baz', 'qux']; +local named(foo, bar=10, baz=20) = ['baz', 'qux']; +local in1troduction = 'introduction'; +assert 5 > 3: "interesting"; +//comment +{ + local foo = "bar", + spam: 'eggs', +} + +{local foo = "bar"} + + +{ + // this is a comment + # python-style comment + assert 1 == 1: 'huh?', + spam: 'eggs // /* #', + spam2(foo, bar):: 2, + spa: 'eggs', + foo: 'bar', + block: ||| + Hello + Block + |||, + baz: 'qux' + 'fuzz', + 'm:oo': 'cow', + "b:oo": ('cow'), + goo: ['bar', 'ba\nz'], + spam3: 2.25, + spam4::: -2.25, + spam5::: +2.25, + spam6//funky + : 'hello' //moo + , //moo + ['spa\'m']: 'eggs', + ["spa\"m2"]: "eggs", + raw1: @'hello\', + raw2: @"hello\", + spam7: foo, + spam8: lambda(1, 2), + spam9: self.spam2(3, 4), + intro: in1troduction, + spam_10: 10, + spam_11(y=10):: 11, + spam12: std.type('null'), + spam13+: 27, + spam14: $.spam13, + spam15: ~5, + spam16: !false, + spam17: 0 - 5, + spam18: 5 & 3, + spam19: 5 | 3, + spam20: 5 ^ 3, + spam21: 5 == 3, + spam22: 5 < 3, + spam23: 5 > 3, + spam24: 5 * 3, + spam25: 5 / 3, + spam26: 5 % 3, +} diff --git a/tests/examplefiles/jsonnet/example.jsonnet.output b/tests/examplefiles/jsonnet/example.jsonnet.output new file mode 100644 index 0000000000..3b98523e59 --- /dev/null +++ b/tests/examplefiles/jsonnet/example.jsonnet.output @@ -0,0 +1,697 @@ +'/* Multiline /\ncomment */' Comment +'\n' Text.Whitespace + +'local' Keyword +' ' Text.Whitespace +'x' Name.Variable +' ' Text.Whitespace +'' Text.Whitespace +'=' Operator +' ' Text.Whitespace +'100' Literal.Number.Float +';' Punctuation +'\n' Text.Whitespace + +'/* Multiline\ncomment */' Comment +'\n\n' Text.Whitespace + +'/**\n * Docs\n **/' Literal.String.Doc +'\n\n\n' Text.Whitespace + +'local' Keyword +' ' Text.Whitespace +'i' Name.Variable +' ' Text.Whitespace +'' Text.Whitespace +'=' Operator +' ' Text.Whitespace +'import' Keyword +' ' Text.Whitespace +"'" Literal.String +'f' Literal.String +'o' Literal.String +'o' Literal.String +"'" Literal.String +';' Punctuation +'\n' Text.Whitespace + +'local' Keyword +' ' Text.Whitespace +'foo' Name.Variable +' ' Text.Whitespace +'' Text.Whitespace +'=' Operator +' ' Text.Whitespace +"'" Literal.String +'b' Literal.String +'a' Literal.String +'r' Literal.String +"'" Literal.String +';' Punctuation +'\n' Text.Whitespace + +'local' Keyword +' ' Text.Whitespace +'lambda' Name.Variable +' ' Text.Whitespace +'' Text.Whitespace +'=' Operator +' ' Text.Whitespace +'function' Keyword +'(' Punctuation +'foo' Name.Variable +',' Punctuation +' ' Text.Whitespace +'bar' Name.Variable +')' Punctuation +' ' Text.Whitespace +'[' Punctuation +"'" Literal.String +'b' Literal.String +'a' Literal.String +'z' Literal.String +"'" Literal.String +',' Punctuation +' ' Text.Whitespace +"'" Literal.String +'q' Literal.String +'u' Literal.String +'x' Literal.String +"'" Literal.String +']' Punctuation +';' Punctuation +'\n' Text.Whitespace + +'local' Keyword +' ' Text.Whitespace +'named' Name.Function +'(' Punctuation +'foo' Name.Variable +',' Punctuation +' ' Text.Whitespace +'bar' Name.Variable +'=' Operator +'10' Literal.Number.Float +'' Text.Whitespace +',' Punctuation +' ' Text.Whitespace +'baz' Name.Variable +'=' Operator +'20' Literal.Number.Float +'' Text.Whitespace +')' Punctuation +' ' Text.Whitespace +'' Text.Whitespace +'=' Operator +' ' Text.Whitespace +'[' Punctuation +"'" Literal.String +'b' Literal.String +'a' Literal.String +'z' Literal.String +"'" Literal.String +',' Punctuation +' ' Text.Whitespace +"'" Literal.String +'q' Literal.String +'u' Literal.String +'x' Literal.String +"'" Literal.String +']' Punctuation +';' Punctuation +'\n' Text.Whitespace + +'local' Keyword +' ' Text.Whitespace +'in1troduction' Name.Variable +' ' Text.Whitespace +'' Text.Whitespace +'=' Operator +' ' Text.Whitespace +"'" Literal.String +'i' Literal.String +'n' Literal.String +'t' Literal.String +'r' Literal.String +'o' Literal.String +'d' Literal.String +'u' Literal.String +'c' Literal.String +'t' Literal.String +'i' Literal.String +'o' Literal.String +'n' Literal.String +"'" Literal.String +';' Punctuation +'\n' Text.Whitespace + +'assert' Keyword +' ' Text.Whitespace +'5' Literal.Number.Float +' ' Text.Whitespace +'>' Operator +' ' Text.Whitespace +'3' Literal.Number.Float +':' Punctuation +' ' Text.Whitespace +'"' Literal.String +'i' Literal.String +'n' Literal.String +'t' Literal.String +'e' Literal.String +'r' Literal.String +'e' Literal.String +'s' Literal.String +'t' Literal.String +'i' Literal.String +'n' Literal.String +'g' Literal.String +'"' Literal.String +';' Punctuation +'\n' Text.Whitespace + +'//comment\n' Comment.Single + +'{' Punctuation +'\n ' Text.Whitespace +'local' Keyword +' ' Text.Whitespace +'foo' Name.Variable +' ' Text.Whitespace +'=' Operator +' ' Text.Whitespace +'"' Literal.String +'b' Literal.String +'a' Literal.String +'r' Literal.String +'"' Literal.String +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam' Name.Variable +':' Punctuation +' ' Text.Whitespace +"'" Literal.String +'e' Literal.String +'g' Literal.String +'g' Literal.String +'s' Literal.String +"'" Literal.String +',' Punctuation +'\n' Text.Whitespace + +'}' Punctuation +'\n\n' Text.Whitespace + +'{' Punctuation +'local' Keyword +' ' Text.Whitespace +'foo' Name.Variable +' ' Text.Whitespace +'=' Operator +' ' Text.Whitespace +'"' Literal.String +'b' Literal.String +'a' Literal.String +'r' Literal.String +'"' Literal.String +'}' Punctuation +'\n\n\n' Text.Whitespace + +'{' Punctuation +'\n ' Text.Whitespace +'// this is a comment\n' Comment.Single + +' ' Text.Whitespace +'# python-style comment\n' Comment.Single + +' ' Text.Whitespace +'assert' Keyword +' ' Text.Whitespace +'1' Literal.Number.Float +' ' Text.Whitespace +'=' Operator +'=' Operator +' ' Text.Whitespace +'1' Literal.Number.Float +':' Punctuation +' ' Text.Whitespace +"'" Literal.String +'h' Literal.String +'u' Literal.String +'h' Literal.String +'?' Literal.String +"'" Literal.String +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam' Name.Variable +':' Punctuation +' ' Text.Whitespace +"'" Literal.String +'e' Literal.String +'g' Literal.String +'g' Literal.String +'s' Literal.String +' ' Literal.String +'/' Literal.String +'/' Literal.String +' ' Literal.String +'/' Literal.String +'*' Literal.String +' ' Literal.String +'#' Literal.String +"'" Literal.String +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam2' Name.Function +'(' Punctuation +'foo' Name.Variable +',' Punctuation +' ' Text.Whitespace +'bar' Name.Variable +')' Punctuation +'::' Punctuation +' ' Text.Whitespace +'2' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spa' Name.Variable +':' Punctuation +' ' Text.Whitespace +"'" Literal.String +'e' Literal.String +'g' Literal.String +'g' Literal.String +'s' Literal.String +"'" Literal.String +',' Punctuation +'\n ' Text.Whitespace +'' Text +'foo' Name.Variable +':' Punctuation +' ' Text.Whitespace +"'" Literal.String +'b' Literal.String +'a' Literal.String +'r' Literal.String +"'" Literal.String +',' Punctuation +'\n ' Text.Whitespace +'' Text +'block' Name.Variable +':' Punctuation +' ' Text.Whitespace +'|||\n Hello\n Block\n |||' Literal.String +',' Punctuation +'\n ' Text.Whitespace +'' Text +'baz' Name.Variable +':' Punctuation +' ' Text.Whitespace +"'" Literal.String +'q' Literal.String +'u' Literal.String +'x' Literal.String +"'" Literal.String +' ' Text.Whitespace +'+' Operator +' ' Text.Whitespace +"'" Literal.String +'f' Literal.String +'u' Literal.String +'z' Literal.String +'z' Literal.String +"'" Literal.String +',' Punctuation +'\n ' Text.Whitespace +"'" Name.Variable +"m:oo'" Name.Variable +':' Punctuation +' ' Text.Whitespace +"'" Literal.String +'c' Literal.String +'o' Literal.String +'w' Literal.String +"'" Literal.String +',' Punctuation +'\n ' Text.Whitespace +'"' Name.Variable +'b:oo"' Name.Variable +':' Punctuation +' ' Text.Whitespace +'(' Punctuation +"'" Literal.String +'c' Literal.String +'o' Literal.String +'w' Literal.String +"'" Literal.String +')' Punctuation +',' Punctuation +'\n ' Text.Whitespace +'' Text +'goo' Name.Variable +':' Punctuation +' ' Text.Whitespace +'[' Punctuation +"'" Literal.String +'b' Literal.String +'a' Literal.String +'r' Literal.String +"'" Literal.String +',' Punctuation +' ' Text.Whitespace +"'" Literal.String +'b' Literal.String +'a' Literal.String +'\\n' Literal.String.Escape +'z' Literal.String +"'" Literal.String +']' Punctuation +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam3' Name.Variable +':' Punctuation +' ' Text.Whitespace +'2.2' Literal.Number.Float +'5' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam4' Name.Variable +':::' Punctuation +' ' Text.Whitespace +'-2.2' Literal.Number.Float +'5' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam5' Name.Variable +':::' Punctuation +' ' Text.Whitespace +'+2.2' Literal.Number.Float +'5' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam6' Name.Variable +'//funky\n' Comment.Single + +' ' Text.Whitespace +':' Punctuation +' ' Text.Whitespace +"'" Literal.String +'h' Literal.String +'e' Literal.String +'l' Literal.String +'l' Literal.String +'o' Literal.String +"'" Literal.String +' ' Text.Whitespace +'//moo\n' Comment.Single + +' ' Text.Whitespace +',' Punctuation +' ' Text.Whitespace +'//moo\n' Comment.Single + +' ' Text.Whitespace +'[' Operator +"'" Literal.String +'s' Literal.String +'p' Literal.String +'a' Literal.String +"\\'" Literal.String.Escape +'m' Literal.String +"'" Literal.String +']' Operator +':' Punctuation +' ' Text.Whitespace +"'" Literal.String +'e' Literal.String +'g' Literal.String +'g' Literal.String +'s' Literal.String +"'" Literal.String +',' Punctuation +'\n ' Text.Whitespace +'[' Operator +'"' Literal.String +'s' Literal.String +'p' Literal.String +'a' Literal.String +'\\"' Literal.String.Escape +'m' Literal.String +'2' Literal.String +'"' Literal.String +']' Operator +':' Punctuation +' ' Text.Whitespace +'"' Literal.String +'e' Literal.String +'g' Literal.String +'g' Literal.String +'s' Literal.String +'"' Literal.String +',' Punctuation +'\n ' Text.Whitespace +'' Text +'raw1' Name.Variable +':' Punctuation +' ' Text.Whitespace +"@'hello\\'" Literal.String +',' Punctuation +'\n ' Text.Whitespace +'' Text +'raw2' Name.Variable +':' Punctuation +' ' Text.Whitespace +'@"hello\\"' Literal.String +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam7' Name.Variable +':' Punctuation +' ' Text.Whitespace +'foo' Name.Variable +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam8' Name.Variable +':' Punctuation +' ' Text.Whitespace +'lambda' Name.Function +'(' Punctuation +'1' Literal.Number.Float +',' Punctuation +' ' Text.Whitespace +'2' Literal.Number.Float +')' Punctuation +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam9' Name.Variable +':' Punctuation +' ' Text.Whitespace +'self' Keyword +'.' Punctuation +'spam2' Name.Function +'(' Punctuation +'3' Literal.Number.Float +',' Punctuation +' ' Text.Whitespace +'4' Literal.Number.Float +')' Punctuation +',' Punctuation +'\n ' Text.Whitespace +'' Text +'intro' Name.Variable +':' Punctuation +' ' Text.Whitespace +'in1troduction' Name.Variable +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam_10' Name.Variable +':' Punctuation +' ' Text.Whitespace +'10' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam_11' Name.Function +'(' Punctuation +'y' Name.Variable +'=' Operator +'10' Literal.Number.Float +'' Text.Whitespace +')' Punctuation +'::' Punctuation +' ' Text.Whitespace +'11' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam12' Name.Variable +':' Punctuation +' ' Text.Whitespace +'std.type' Name.Builtin +'(' Punctuation +"'" Literal.String +'n' Literal.String +'u' Literal.String +'l' Literal.String +'l' Literal.String +"'" Literal.String +')' Punctuation +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam13' Name.Variable +'+:' Punctuation +' ' Text.Whitespace +'27' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam14' Name.Variable +':' Punctuation +' ' Text.Whitespace +'$' Operator +'.' Punctuation +'spam13' Name.Variable +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam15' Name.Variable +':' Punctuation +' ' Text.Whitespace +'~' Operator +'5' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam16' Name.Variable +':' Punctuation +' ' Text.Whitespace +'!' Operator +'false' Keyword +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam17' Name.Variable +':' Punctuation +' ' Text.Whitespace +'0' Literal.Number.Float +' ' Text.Whitespace +'-' Operator +' ' Text.Whitespace +'5' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam18' Name.Variable +':' Punctuation +' ' Text.Whitespace +'5' Literal.Number.Float +' ' Text.Whitespace +'&' Operator +' ' Text.Whitespace +'3' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam19' Name.Variable +':' Punctuation +' ' Text.Whitespace +'5' Literal.Number.Float +' ' Text.Whitespace +'|' Operator +' ' Text.Whitespace +'3' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam20' Name.Variable +':' Punctuation +' ' Text.Whitespace +'5' Literal.Number.Float +' ' Text.Whitespace +'^' Operator +' ' Text.Whitespace +'3' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam21' Name.Variable +':' Punctuation +' ' Text.Whitespace +'5' Literal.Number.Float +' ' Text.Whitespace +'=' Operator +'=' Operator +' ' Text.Whitespace +'3' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam22' Name.Variable +':' Punctuation +' ' Text.Whitespace +'5' Literal.Number.Float +' ' Text.Whitespace +'<' Operator +' ' Text.Whitespace +'3' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam23' Name.Variable +':' Punctuation +' ' Text.Whitespace +'5' Literal.Number.Float +' ' Text.Whitespace +'>' Operator +' ' Text.Whitespace +'3' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam24' Name.Variable +':' Punctuation +' ' Text.Whitespace +'5' Literal.Number.Float +' ' Text.Whitespace +'*' Operator +' ' Text.Whitespace +'3' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam25' Name.Variable +':' Punctuation +' ' Text.Whitespace +'5' Literal.Number.Float +' ' Text.Whitespace +'/' Operator +' ' Text.Whitespace +'3' Literal.Number.Float +',' Punctuation +'\n ' Text.Whitespace +'' Text +'spam26' Name.Variable +':' Punctuation +' ' Text.Whitespace +'5' Literal.Number.Float +' ' Text.Whitespace +'%' Operator +' ' Text.Whitespace +'3' Literal.Number.Float +',' Punctuation +'\n' Text.Whitespace + +'}' Punctuation +'\n' Text.Whitespace