# Eggshell runtime library # # Copyright (C) 2016 Patrick "P. J." McDermott # # This file is part of the Eggshell Compiler. # # The Eggshell Compiler 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 Compiler 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 Compiler If not, see # . use nostack __ESC="$(printf '\033.')"; __ESC="${__ESC%.}" __RS="$(printf '\036.')"; __RS="${__RS%.}" __US="$(printf '\037.')"; __US="${__US%.}" __sp=0 __fn_name='' __fn_tu='' __fn_vars='' __fn='' __prev_tu='' __prev_vars='' __var='' __val='' __fn_frame=0 __paramc='' __paramv='' __param='' __i=0 __err=false __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}" } __frame_get() { eval "__fn_name=\${__frame_${__sp}_name}" eval "__fn_tu=\${__frame_${__sp}_tu}" eval "__fn_vars=\${__frame_${__sp}_vars}" } __fn_ctxsw() { unset IFS case "${__prev_tu}" in ${__fn_tu});; ?*) # Unset static variables and functions from previous TU. eval "__val=\${__${__prev_tu}_static_vars}" case "${__val}" in ?*) eval "unset \${__${__prev_tu}_static_vars}" ;; esac eval "__val=\${__${__prev_tu}_static_fns}" for __fn in ${__val}; do unset -f "${__fn%:*}" done ;; esac case "${__fn_tu}" in ${__prev_tu});; ?*) # Set static variables and function for the current TU. eval "__val=\${__${__fn_tu}_static_var_vals}" eval "${__val}" eval "__val=\${__${__fn_tu}_static_fns}" for __fn in ${__val}; do eval "${__fn%:*}() { ${__fn#*:}; }" done ;; esac case "${__prev_vars}" in ?*) unset ${__prev_vars} ;; esac for __var in ${__fn_vars}; do eval "${__var}=\${__fn_vars_${__sp}_${__var}}" done } __fn_update_vars() { unset IFS for __var in ${__fn_vars}; do eval "__fn_vars_${__sp}_${__var}=\${${__var}}" done } __fn_start() { # Hooks. unset IFS for __fn in ${__fn_begin_hooks}; do ${__fn} ${2} done # Update local vars in stack. __fn_update_vars __frame_set # Old state. __prev_tu="${__fn_tu}" __prev_vars="${__fn_vars}" # Set stack pointer. __sp_inc # New state. __fn_name="${2}" __fn_tu="${1}" __fn_vars= __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 local 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 } __check_args() { __fn="${1}" __paramc="${2}" __paramv="${3}" shift 3 if [ ${#} -ne ${__paramc} ]; then printf 'Error: Incorrect number of arguments to function %s\n' \ "${__fn_name}()" >&2 exit 1 fi unset IFS __i=0 for __param in ${__paramv}; do __i=$((${__i} + 1)) __err=false case "${__param%:*}" in 'bool') case "${1}" in 'true'|'false');; *) __err=true;; esac ;; 'int') case "${1}" in *[!0-9]*) __err=true;; esac ;; esac if ${__err}; then printf 'Error: Argument %d of %s() %s (%s %s)\n' \ ${__i} "${__fn_name}" 'has incorrect type' \ 'expecting' "${__param%:*}" >&2 exit 1 else __local "${__param#*:}=${1}" fi shift 1 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}" }