We'll soon need the full apfl_ctx, where we previously only needed the
gc. apflc was the only place manually constructing a struct gc without
an apfl_ctx, so lets change that.
Pairs are 2-tuples of values that are constructed and matched with the `::`
operator. They can also be matched with a `:` operator, the LHS is an
expression then, the pair will then only match, if the LHS matches the
result of that expression.
Pairs should be useful to do something similar what sum types / tagged
unions do in statically typed languages, e.g. you could write something
like:
some := (symbol) # Somthing that creates a unique value
filter-map := {
_ [] -> []
f [x ~xs] ->
{
some:y -> [y ~(filter-map f xs)]
nil -> filter-map f xs
} (f x)
}
filter-map {
x?even -> some :: (* x 10)
_ -> nil
} some-list
We're now first building a standalone bytecode compiler `apflc` that will
compile `globals.apfl` into bytecode and write it out as a C source file.
When initializing a new context, that embedded bytecode will then get
evaluated and the global scope will be populated from the dictionary
returned by that bytecode.
Previously we were getting a pointer into the value stack for the parts
list. However, that pointer would not necessarily be a valid pointer later
any more, as we're also manipulating the value stack.
This introduces the higher level API apfl_set_list_member_by_index to
modify a list and also adds an option for our test suite to run the tests
with valgrind --tool=memcheck. This should catch such errors in the future.
This implements the last remaining feature of the language syntax! :)
The implementation of this was delightfully simple, since all the heavy
lifting is done by already implemented functions.
We called return_from_matcher once inside
matcher_evaluate_capturing_instruction and outside of it. That way we
returned not to the parent call stack entry but to the grandparent.
It's now possible to assign to a key of a dictionary and even to a nested
key path.
This patch changes the way matchers work a bit:
First, a function call stack frame now has a stack of matchers that are
manipulateable instead of a single matcher.
Second, the matcher is now in charge of setting the matched values to the
variables (previously the caller of the matcher needed to extract the
matched values and assign them itself). This change simplifies code
generation, especially for chained assignments and dictionary key paths.
This removes the last usage of APFL_ERR_NOT_IMPLEMENTED :)