If you assign into a member access (`foo.bar = baz` or `foo@bar = baz`), it
is no longer permitted that the LHS of the at/dot is an arbitrary
assignable. It now must be a variable, at or dot. This disallows some silly
constructs (e.g. `[foo]@bar = baz`), increases the similarity to function
parameters and should make writing the evaluation code for these more easy.
The previous representation didn't properly model the fact that an
assignable / parameter can only be expanded, if it's a list element. This
now better models this. Other than being more correct, this should also
make evaluating these a bit easier.
While I was at it, I also improved the error message for multiple
expansions on the same level and added tests for these.
This is analogous to dictionaries and ensures that no circular references
can be created when using the exported API in apfl.h.
This also changes apfl_value_copy into apfl_value_incref to better reflect
what it does and to reflect that it is no longer an operation that can
fail.
Increasing the refcount (confusingly called copy before, fixed that too)
didn't work properly, as the object was copied and the refcount was only
updated in one of the copies.
This avoids copying the string every time we pass it around. Not too
important right now, but will become important onve we're able to evaluate
more complex expressions.
It's really easy to accidentally pass an uninitialized string as dst into
the copy function, which will result in an free() call to an arbitrary
pointer. Maybe it's a better idea to not deinit the dst string before
copying? The documentation at least makes it more clear and the new
apfl_string_blank() function makes it easy to create an empty string.
A useful source reader implementation to pass in a source saved as an
in-memory string into the tokenizer.
This replaces the string_src_reader in the tokenizer_test and is even a bit
more flexible, by allowing any aplf_string_view as the source.