#!/bin/bash warn() { echo "$@" >&2 } die() { echo "$@" >&2 exit 3 } content_desc() { local c=$1 case $c in \ ) echo space ;; \!) echo exclamation mark ;; \$) echo dollar sign ;; \&) echo ampersand ;; \() echo opening bracket ;; \)) echo closing bracket ;; \*) echo asterisk ;; \;) echo semicolon ;; \?) echo question mark ;; \\) echo backslash ;; \`) echo tick mark;; \>) echo greater than ;; \<) echo less than ;; \{) echo opening curly brace ;; \|) echo pipe symbol ;; \}) echo closing curly brace ;; BS) echo backslash ;; SQ) echo single quote ;; DQ) echo double quote ;; TAB) echo tab ;; ES) echo empty string ;; NL) echo newline ;; A) echo letter A ;; esac } mode_name() { local mode=$1 case $mode in bs) echo backslash escaping ;; sq) echo single quoting ;; dq) echo double quoting ;; esac } mktest() { local mode=$1; shift local mode_name local content_desc mode_name="$(mode_name "$mode")" local c local self=$0 printf 'test "parse: %s (generated)" {\n' "$mode_name" printf ' // TEST GENERATED BY %s\n' "$self" #shellcheck disable=SC2016 for c in "$@"; do content_desc="$(content_desc "$c")" # every backslash needs to be doubled because of printf. # some backslashes need to be doubled again becase of syntax (eg. `"\\\\" is 2 backslashes in Zig) case $mode:$c in bs:BS) printf ' try parse_t("\\\\\\\\", Result{ .tokens = &.{"\\\\"} }); // %s `\\` (%s)\n' "$mode_name" "$content_desc" ;; bs:DQ) printf ' try parse_t("\\\\\\"", Result{ .tokens = &.{"\\""} }); // %s `"` (%s)\n' "$mode_name" "$content_desc" ;; bs:ES) true ;; # impossible case bs:NL) printf ' try parse_t("\\\\\\n", Result{ .tokens = &.{"\\n"} }); // %s `\\n` (%s)\n' "$mode_name" "$content_desc" ;; bs:SQ) printf ' try parse_t("\\\\%s", Result{ .tokens = &.{"%s"} }); // %s `%s` (%s)\n' "'" "'" "$mode_name" "'" "$content_desc" ;; bs:TAB) printf ' try parse_t("\\\\\\t", Result{ .tokens = &.{"\\t"} }); // %s `\\t` (%s)\n' "$mode_name" "$content_desc" ;; bs:*) printf ' try parse_t("\\\\%s", Result{ .tokens = &.{"%s"} }); // %s `%s` (%s)\n' "$c" "$c" "$mode_name" "$c" "$content_desc" ;; sq:NL) printf ' try parse_t("%s\\n%s", Result{ .tokens = &.{"\\n"} }); // %s `\\n` (%s)\n' "'" "'" "$mode_name" "$content_desc" ;; sq:TAB) printf ' try parse_t("%s\\t%s", Result{ .tokens = &.{"\\t"} }); // %s `\\t` (%s)\n' "'" "'" "$mode_name" "$content_desc" ;; sq:DQ) printf ' try parse_t("%s\\"%s", Result{ .tokens = &.{"\\""} }); // %s `"` (%s)\n' "'" "'" "$mode_name" "$content_desc" ;; sq:ES) printf ' try parse_t("%s%s", Result{ .tokens = &.{""} }); // %s `\\` (%s)\n' "'" "'" "$mode_name" "$content_desc" ;; sq:BS) printf ' try parse_t("%s\\\\%s", Result{ .tokens = &.{"\\\\"} }); // %s `\\` (%s)\n' "'" "'" "$mode_name" "$content_desc" ;; sq:SQ) true ;; # impossible case sq:*) printf ' try parse_t("'"'"'%s'"'"'", Result{ .tokens = &.{"%s"} }); // %s `%s` (%s)\n' "$c" "$c" "$mode_name" "$c" "$content_desc" ;; dq:BS) printf ' try parse_t("\\"\\\\\\\\\\"", Result{ .tokens = &.{"\\\\"} }); // %s `\\` (%s)\n' "$mode_name" "$content_desc" ;; dq:DQ) printf ' try parse_t("\\"\\\\\\"\\"", Result{ .tokens = &.{"\\""} }); // %s `"` (%s)\n' "$mode_name" "$content_desc" ;; dq:ES) printf ' try parse_t("\\"\\"", Result{ .tokens = &.{""} }); // %s `\\` (%s)\n' "$mode_name" "$content_desc" ;; dq:NL) printf ' try parse_t("\\"\\n\\"", Result{ .tokens = &.{"\\n"} }); // %s `\\n` (%s)\n' "$mode_name" "$content_desc" ;; dq:SQ) printf ' try parse_t("\\"%s\\"", Result{ .tokens = &.{"%s"} }); // %s `%s` (%s)\n' "'" "'" "$mode_name" "'" "$content_desc" ;; dq:TAB) printf ' try parse_t("\\"\\t\\"", Result{ .tokens = &.{"\\t"} }); // %s `\\t` (tab)\n' "$mode_name" ;; dq:*) printf ' try parse_t("\\"%s\\"", Result{ .tokens = &.{"%s"} }); // %s `%s` (%s)\n' "$c" "$c" "$mode_name" "$c" "$content_desc" ;; *) die "unknown character or mode: c=$c mode=$mode" ;; esac done printf '}\n' echo } main() { local cases=( '!' '$' '&' '(' ')' '*' ';' '?' '`' '{' '>' '<' '|' '}' ' ' SQ DQ BS TAB NL ES A ) mktest bs "${cases[@]}" mktest sq "${cases[@]}" mktest dq "${cases[@]}" } main "$@"