From 16acd51be446ac1e73d629dd9b96992057abb5e2 Mon Sep 17 00:00:00 2001 From: Richard van Velzen Date: Fri, 24 Feb 2023 10:34:01 +0100 Subject: [PATCH] Improve bash math expansion lexing --- pygments/lexers/shell.py | 6 +- .../singularity/Singularity.output | 2 +- tests/snippets/shell/test_math.txt | 675 ++++++++++++++++++ 3 files changed, 680 insertions(+), 3 deletions(-) create mode 100644 tests/snippets/shell/test_math.txt diff --git a/pygments/lexers/shell.py b/pygments/lexers/shell.py index d3fb8a11a6..db0eaf8efb 100644 --- a/pygments/lexers/shell.py +++ b/pygments/lexers/shell.py @@ -105,10 +105,12 @@ class BashLexer(RegexLexer): ], 'math': [ (r'\)\)', Keyword, '#pop'), - (r'[-+*/%^|&]|\*\*|\|\|', Operator), - (r'\d+#\d+', Number), + (r'\*\*|\|\|<<|>>|[-+*/%^|&<>]', Operator), + (r'\d+#[\da-zA-Z]+', Number), (r'\d+#(?! )', Number), + (r'0x[\da-zA-Z]+', Number), (r'\d+', Number), + (r'[a-zA-Z_]\w*', Name.Variable), # user variable include('root'), ], 'backticks': [ diff --git a/tests/examplefiles/singularity/Singularity.output b/tests/examplefiles/singularity/Singularity.output index 5fe858b093..cbaec958a2 100644 --- a/tests/examplefiles/singularity/Singularity.output +++ b/tests/examplefiles/singularity/Singularity.output @@ -301,7 +301,7 @@ 'NOW' Name.Variable '=' Operator '$((' Keyword -'date' Text +'date' Name.Variable ' ' Text.Whitespace '%' Operator ' ' Text.Whitespace diff --git a/tests/snippets/shell/test_math.txt b/tests/snippets/shell/test_math.txt new file mode 100644 index 0000000000..334f10c342 --- /dev/null +++ b/tests/snippets/shell/test_math.txt @@ -0,0 +1,675 @@ +---input--- +# TODO: Find git dir; global options +# TODO: LIBEXECDIR or something +GIT_DIR="${GIT_DIR:-.git}" + +INDEX_VERSION=2 + +gitsort() ( + # This will still often be wrong + LANG=C sort +) + +# Is it hacky? Hell yes. Is it POSIX? HELL YES. +write_hex() { + hex="$1" + while [ -n "$hex" ] + do + cur=$(printf "%s" "$hex" | cut -c1-2) + next=$(printf "%s" "$hex" | cut -c3-) + printf "\\x$(printf "%s" "$cur")" + hex="$next" + done +} + +# Prints an integer to stdout in binary, big-endian +write_int32() ( + n="$1" + hex=$(printf "%08X" "$n") + write_hex "$hex" +) + +write_int16() ( + n="$1" + hex=$(printf "%04X" "$n") + write_hex "$hex" +) + +read_text() ( + path="$1" + offs="$2" + len="$3" + for oct in $(od -An -txC -N"$len" -j"$offs" "$index") + do + printf "\x$oct" + done +) + +read_int16() ( + path="$1" + offs="$2" + i16=$(od -An -tdS -j"$offs" -N2 "$path" | tr -d ' ') + i16=$((((i16>>8)&0xff) | ((i16<<8)&0xff00))) + echo "$i16" +) + +read_int32() ( + path="$1" + offs="$2" + i32=$(od -An -tdI -j"$offs" -N4 "$path" | tr -d ' ') + i32=$((((i32>>24)&0xff) | + ((i32<<8)&0xff0000) | + ((i32>>8)&0xff00) | + ((i32<<24)&0xff000000))) + echo "$i32" +) + +read_hex() ( + path="$1" + offs="$2" + len="$3" + od -An -txC -N"$len" -j"$offs" "$path" | tr -d ' \n' +) + +normalize_path() ( + path="$1" + path="${path#./}" + # TODO: Remove the leading / if fully qualified + if [ "${path#.git}" != "$path" ] + then + printf '%s' 'Invalid path %s\n' "$path" + exit 1 + fi + printf "%s" "$path" +) + +---tokens--- +'# TODO: Find git dir; global options\n' Comment.Single + +'# TODO: LIBEXECDIR or something\n' Comment.Single + +'GIT_DIR' Name.Variable +'=' Operator +'"' Literal.String.Double +'${' Literal.String.Interpol +'GIT_DIR' Name.Variable +':-' Keyword +'.git' Punctuation +'}' Literal.String.Interpol +'"' Literal.String.Double +'\n\n' Text.Whitespace + +'INDEX_VERSION' Name.Variable +'=' Operator +'2' Literal.Number +'\n\n' Text.Whitespace + +'gitsort' Text +'(' Operator +')' Operator +' ' Text.Whitespace +'(' Operator +'\n\t' Text.Whitespace +'# This will still often be wrong\n' Comment.Single + +'\t' Text.Whitespace +'LANG' Name.Variable +'=' Operator +'C' Text +' ' Text.Whitespace +'sort' Text +'\n' Text.Whitespace + +')' Operator +'\n\n' Text.Whitespace + +'# Is it hacky? Hell yes. Is it POSIX? HELL YES.\n' Comment.Single + +'write_hex' Text +'(' Operator +')' Operator +' ' Text.Whitespace +'{' Operator +'\n\t' Text.Whitespace +'hex' Name.Variable +'=' Operator +'"' Literal.String.Double +'$1' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'while' Keyword +' ' Text.Whitespace +'[' Operator +' ' Text.Whitespace +'-n' Text +' ' Text.Whitespace +'"' Literal.String.Double +'$hex' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +']' Operator +'\n\t' Text.Whitespace +'do' Keyword +'\n\t\t' Text.Whitespace +'cur' Name.Variable +'=' Operator +'$(' Keyword +'printf' Name.Builtin +' ' Text.Whitespace +'"%s"' Literal.String.Double +' ' Text.Whitespace +'"' Literal.String.Double +'$hex' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +'|' Punctuation +' ' Text.Whitespace +'cut' Text +' ' Text.Whitespace +'-c1-2' Text +')' Keyword +'\n\t\t' Text.Whitespace +'next' Name.Variable +'=' Operator +'$(' Keyword +'printf' Name.Builtin +' ' Text.Whitespace +'"%s"' Literal.String.Double +' ' Text.Whitespace +'"' Literal.String.Double +'$hex' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +'|' Punctuation +' ' Text.Whitespace +'cut' Text +' ' Text.Whitespace +'-c3-' Text +')' Keyword +'\n\t\t' Text.Whitespace +'printf' Name.Builtin +' ' Text.Whitespace +'"' Literal.String.Double +'\\\\x' Literal.String.Double +'$(' Keyword +'printf' Name.Builtin +' ' Text.Whitespace +'"%s"' Literal.String.Double +' ' Text.Whitespace +'"' Literal.String.Double +'$cur' Name.Variable +'"' Literal.String.Double +')' Keyword +'"' Literal.String.Double +'\n\t\t' Text.Whitespace +'hex' Name.Variable +'=' Operator +'"' Literal.String.Double +'$next' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'done' Keyword +'\n' Text.Whitespace + +'}' Operator +'\n\n' Text.Whitespace + +'# Prints an integer to stdout in binary, big-endian\n' Comment.Single + +'write_int32' Text +'(' Operator +')' Operator +' ' Text.Whitespace +'(' Operator +'\n\t' Text.Whitespace +'n' Name.Variable +'=' Operator +'"' Literal.String.Double +'$1' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'hex' Name.Variable +'=' Operator +'$(' Keyword +'printf' Name.Builtin +' ' Text.Whitespace +'"%08X"' Literal.String.Double +' ' Text.Whitespace +'"' Literal.String.Double +'$n' Name.Variable +'"' Literal.String.Double +')' Keyword +'\n\t' Text.Whitespace +'write_hex' Text +' ' Text.Whitespace +'"' Literal.String.Double +'$hex' Name.Variable +'"' Literal.String.Double +'\n' Text.Whitespace + +')' Operator +'\n\n' Text.Whitespace + +'write_int16' Text +'(' Operator +')' Operator +' ' Text.Whitespace +'(' Operator +'\n\t' Text.Whitespace +'n' Name.Variable +'=' Operator +'"' Literal.String.Double +'$1' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'hex' Name.Variable +'=' Operator +'$(' Keyword +'printf' Name.Builtin +' ' Text.Whitespace +'"%04X"' Literal.String.Double +' ' Text.Whitespace +'"' Literal.String.Double +'$n' Name.Variable +'"' Literal.String.Double +')' Keyword +'\n\t' Text.Whitespace +'write_hex' Text +' ' Text.Whitespace +'"' Literal.String.Double +'$hex' Name.Variable +'"' Literal.String.Double +'\n' Text.Whitespace + +')' Operator +'\n\n' Text.Whitespace + +'read_text' Text +'(' Operator +')' Operator +' ' Text.Whitespace +'(' Operator +'\n\t' Text.Whitespace +'path' Name.Variable +'=' Operator +'"' Literal.String.Double +'$1' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'offs' Name.Variable +'=' Operator +'"' Literal.String.Double +'$2' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'len' Name.Variable +'=' Operator +'"' Literal.String.Double +'$3' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'for' Keyword +' ' Text.Whitespace +'oct' Text +' ' Text.Whitespace +'in' Keyword +' ' Text.Whitespace +'$(' Keyword +'od' Text +' ' Text.Whitespace +'-An' Text +' ' Text.Whitespace +'-txC' Text +' ' Text.Whitespace +'-N' Text +'"' Literal.String.Double +'$len' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +'-j' Text +'"' Literal.String.Double +'$offs' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +'"' Literal.String.Double +'$index' Name.Variable +'"' Literal.String.Double +')' Keyword +'\n\t' Text.Whitespace +'do' Keyword +'\n\t\t' Text.Whitespace +'printf' Name.Builtin +' ' Text.Whitespace +'"' Literal.String.Double +'\\x' Literal.String.Double +'$oct' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'done' Keyword +'\n' Text.Whitespace + +')' Operator +'\n\n' Text.Whitespace + +'read_int16' Text +'(' Operator +')' Operator +' ' Text.Whitespace +'(' Operator +'\n\t' Text.Whitespace +'path' Name.Variable +'=' Operator +'"' Literal.String.Double +'$1' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'offs' Name.Variable +'=' Operator +'"' Literal.String.Double +'$2' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'i16' Name.Variable +'=' Operator +'$(' Keyword +'od' Text +' ' Text.Whitespace +'-An' Text +' ' Text.Whitespace +'-tdS' Text +' ' Text.Whitespace +'-j' Text +'"' Literal.String.Double +'$offs' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +'-N2' Text +' ' Text.Whitespace +'"' Literal.String.Double +'$path' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +'|' Punctuation +' ' Text.Whitespace +'tr' Text +' ' Text.Whitespace +'-d' Text +' ' Text.Whitespace +"' '" Literal.String.Single +')' Keyword +'\n\t' Text.Whitespace +'i16' Name.Variable +'=' Operator +'$((' Keyword +'(' Operator +'(' Operator +'i16' Name.Variable +'>>' Operator +'8' Literal.Number +')' Operator +'&' Operator +'0xff' Literal.Number +')' Operator +' ' Text.Whitespace +'|' Operator +' ' Text.Whitespace +'(' Operator +'(' Operator +'i16' Name.Variable +'<' Operator +'<' Operator +'8' Literal.Number +')' Operator +'&' Operator +'0xff00' Literal.Number +'))' Keyword +')' Operator +'\n\t' Text.Whitespace +'echo' Name.Builtin +' ' Text.Whitespace +'"' Literal.String.Double +'$i16' Name.Variable +'"' Literal.String.Double +'\n' Text.Whitespace + +')' Operator +'\n\n' Text.Whitespace + +'read_int32' Text +'(' Operator +')' Operator +' ' Text.Whitespace +'(' Operator +'\n\t' Text.Whitespace +'path' Name.Variable +'=' Operator +'"' Literal.String.Double +'$1' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'offs' Name.Variable +'=' Operator +'"' Literal.String.Double +'$2' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'i32' Name.Variable +'=' Operator +'$(' Keyword +'od' Text +' ' Text.Whitespace +'-An' Text +' ' Text.Whitespace +'-tdI' Text +' ' Text.Whitespace +'-j' Text +'"' Literal.String.Double +'$offs' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +'-N4' Text +' ' Text.Whitespace +'"' Literal.String.Double +'$path' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +'|' Punctuation +' ' Text.Whitespace +'tr' Text +' ' Text.Whitespace +'-d' Text +' ' Text.Whitespace +"' '" Literal.String.Single +')' Keyword +'\n\t' Text.Whitespace +'i32' Name.Variable +'=' Operator +'$((' Keyword +'(' Operator +'(' Operator +'i32' Name.Variable +'>>' Operator +'24' Literal.Number +')' Operator +'&' Operator +'0xff' Literal.Number +')' Operator +' ' Text.Whitespace +'|' Operator +'\n\t\t' Text.Whitespace +'(' Operator +'(' Operator +'i32' Name.Variable +'<' Operator +'<' Operator +'8' Literal.Number +')' Operator +'&' Operator +'0xff0000' Literal.Number +')' Operator +' ' Text.Whitespace +'|' Operator +'\n\t\t' Text.Whitespace +'(' Operator +'(' Operator +'i32' Name.Variable +'>>' Operator +'8' Literal.Number +')' Operator +'&' Operator +'0xff00' Literal.Number +')' Operator +' ' Text.Whitespace +'|' Operator +'\n\t\t' Text.Whitespace +'(' Operator +'(' Operator +'i32' Name.Variable +'<' Operator +'<' Operator +'24' Literal.Number +')' Operator +'&' Operator +'0xff000000' Literal.Number +'))' Keyword +')' Operator +'\n\t' Text.Whitespace +'echo' Name.Builtin +' ' Text.Whitespace +'"' Literal.String.Double +'$i32' Name.Variable +'"' Literal.String.Double +'\n' Text.Whitespace + +')' Operator +'\n\n' Text.Whitespace + +'read_hex' Text +'(' Operator +')' Operator +' ' Text.Whitespace +'(' Operator +'\n\t' Text.Whitespace +'path' Name.Variable +'=' Operator +'"' Literal.String.Double +'$1' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'offs' Name.Variable +'=' Operator +'"' Literal.String.Double +'$2' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'len' Name.Variable +'=' Operator +'"' Literal.String.Double +'$3' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'od' Text +' ' Text.Whitespace +'-An' Text +' ' Text.Whitespace +'-txC' Text +' ' Text.Whitespace +'-N' Text +'"' Literal.String.Double +'$len' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +'-j' Text +'"' Literal.String.Double +'$offs' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +'"' Literal.String.Double +'$path' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +'|' Punctuation +' ' Text.Whitespace +'tr' Text +' ' Text.Whitespace +'-d' Text +' ' Text.Whitespace +"' \\n'" Literal.String.Single +'\n' Text.Whitespace + +')' Operator +'\n\n' Text.Whitespace + +'normalize_path' Text +'(' Operator +')' Operator +' ' Text.Whitespace +'(' Operator +'\n\t' Text.Whitespace +'path' Name.Variable +'=' Operator +'"' Literal.String.Double +'$1' Name.Variable +'"' Literal.String.Double +'\n\t' Text.Whitespace +'path' Name.Variable +'=' Operator +'"' Literal.String.Double +'${' Literal.String.Interpol +'path' Name.Variable +'#./' Punctuation +'}' Literal.String.Interpol +'"' Literal.String.Double +'\n\t' Text.Whitespace +'# TODO: Remove the leading / if fully qualified\n' Comment.Single + +'\t' Text.Whitespace +'if' Keyword +' ' Text.Whitespace +'[' Operator +' ' Text.Whitespace +'"' Literal.String.Double +'${' Literal.String.Interpol +'path' Name.Variable +'#.git' Punctuation +'}' Literal.String.Interpol +'"' Literal.String.Double +' ' Text.Whitespace +'!' Text +'=' Operator +' ' Text.Whitespace +'"' Literal.String.Double +'$path' Name.Variable +'"' Literal.String.Double +' ' Text.Whitespace +']' Operator +'\n\t' Text.Whitespace +'then' Keyword +'\n\t\t' Text.Whitespace +'printf' Name.Builtin +' ' Text.Whitespace +"'%s'" Literal.String.Single +' ' Text.Whitespace +"'Invalid path %s\\n'" Literal.String.Single +' ' Text.Whitespace +'"' Literal.String.Double +'$path' Name.Variable +'"' Literal.String.Double +'\n\t\t' Text.Whitespace +'exit' Name.Builtin +' ' Text.Whitespace +'1' Literal.Number +'\n\t' Text.Whitespace +'fi' Keyword +'\n\t' Text.Whitespace +'printf' Name.Builtin +' ' Text.Whitespace +'"%s"' Literal.String.Double +' ' Text.Whitespace +'"' Literal.String.Double +'$path' Name.Variable +'"' Literal.String.Double +'\n' Text.Whitespace + +')' Operator +'\n' Text.Whitespace