diff options
author | Peter Stephenson <pws@zsh.org> | 2016-06-21 16:34:55 +0100 |
---|---|---|
committer | Peter Stephenson <pws@zsh.org> | 2016-06-21 16:34:55 +0100 |
commit | 5103c85abb239a12a3d29da9b41515cd4af19a9f (patch) | |
tree | eb5e729b2d2c06274c8a08eaf332beb9a72f7abc /Functions/Misc/zcalc | |
parent | 016929e043abb8ba778293c29081ca8e227c6e58 (diff) | |
download | zsh-5103c85abb239a12a3d29da9b41515cd4af19a9f.tar.gz zsh-5103c85abb239a12a3d29da9b41515cd4af19a9f.tar.xz zsh-5103c85abb239a12a3d29da9b41515cd4af19a9f.zip |
38736: various RPN mode enhancements for zcalc
Diffstat (limited to 'Functions/Misc/zcalc')
-rw-r--r-- | Functions/Misc/zcalc | 78 |
1 files changed, 66 insertions, 12 deletions
diff --git a/Functions/Misc/zcalc b/Functions/Misc/zcalc index eb240b2ec..fa1a8f600 100644 --- a/Functions/Misc/zcalc +++ b/Functions/Misc/zcalc @@ -100,7 +100,8 @@ zcalc_show_value() { if [[ -n $base ]]; then print -- $(( $base $1 )) elif [[ $1 = *.* ]] || (( outdigits )); then - if [[ -z $forms[outform] ]]; then + # With normal output, ensure trailing "." doesn't get lost. + if [[ -z $forms[outform] || ($outform -eq 1 && $1 = *.) ]]; then print -- $(( $1 )) else printf "$forms[outform]\n" $outdigits $1 @@ -115,10 +116,10 @@ local ZCALC_ACTIVE=1 # TODO: make local variables that shouldn't be visible in expressions # begin with _. -local line ans base defbase forms match mbegin mend psvar optlist opt arg +local line ans base defbase forms match mbegin mend psvar optlist opt arg tmp local compcontext="-zcalc-line-" -integer num outdigits outform=1 expression_mode rpn_mode matched show_stack i -integer max_stack +integer num outdigits outform=1 expression_mode rpn_mode matched show_stack i n +integer max_stack push local -a expressions stack match mbegin mend # We use our own history file with an automatic pop on exit. @@ -131,6 +132,13 @@ if zmodload -i zsh/mathfunc 2>/dev/null; then zmodload -P mathfuncs -FL zsh/mathfunc mathfuncs="("${(j.|.)${mathfuncs##f:}}")" fi +local -A userfuncs +for line in ${(f)"$(functions -M)"}; do + match=(${=line}) + # get minimum number of arguments + userfuncs[${match[3]}]=${match[4]} +done +line= autoload -Uz zmathfuncdef if (( ! ${+ZCALCPROMPT} )); then @@ -298,6 +306,7 @@ while (( expression_mode )) || ((function|:f(unc(tion|)|))[[:blank:]]##(#b)([^[:blank:]]##)(|[[:blank:]]##([^[:blank:]]*))) zmathfuncdef $match[1] $match[3] + userfuncs[$match[1]]=${$(functions -Mm $match[1])[4]} line= continue ;; @@ -318,19 +327,38 @@ while (( expression_mode )) || (*) line=${${line##[[:blank:]]##}%%[[:blank:]]##} - if (( rpn_mode )); then + if [[ rpn_mode -ne 0 && $line != '' ]]; then + push=1 matched=1 case $line in - (=) + (\=|pop|\<[[:IDENT:]]#) if (( ${#stack} < 1 )); then print -r -- "${line}: not enough values on stack" >&2 line= continue fi - ans=${stack[1]} + case $line in + (=) + ans=${stack[1]} + ;; + (pop|\<) + push=0 + shift stack + ;; + (\<[[:IDENT:]]##) + (( ${line##\<} = ${stack[1]} )) + push=0 + shift stack + ;; + (*) + print "BUG in special RPN functions" >&2 + line= + continue + ;; + esac ;; - (+|-|\^|\||\&|\*|\*\*|/) + (+|-|\^|\||\&|\*|/|\*\*|\>\>|\<\</) # Operators with two arguments if (( ${#stack} < 2 )); then print -r -- "${line}: not enough values on stack" >&2 @@ -341,15 +369,22 @@ while (( expression_mode )) || shift 2 stack ;; - (ldexp|jn|yn|scalb) + (ldexp|jn|yn|scalb|xy) # Functions with two arguments if (( ${#stack} < 2 )); then print -r -- "${line}: not enough values on stack" >&2 line= continue fi - eval "(( ans = ${line}(\${stack[2]},\${stack[1]}) ))" - shift 2 stack + if [[ $line = xy ]]; then + tmp=${stack[1]} + stack[1]=${stack[2]} + stack[2]=$tmp + push=0 + else + eval "(( ans = ${line}(\${stack[2]},\${stack[1]}) ))" + shift 2 stack + fi ;; (${~mathfuncs}) @@ -365,6 +400,25 @@ while (( expression_mode )) || shift stack ;; + (${(kj.|.)~userfuncs}) + # Get minimum number of arguments to user function + n=${userfuncs[$line]} + if (( ${#stack} < n )); then + print -r -- "${line}: not enough vlaues ($n) on stack" >&2 + line= + continue + fi + line+="(" + # least recent elements on stack are earlier arguments + for (( i = n; i > 0; i-- )); do + line+=${stack[i]} + (( i > 1 )) && line+="," + done + line+=")" + shift $n stack + eval "(( ans = $line ))" + ;; + (*) # Treat as expression evaluating to new value to go on stack. matched=0 @@ -386,7 +440,7 @@ while (( expression_mode )) || fi argv[num++]=$ans psvar[1]=$num - stack=($ans $stack) + (( push )) && stack=($ans $stack) ;; esac if (( show_stack )); then |