Skip to content

Instantly share code, notes, and snippets.

@alganet
Created August 19, 2022 10:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alganet/c4647a6de06d5edc5c81803e5c6e0ef5 to your computer and use it in GitHub Desktop.
Save alganet/c4647a6de06d5edc5c81803e5c6e0ef5 to your computer and use it in GitHub Desktop.
Portable shell script cargo typing and runtime expression parsing experiment
set -euf
PATH=
IFS=
_r=
_v=0 # variable counter
_f=1 # scopedion namespace
_x=0 # parser namespace
! command -v emulate >/dev/null 2>&1 || emulate ksh >/dev/null 2>&1
command -v local >/dev/null 2>&1 || alias local=typeset
xp () {
test -n "${1:-}" || return 1
test "$1" = '[' || set -- [ "$@" ]
while test $# -gt 0
do
if test "$1" = '['
then _x=$(($_x + 1))
elif test "$1" = ']'
then
test "$_x" -gt 0 || return 1
eval "eval \"\$_x_$_x\"; _x=$(($_x - 1))"
eval "_x_$_x=\"$_r\""
unset "_x_"$((_x + 1))
else
case "$1" in
'@'*) val "${1#"@"}";;
'n'*) num "${1#"n"}";;
*) _r="$1";;
esac
eval "_x_$_x=\"\${_x_$_x:-}$_r \""
fi
shift
done
if test "$_x" = 0
then unset _x_0
elif test "$_x" = 1 && test "$_r" = $((_x_$_x))
then unset _x_1
else return 1
fi
}
## FLOW CONTROL
_shift_xp () {
shift $1;
xp "$@"
}
var () {
_r=
_shift_xp 3 "$@"
val_usage "$_r" +1
eval "_f$_f=\"\${_f$_f:- }$1 \""
eval "$1='$_r'"
}
scoped () {
_f="$((_f + 1))"
eval "_f$_f=;_f${_f}l=${_v:-0}"
}
result () {
_r=${1:-$_r}
_gc_uvars
_gc_scope $_r
_f="$((_f - 1))"
}
## GARBAGE COLLECTION
_gc_val () {
if eval test \"\${_${1}r:-0}\" = 0
then val_invoke "$1" destroy
fi
}
_gc_uvars () {
IFS=' '
eval "set -- \$_f$_f"
IFS=''
while test $# -gt 0
do eval val_usage "\$$1" -1; shift
done
unset "_f$_f"
}
_gc_scope () {
local _vlow _vhigh
eval "_vlow=\${_f${_f}l:-0}; _vhigh=\$((_v - _vlow))"
while test $_vhigh -gt $_vlow
do
test "$_vhigh" = "$1" || _gc_val "$_vhigh"
_vhigh=$((_vhigh - 2))
done
unset "_f${_f}l"
}
## TYPES
val_invoke () {
local method="$2" vid="$1"
shift 2
eval "eval \"\\\${_\$(($vid - 1)):-seq}_$method $vid \\\"\\\$@\\\"\""
}
val_usage () {
eval "_${1}r=\$((\${_${1}r:-} + $2))"
}
val_destroy () {
unset "_${1}" "_${1}r" "_$(($1 - 1))"
}
val () {
_v=$((_v + 1))
eval "_$_v='val'"
_v=$((_v + 1))
eval "_$_v='$1'"
_r="$_v"
}
num () {
_v=$((_v + 1))
eval "_$_v='num'"
_v=$((_v + 1))
eval "_$_v='$1'"
_r="$_v"
}
num_destroy () {
val_destroy "$@"
}
seq () {
_v=$((_v + 2))
eval "_$_v=''"
_r="$_v"
while test $# -gt 0
do seq_push $_v $1; shift
done
}
seq_destroy () {
local _name="$1"
IFS=' '
eval "set -- \$_$1"
IFS=''
while test $# -gt 0
do val_usage "$1" -1; shift
done
val_destroy $_name
}
seq_push () {
val_usage "$2" +1
eval "_$1=\"\${_$1:- }$2 \""
}
hello () {
scoped
local greetings greetings2
var greetings = seq @"Hello " n10 $1
var greetings2 = seq @"Hello " n15 $1
result $greetings
return
}
var zoid = hello @"Alexandre"
result $zoid
set
eval : $_r \$_$_r
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment