Here’s a way to check boolean, string and error equality in pure kakscript. These techniques are used, for example, in my Forth implementation in pure kakscript.
Disclaimers
-
def
's are prefixed withmypkg-
(sometimes implied) so as not to pollute the namespace - I have written this post manually; examples may contain typos/errors (though the showcased techniques are proven in the above-mentioned Forth implementation and other pieces of code)
- using such techniques is, sadly, not really a copy-paste job at this time (though the Forth implementation is UNLINCESE’d, so one can copy-paste from there).
Without further ado:
Testing booleans
… reduces to testing expansions for string equality to literal true
/ false
.
For “well-behaved” strings like “true” / “false”, this is doable via command existence/in-existence (otherwise, I do not have a solution).
We can define multiple str-literal-STR-STR
commands, with zero args (yes, zero; the argument needs to be incorporated in a double-quoted string, see below). These checkers will succeed IF AND ONLY IF called as "literal-STR-%expansion{}"
when the expansion (%arg
, %opt
, or even %sh
) is EXACTLY, literally STR
; and conversely fail (due to non-existence) otherwise.
# Use these by calling the basename with an appended expansion, inside double quotes:
# "mypkg-literal-true-%arg{1}"
# # ... in a 'try/catch', inside a `def`.
# or
# "mypkg-literal-false-%opt{some_bool}"
# # ... in a 'try/catch', anywhere
The call will either be a nop (and thus succeed); or fail due to inexistence. Here are the auxiliary defs and examples:
def mypkg-str-literal-true-true %{}
def mypkg-str-literal-false-false %{}
decl bool bb # test variable
# a testing command
def chk-bool -params 1 %{
try %{
"mypkg-str-literal-true-%arg{1}"
echo -debug checked true
} catch %{
"mypkg-str-literal-false-%arg{1}"
echo -debug checked false
} catch %{
echo -debug -quoting kakoune \
'bool parsing error in kak:' %arg{1} 'should not be assignable to a bool'
}
} -override -hidden
# use chk-bool
set global bb true
chk-bool %opt{bb}
set global bb false
chk-bool %opt{bb}
try %{
set global bb unparsable-bool # fails, next statement shouldn't execute
chk-bool %opt{bb}
} catch %{ echo -debug Expected error: %val{error} }
Compare strings
We can generalize this idea to any other “well-behaved” string constants (anything that can be a part of a command name; inclusing the empty string), using a def that in turn… defines a zero-arg checker:
def mypkg-str-def -params 1 -docstring %{
This defines a checker command:
mypkg-str-literal-%arg{1}-%arg{1}
Call with any expansion (reg, opt) as:
try %{ "%mypkg-str-literal-%expansion{}-%expansion"
# IF-EQUAL commands
} catch %{
# IF-UNEQUAL commands
}
The checker will fail if arg != initial arg
} %{
def "mypkg-str-literal-%arg{1}-%arg{1}" %{} -override -hidden
}
mypkg-str-def 42 # tested via `mypkg-str-literal-42-%expansion{}`
mypkg-str-def '' # tested via `mypkg-str-literal--%expansion{}`
… and these can be checked via
set global mypgk_s 42
try %{ "mypkg-str-literal-42-%opt{mypgk_s}"
echo -debug 42: lets go
} catch %{
echo -debug mypkg: not 42
}
set global mypgk_s 43
try %{ "mypkg-str-literal-42-%opt{mypgk_s}"
echo -debug 42: lets go
} catch %{
echo -debug mypkg: not 42
}
Catch specific errors
Let’s use this to define and catch specific exceptions, while ignoring others.
It’s a bit more complicated because any try
's erase the current %val{error}
. Therefore, the current error needs to be saved first — in a str
(errors are simple strings), or in a fail %value{error}
str-list trampoline. Using a trampoline (executed as %opt{trampoline}
) is simpler, because it can be either an empty str-list
(which is a nop), or the fail
action.
def mypkg-err-def -docstring %{
Define a string equality test, to be used next as an exception checker
} %{
define -override -hidden mypkg-err-def -params 1 %{
def "mypkg-str-literal-%arg{1}-%arg{1}" %{} -override -hidden
}
}
decl -hidden str-list mypkg_err_slist # variable holding current error
define -override -hidden mypkg-err-eq -params 1 -docstring %{
Defines an error checker
} %{
# save current error; would be overwritten by subsequent try's
set global mypkg_err_slist fail %val{error} # save in revolver
try %{
"mypkg-str-literal-%arg{1}-%val{error}" # test str=
} catch %{
%opt{mypkg_err_slist} # unequal; fire revolver
}
}