This is a new API that is similar in spirit and plumbing to the World
API, but it intended for all local machine operations and will likely
only ever have one implementation.
This test detects a mistake which is easy to make: when making a
recursive call to the target of an ExprVar, it would be easy to
accidentally pass the environment, like we usually do with every other
recursive call. For variables, this is a mistake, because the lambda
parameters which are in scope where the variable is used must not be in
scope where the variable is defined.
In fact, ExprVar.Graph() currently makes this mistake. The test passes
anyway, because an earlier phase (SetScope) correctly clears the
environment and detects the problem before the Graph phase. Thus, this
test does not guarantee that all the phases correctly clear their
environment, it merely detects the unlikely case in which all the phases
make the same mistake.
This modifies the panic feature to accept a boolean or a string. If true
or not empty, then it will cause the panic. This makes some of the error
code a little less ugly.
This is a newer implementation of the panic magic. I kept the old commit
in for posterity and to show the difference. The two versions are
identical to the end-user with one exception: the newer version doesn't
include a useless panic resource in the graph when there is no panic. In
this version, the panic function returns false and the if statement it's
the condition of, doesn't produce the resource within. On error, we
still consume the function in the if expression, and doing so causes
everything to shutdown.
The other benefit is that the implementation is much cleaner and doesn't
need the interpolate hack.
It's valuable to check your runtime values and to shut down the entire
engine in case something doesn't match. This patch adds some magic
plumbing to support a "panic" mechanism.
A new "panic" statement gets transparently converted into a panic
function and panic resource. The former errors if the input is not
empty. The latter must be present to consume the value, but doesn't
actually do anything.
Most of this logging isn't useful for ordinary usage. Hide it for now.
Eventually when we have a fancy logging system (curses-like) we can
bring back more information on the state of everything.
This is a strange resource which is probably most useful for passing
values between scopes. It supports a variant resource field, and should
only be used as a last resort and if you know exactly what you're doing.
We run the resource engine once and look at its values. This is useful
for testing send/recv in particular.
The converger code is probably not working properly. We'll look into
that subsequently if this gets used a lot.
If we have rare, but special *interface{} values in resource structs, we
should be able to handle them normally. It's really not recommended that
you use these unless you know exactly why they are useful.
This lets us add a resource that has an implementation with a field
whose type is determined at compile time. This let's us write more
flexible resources.
What's missing is additional type checking so that we guarantee that a
specific resource doesn't change types during run-time.
This seems to make things work. I'm worried I might have an ordering bug
where we might choose the wrong precedence if we write ambiguous code
somehow, but at least for now, let's commit this and move on. Hopefully
the nonassoc stuff is actually correct.
This adds an interesting version of the struct lookup function. In the
situation where we can't type-check the field name, it will use the
optional value passed in. This makes it easy to write a function that
will pull in the desired value, even as the input struct changes type
between compilations, without having to re-write your code.
It's structurally different from the other default lookup functions,
which is why it is named differently.
If we use this to generate a zero value, we want to make sure it's
completely initialized in case we use it subsequently. We also improve
the docs at the same time.
Instead of in the lexer. I think this simplifies things and gives the
parser more information which should hopefully make it easier to parse
without shift/reduce conflicts.
It's a normally named function for now, until we think of a common
package to move it into.
Hopefully this makes improving the lexer and parser easier for now. We
can consider bringing it back if needed.
This is a big giant patch that implements the AST part of lambdas!
I don't know how Sam is able to understand the AST so well, but he does,
and we're all grateful for it. Most of this code was written by him.
Co-authored-by: Samuel Gélineau <gelisam@gmail.com>