diff options
Diffstat (limited to 'eshld/eshrt.esh')
-rw-r--r-- | eshld/eshrt.esh | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/eshld/eshrt.esh b/eshld/eshrt.esh new file mode 100644 index 0000000..0a6fdb7 --- /dev/null +++ b/eshld/eshrt.esh @@ -0,0 +1,248 @@ +# Eggshell Linker 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 +# <http://www.gnu.org/licenses/>. + +eshrtbegin() +{ + cat <<-'EOF' +__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='' +__init_funcs='' + +__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 +} + +__init() +{ + __init_funcs="${__init_funcs} ${1}" +} +EOF +} + +eshrtend() +{ + local entry="${1}" + shift 1 + + cat <<-'EOF' +for __func in ${__init_funcs}; do + ${__func} +done +EOF + printf '%s "${@}"\n' "${entry_point}" +} |