# Eggshell runtime library # # Copyright (C) 2016 Patrick "P. J." McDermott # # This file is part of the Eggshell Linker. # # The Eggshell Linker is free software: you can redistribute it # and/or modify it under the terms of the GNU General Public License # as published by the Free Software Foundation, either version 3 of # the License, or (at your option) any later version. # # The Eggshell Linker is distributed in the hope that it will be # useful, but WITHOUT ANY WARRANTY; without even the implied warranty # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with the Eggshell Linker If not, see # . eshrtbegin() { cat <<-'EOF' __ESC="$(printf '\033.')"; __ESC="${__ESC%.}" __RS="$(printf '\036.')"; __RS="${__RS%.}" __US="$(printf '\037.')"; __US="${__US%.}" __sp=0 __fn_name='' __fn_tu='' __fn_vars='' __fn_var_vals='' __fn='' __prev_tu='' __prev_vars='' __var='' __val='' __fn_frame=0 __fn_begin_hooks='' __fn_end_hooks='' __init_funcs='' __sp_inc() { __sp=$((${__sp} + 1)) } __sp_dec() { __sp=$((${__sp} - 1)) } __frame_set() { eval "__frame_${__sp}_name=\${__fn_name}" eval "__frame_${__sp}_tu=\${__fn_tu}" eval "__frame_${__sp}_vars=\${__fn_vars}" eval "__frame_${__sp}_var_vals=\${__fn_var_vals}" } __frame_get() { eval "__fn_name=\${__frame_${__sp}_name}" eval "__fn_tu=\${__frame_${__sp}_tu}" eval "__fn_vars=\${__frame_${__sp}_vars}" eval "__fn_var_vals=\${__frame_${__sp}_var_vals}" } __fn_ctxsw() { unset IFS case "${__prev_tu}" in ${__fn_tu});; ?*) # Unset static variables and functions from previous TU. case "$(eval "printf '%s' \ \"\${__${__prev_tu}_static_vars}\"")" \ in ?*) eval "unset \${__${__prev_tu}_static_vars}" ;; esac 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 case "${__prev_vars}" in ?*) unset ${__prev_vars} ;; esac eval "${__fn_var_vals}" } __fn_update_vars() { unset IFS 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() { # Hooks. unset IFS for __fn in ${__fn_begin_hooks}; do ${__fn} ${2} done # Old state. __prev_tu="${__fn_tu}" __prev_vars="${__fn_vars}" # Update local vars in stack. __fn_update_vars __frame_set # Set stack pointer. __sp_inc # New state. __fn_name="${2}" __fn_tu="${1}" __fn_vars= __fn_var_vals= __frame_set # Switch. __fn_ctxsw } __fn_end() { # Hooks. unset IFS for __fn in ${__fn_end_hooks}; do ${__fn} ${__fn_name} done # Old state. __prev_tu="${__fn_tu}" __prev_vars="${__fn_vars}" # Set stack pointer. __sp_dec # New state. __frame_get # Switch. __fn_ctxsw } __tu_end() { # Save TU static vars. unset IFS 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() { __fn_frame=0 while [ ${__fn_frame} -le ${__sp} ]; do eval "printf '%s\n' \"\${__frame_${__fn_frame}_name}\"" __fn_frame=$((${__fn_frame} + 1)) done } __local() { unset IFS 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 unset IFS 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 } __fn_begin_hook() { __fn_begin_hooks="${__fn_begin_hooks} ${1}" } __fn_end_hook() { __fn_end_hooks="${__fn_end_hooks} ${1}" } __init() { __init_funcs="${__init_funcs} ${1}" } EOF } eshrtend() { local entry="${1}" shift 1 cat <<-'EOF' unset IFS for __func in ${__init_funcs}; do ${__func} done EOF printf '%s "${@}"\n' "${entry_point}" }