# Kakscript: boolean / string / error equality testing

**URL:** <https://discuss.kakoune.com/t/kakscript-boolean-string-error-equality-testing/1959>\
**Category:** Resources\
**Tags:** scripting\
**Created:** [December 15, 2021, 1:07pm UTC](https://discuss.kakoune.com/t/kakscript-boolean-string-error-equality-testing/1959 "2021-12-15T13:07:15Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![almr](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/almr/32/934_2.png) [@almr](https://discuss.kakoune.com/u/almr)\
**Post date:** [December 15, 2021, 1:07pm UTC](https://discuss.kakoune.com/t/kakscript-boolean-string-error-equality-testing/1959/1 "2021-12-15T13:07:16Z")

</div>

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](https://gitlab.com/kstr0k/kak-stkmach).

## Disclaimers

- `def`’s are prefixed with `mypkg-` (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.

```auto
# 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:

```auto
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:

```auto
  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

```auto
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.

```auto
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
  }
}

```

---

<div class="post-metadata">

**Author:** ![almr](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/almr/32/934_2.png) [@almr](https://discuss.kakoune.com/u/almr)\
**Post date:** [December 15, 2021, 1:30pm UTC](https://discuss.kakoune.com/t/kakscript-boolean-string-error-equality-testing/1959/2 "2021-12-15T13:30:41Z")

</div>

A quick note: I think this mostly supersedes @andreyorst 's [if-then-else technique](https://discuss.kakoune.com/t/if-else-control-flow-operator/571), because

```auto
def some-function-using-if_then_else -params 3 %{
try %{
  "mypkg-str-literal-true-%arg{1}"
  # IF PART
  echo -debug %arg{2}
} catch %{
  # ELSE PART
  echo -debug %arg{3}
}
}

```

can evaluate its arguments. If- and else- strings, OTOH, if passed to an `if` function, would be evaluated in _that_ function’s context, so `%arg`'s would be nonsense — and access to the original args would need to be arranged via saving them in an option.

---

<div class="post-metadata">

**Author:** ![andreyorst](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/andreyorst/32/29_2.png) [@andreyorst](https://discuss.kakoune.com/u/andreyorst)\
**Post date:** [December 15, 2021, 10:57pm UTC](https://discuss.kakoune.com/t/kakscript-boolean-string-error-equality-testing/1959/3 "2021-12-15T22:57:25Z")

</div>

FYI I’m no longer using that method, and have migrated to pure kakscript one:

[https://github.com/andreyorst/dotfiles/blob/master/.config/kak/commands.kak#L244-L248](https://github.com/andreyorst/dotfiles/blob/master/.config/kak/commands.kak#L244-L248)

---

<div class="post-metadata">

**Author:** ![almr](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/almr/32/934_2.png) [@almr](https://discuss.kakoune.com/u/almr)\
**Post date:** [December 16, 2021, 12:34am UTC](https://discuss.kakoune.com/t/kakscript-boolean-string-error-equality-testing/1959/4 "2021-12-16T00:34:06Z")

</div>

That’s the one I was referring. The problem is that such versions of`-if`, `when`, and `-unless` take string arguments. Those strings are expanded (or not expanded) inside another function (those conditionals), not in the context of the original callers. Most expansions are context-free and thus work, but not `%arg`; if these string arguments try to use a `%arg` expansion, it will be nonsense. So, for example,

```auto
def myfunc -params 1 %{
  functional-if true %{
    echo -debug %arg{1} # improper expansion passed as a string
  } %{ echo -debug ELSE-CLAUSE } # no problem here
}

myfunc true
myfunc false

```

The basic problem is that you can’t produce a closure (to pass on to those conditionals).

_Edit_: sorry for the post edits; I always end up trying to clarify

---

<div class="post-metadata">

**Author:** ![andreyorst](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/andreyorst/32/29_2.png) [@andreyorst](https://discuss.kakoune.com/u/andreyorst)\
**Post date:** [December 24, 2021, 1:35pm UTC](https://discuss.kakoune.com/t/kakscript-boolean-string-error-equality-testing/1959/5 "2021-12-24T13:35:01Z")

</div>

yes, you’re right. This didn’t occur to me as I write very few functions that require alteration but don’t use sh already. This `if` is primary for conditional configuration.
