compiler: Fix recursives capturing non-recursives

When the self-recursive lambda optimisation was introduced we "hid" all
the values from the same binding from PlanLambda so it wouldn't consider
the self value captured. This had the side-effect of making all other
values in the same binding invisible to the lambda. We were also
returning the initial state in to the fold which meant that all forward
declared recursive values were forgotten when the first self-recursive
value is encountered.

Fix by explicitly excluding the recursive self value in FindClosedVars
and tracking the current state properly in PlanBind
stdlib: Implement (vector-copy)

This is simply a wrapper around the existing VectorCell::copy() function
stdlib: Implement (min) and (max)

This is a simple C++ implementation. Making a performant Scheme
implementation is difficult with dialects with mutable pairs due to the
restricted type inference and optimisation.
compiler: Fix codegen for non-BMP characters

Java is internally based on UTF-16. For Unicode code points outside the
BMP it uses surrogate pairs which count as two Java "characters".
Llambda is native UTF-8 and considers a code point to be synonymous with
character. Use Java's codePointCount to calculate the actual code points
in a string.
compiler: Fix copy-and-pasted variable name
compiler: Planning for (string-length)

This will be important for procedures that optionally take string
slices. If the slice end isn't specified we need to fetch the string
length to pass as the end index. This is the same way vector slicing is
implemented.

- Implement planning of (string-length) for static values. This uses
  codePointCount to calculate the number of code points in the string.

- Add loading of string length from dynamic strings using a new
  LoadStringCharLength plan step