summaryrefslogtreecommitdiffstats
path: root/research/research4.sh
diff options
context:
space:
mode:
Diffstat (limited to 'research/research4.sh')
-rw-r--r--research/research4.sh323
1 files changed, 323 insertions, 0 deletions
diff --git a/research/research4.sh b/research/research4.sh
new file mode 100644
index 0000000..9ef3bf0
--- /dev/null
+++ b/research/research4.sh
@@ -0,0 +1,323 @@
+set -eu
+__ESC="$(printf '\033.')"; __ESC="${__ESC%.}"
+ __RS="$(printf '\036.')"; __RS="${__RS%.}"
+ __US="$(printf '\037.')"; __US="${__US%.}"
+__fn_stack=
+__fn_frame=
+__fn_name=
+__fn_tu=
+__fn_vars=
+__fn_var_vals=
+__fn=
+__prev_tu=
+__prev_vars=
+__var=
+__val=
+
+__fn_stack_push()
+{
+ __fn_stack="${__fn_stack}${__RS}${__fn_frame}"
+}
+
+__fn_stack_peek()
+{
+ __fn_frame="${__fn_stack##*${__RS}}"
+}
+
+__fn_stack_pop()
+{
+ __fn_stack_peek
+ __fn_stack="${__fn_stack%${__RS}*}"
+}
+
+__fn_frame_encode()
+{
+ # RS and US in frame variable values must be encoded.
+ __fn_var_vals="$(printf '%s' "${__fn_var_vals}" | sed "
+ s|${__ESC}|${__ESC}0|g;
+ s|${__RS}|${__ESC}1|g; s|${__US}|${__ESC}2|g;
+ ")"
+ __fn_frame="${__fn_name}${__US}${__fn_tu}"
+ __fn_frame="${__fn_frame}${__US}${__fn_vars}${__US}${__fn_var_vals}"
+}
+
+__fn_frame_decode()
+{
+ __fn_name="${__fn_frame%%${__US}*}"
+ __fn_frame="${__fn_frame#*${__US}}"
+ __fn_tu="${__fn_frame%%${__US}*}"
+ __fn_frame="${__fn_frame#*${__US}}"
+ __fn_vars="${__fn_frame%%${__US}*}"
+ __fn_var_vals="${__fn_frame#*${__US}}"
+ __fn_var_vals="$(printf '%s' "${__fn_var_vals}" | sed "
+ s|${__ESC}0|${__ESC}|g;
+ s|${__ESC}1|${__RS}|g; s|${__ESC}2|${__US}|g;
+ ")"
+}
+
+__fn_ctxsw()
+{
+ unset IFS
+ case "${__prev_tu}" in
+ ${__fn_tu});;
+ ?*)
+ # Unset static variables and functions from previous TU.
+ eval "unset \${__${__prev_tu}_static_vars}"
+ for __fn in $(eval printf '%s' \
+ "\"\${__${__prev_tu}_static_fns}\""); do
+ unset -f "${__fn%:*}"
+ done
+ ;; esac
+ case "${__fn_tu}" in
+ ${__prev_tu});;
+ ?*)
+ # Set static variables and function for the current TU.
+ eval "$(eval printf '%s' "\"$(eval printf '%s' \
+ "'\${__${__fn_tu}_static_var_vals}'")\"")"
+ for __fn in $(eval printf '%s' \
+ "\"\${__${__fn_tu}_static_fns}\""); do
+ eval "${__fn%:*}() { ${__fn#*:}; }"
+ done
+ ;; esac
+ unset ${__prev_vars}
+ eval "${__fn_var_vals}"
+}
+
+__fn_update_vars()
+{
+ for __var in ${__fn_vars}; do
+ __val="$(eval "printf '%s' \"\${${__var}}\"" | \
+ sed "s|'|'\\\\''|g;")"
+ __fn_var_vals="${__fn_var_vals} ${__var}='${__val}'"
+ done
+}
+
+__fn_start()
+{
+ # Old state.
+ __prev_tu="${__fn_tu}"
+ __prev_vars="${__fn_vars}"
+
+ # Update local vars in stack.
+ __fn_stack_pop
+ __fn_vars="${__prev_vars}"
+ __fn_update_vars
+ __fn_frame_encode
+ __fn_stack_push
+
+ # New state.
+ __fn_name="${2}"
+ __fn_tu="${1}"
+ __fn_vars=
+ __fn_var_vals=
+ __fn_frame_encode
+ __fn_stack_push
+
+ # Switch.
+ __fn_ctxsw
+}
+
+__fn_end()
+{
+ # Old state.
+ __fn_stack_pop
+ __fn_frame_decode
+ __prev_tu="${__fn_tu}"
+ __prev_vars="${__fn_vars}"
+
+ # New state.
+ __fn_stack_peek
+ __fn_frame_decode
+
+ # Switch.
+ __fn_ctxsw
+}
+
+__tu_end()
+{
+ # Save TU static vars.
+ for __var in $(eval "printf '%s' \"\${__${__tu}_static_vars}\""); do
+ __val="$(eval "printf '%s' \"\${${__var}}\"" | \
+ sed "s|'|'\\\\''|g")"
+ eval "__${__tu}_static_var_vals=\"\${__${__tu}_static_var_vals}\
+ ${__var}='\${__val}'\""
+ unset ${__var}
+ done
+
+ __tu=''
+}
+
+__stack_trace()
+{
+ IFS="${__RS}"
+ for __fn_frame in ${__fn_stack#${__RS}}; do
+ printf '%s\n' "${__fn_frame%%${__US}*}"
+ done
+}
+
+__local()
+{
+ for __var in "${@}"; do
+ case "${__var}" in
+ *=*)
+ __val="${__var#*=}"
+ __var="${__var%%=*}"
+ ;;
+ *)
+ __val=''
+ ;;
+ esac
+ case "${__var}" in [!A-Za-z_]* | *[!0-9A-Za-z_]*)
+ printf 'Syntax error: %s %s\n' \
+ 'illegal static variable name:' "${__var}" >&2
+ exit 1
+ ;; esac
+ eval "${__var}=\${__val}"
+ __fn_vars="${__fn_vars} ${__var}"
+ done
+}
+
+static()
+{
+ case "${__tu}" in '')
+ printf 'Error: Cannot declare static variables in functions' >&2
+ exit 1
+ ;; esac
+ for __var in "${@}"; do
+ case "${__var}" in
+ *=*)
+ __val="${__var#*=}"
+ __var="${__var%%=*}"
+ ;;
+ *)
+ __val=''
+ ;;
+ esac
+ case "${__var}" in [!A-Za-z_]* | *[!0-9A-Za-z_]*)
+ printf 'Syntax error: %s %s\n' \
+ 'illegal static variable name:' "${__var}" >&2
+ exit 1
+ ;; esac
+ eval "${__var}=\${__val}"
+ eval "__${__tu}_static_vars=\"\${__${__tu}_static_vars} \
+ ${__var}\""
+ done
+}
+
+EOF(){ :; }
+
+#: <<'EOF'
+################################################################################
+# Stack trace test
+################################################################################
+__tu=tu0
+__tu0_static_vars=
+__tu0_static_var_vals=
+__tu0_static_fns=
+
+a(){ __fn_start tu0 a; b; __fn_end; }
+b(){ __fn_start tu0 b; c; __fn_end; }
+c(){ __fn_start tu0 c; printf 'Stack trace:\n';
+ printf ' * %s()\n' $(__stack_trace); __fn_end; }
+a
+
+__tu_end
+EOF
+
+: <<'EOF'
+################################################################################
+# TU 0
+################################################################################
+__tu=tu0
+__tu0_static_vars=
+__tu0_static_var_vals=
+__tu0_static_fns=
+
+static v=1
+
+foo()
+{
+ __fn_start tu0 foo
+
+ echo "v (should be 1): $v"
+
+ __fn_end
+}
+
+__tu_end
+
+################################################################################
+# TU 1
+################################################################################
+__tu=tu1
+__tu1_static_vars=
+__tu1_static_var_vals=
+__tu1_static_fns=
+
+bar()
+{
+ __fn_start tu1 bar
+
+ echo "v (should not be 1): $v"
+ foo
+ echo "v (should not be 1): $v"
+
+ __fn_end
+}
+
+__tu_end
+
+bar
+EOF
+
+: <<'EOF'
+################################################################################
+# TU 0
+################################################################################
+__tu=tu0
+__tu0_static_vars=
+__tu0_static_var_vals=
+__tu0_static_fns=
+
+a()
+{
+ __fn_start tu0 a
+ __local v=1
+ echo "v (should be 1): $v"
+ b
+ echo "v (should be 1): $v"
+ __fn_end
+}
+
+b()
+{
+ __fn_start tu0 b
+ echo "v (should be empty): $v"
+ __fn_end
+}
+
+__tu_end
+
+a
+EOF
+
+: <<'EOF'
+################################################################################
+# TU 0
+################################################################################
+__tu=tu0
+__tu0_static_vars=
+__tu0_static_var_vals=
+__tu0_static_fns=
+
+a()
+{
+ __fn_start tu0 a
+ static v=1
+ __fn_end
+}
+
+__tu_end
+
+a
+EOF