Commit Graph

177 Commits

Author SHA1 Message Date
Andrei Ciobanu
481798ab36 Unify core functions address handling (#3445)
Signed-off-by: Andrei Ciobanu <andrei.ciobanu@opentofu.org>
2025-10-31 08:41:52 +02:00
Andrei Ciobanu
af43817e57 Extract the provider functions references from the dynamic blocks (#3429)
Signed-off-by: Andrei Ciobanu <andrei.ciobanu@opentofu.org>
2025-10-28 17:10:07 +02:00
Martin Atkins
639dff15c3 lang/eval: Clear some linter warnings
Based on discussion so far it seems that we have consensus about merging
the lang/eval and engine-related commits that precede this one as a
starting point for ongoing work in future (hopefully smaller) PRs.

This commit therefore mostly just acknowledges a small amount of unused
code in a way that it won't cause linter noise, since the future work is
likely to make these be used and so it'll be helpful to have them around as
examples to build on. (Which is, after all, the whole point of merging this
as dead code in the first place!)

This does _actually_ remove an old, now-redundant declaration of the
"compiled module instance" interface though, since that eventually ended
up in a different place and I just forgot to clean up this initial form
of it in later refactoring.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
4218231438 execgraph: Most of the "compiler" machinery
This covers most of the logic required to turn a source graph into a
compiled graph ready for execution. There's currently only support for one
of the opcodes though, so subsequent commits will sketch those out more
and then add some tests and fix any problems that inevitably exist here but
aren't yet visible because there are no tests.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
b6cdfd1afa lang/eval: Bind PlanningOracle to PlanGlue
Previously the PlanGlue methods all took PlanningOracle pointers as one
of their arguments, which is annoying since all of them should end up with
pointers to the same object and it makes it hard for the PlanGlue
implementation to do any work outside of and between the PlanGlue method
calls.

Instead then we'll have DrivePlanning take a function for building a
PlanGlue implementation given a PlanningOracle pointer, and then the
planning engine returns an implementation that binds a planContext to a
PlanningOracle it can then use to do all of its work.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
4772944e91 engine/planning: Provider instances and stub of data resource planning
This is a sketch of starting and configuring provider instances once they
are needed and then closing them once they are no longer needed. The
stubby implementation of data resource instance planning is there mainly
just to illustrate how this is intended to work, but it's not yet complete
enough to actually function.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
4ea51e4faf lang/eval: Provider instance to ephemeral resource instance dependencies
This completes a previously-missing piece of the "prepareToPlan" result,
tracking which provider instances are relying on each ephemeral resource
instance.

This is important because the planning engine can "see"
resource-instance-to-provider relationships in the state that the eval
system isn't aware of, and so the planning engine must be able to keep
a provider instance open long enough to deal with both config-driven and
state-driven uses of it, which in turn means keeping open any ephemeral
resource instances that those provider instances depend on.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
6b9cebaf8b engine/planning: Find "orphan" resource instances
The eval system gradually reports the "desired" declarations at various
different levels of granularity, and so the planning engine should compare
that with the instances in the previous run state to notice when any
existing resource instance is no longer in the desired state.

This doesn't yet include a real implementation of planning the deletion of
such resource instances. Real planning behaviors depend on us having some
sort of provider instance and ephemeral resource instance manager to be
able to make requests to configured providers, so that will follow in
subsequent commits before we can implement the actual planning behaviors.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
a82da0f674 lang/eval: Call PlanGlue.Plan*Orphans methods
In a new async recursive tree walk we'll gradually traverse the tree of
module calls and announce the desired state objects at each level, so that
the PlanGlue implementation can then compare that with its own record of
the prior state to determine by omission which resource instances are
"orphans" that should be planned for deletion.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
450fe5c7ab lang/eval: More stubbing for PlanGlue.Plan*Orphans calls
This puts the infrastructure in place to allow us to notify the PlanGlue
implementation about what's declared in the configuration so it can detect
orphaned resource instances by omission, but stops short of actually doing
that because it'll require another concurrent recursive tree walk which
is likely to be complex enough to deserve to live in its own later commit.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
557026c5db lang/eval: A different approach to "orphan" resource instances
Previously this had the idea that the planning engine would work in two
subphases where first it would deal with the desired state (decided by
evaluating the configuration) and then it would do a second pass to plan
to delete any resource instances that didn't show up in the desired state.

Although that would technically work, we need to keep configured provider
instances open for the whole timespan between planning the first
desired resource instance and the final orphan instance using each
provider, and so splitting into two phases effectively means we'd have
provider instances sitting open but idle waiting for the desired state
subphase to complete to learn if they are needed for the orphan subphase.

This commit stubs out (but does not yet implement) a new approach where
the orphan planning can happen concurrently with the desired state
planning. This works by having the evaluator gradually describe to the
planning engine which module calls, module call instances, resources, and
resource instances _are_ present in the desired state -- as soon as that
information becomes available -- so that the planning engine can notice
by omission what subset of the prior state resource instances are no longer
desired and are therefore orphans.

This means that the planning engine should now have all of the information
it needs to recognize when a provider can be closed: the PlanningOracle
reports which _desired_ resource instances (or placeholders thereof) are
expected to need each provider instance, and the prior state tracks
exactly which provider instance each prior resource instance was associated
with, and so a provider's work is finished once all instances in the union
of those two sets have had their action planned.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
7e5378bea2 lang/eval: Expose EvalContext for caller use
Although our EvalContext API is primarily focused on what the eval system
needs, it's desirable for higher-level subsystems that wrap the evaluator
to be able to guarantee they are using the same provider and other
dependencies, so we'll expose the EvalContext that each ConfigInstance is
associated with in the public API.

The Providers interface now also grows to include NewConfiguredProvider as
a way to instantiate a configured provider instance. The eval system
doesn't need that itself, but exposing it here means that a caller can be
confident that they are definitely instantiating and configuring the same
provider that the eval system had previously used to validate the
configuration.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
eb1d686806 lang/eval: PlanningOracle methods have their own workgraph workers
As was already noted in a comment in the PlanningOracle declaration, the
PlanningOracle API is an exported entrypoint usable from outside lang/eval
and so each exported method should establish its own workgraph worker to
make sure it's handling those concerns correctly regardless of how the
caller chooses to use them.

For example, a caller might choose to make concurrent calls into the oracle
from multiple goroutines, which would violate the assumption that each
concurrently-running codepath is associated with a separate workgraph
worker.

Even if a caller is managing their own workgraph workers in the expected
way, this is functionally harmless and relatively cheap.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
7cab34815a lang/eval: PlanningOracle.AwaitResourceInstancesCompletion
This is a building block for use by a planning engine implemented elsewhere
in OpenTofu so that it can be notified (by the completion of a call to the
function) when all resource instances that use a particular provider
instance or ephemeral resource instance have completed their plan-time
evaluation work.

Existing methods of PlanningOracle already expose sets of addresses to
wait for, but this method is separate from those because the planning
engine also needs the dependency information as data to know when an
ephemeral resource instance might need to be left open beyond the part of
the planning process driven by lang/eval in order to plan the delete
actions for any "orphan" resource instances that are in the prior state
but no longer declared in the configuration.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
ab6af47df7 lang/eval: Move PlanningOracle to its own file
Continuing to split up some of the source files that have grown long over
ongoing experimentation, this is the start of splitting the config_plan.go
file into smaller parts.

For now only PlanningOracle gets its own file, but other types related to
planning might follow in later commits.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
52a27d1865 lang/eval: PlanningOracle can now return a provider instance config
This was the big known missing piece for making a "real" implementation
of planning using this new package, so that the planning engine can know
what configuration to use when preparing a configured provider instance
for planning requests.

I'm sure there are other missing pieces that I've just not learned about
yet, but this is still a good checkpoint to stop iterating on lang/eval
for a little while and start stubbing out the planning engine.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
db8af25531 lang/eval: Rework how module calls work
The previous approach had the problem that we only had the
CompiledModuleInstance object for a child module briefly in a local
variable while evaluating the child call, which is sufficient for just
evaluation but is not enough to support full config tree traversal for
questions like "what resource instances are declared throughout the
configuration?" and "what configgraph node corresponds to this provider
configuration instance address?"

This moves the separation of concerns around a little to be perhaps more
like how resource instances work, where the ModuleCallInstance.Value
method just wraps a function provided by the "compile" layer which then
takes the config value and compiles the child module instance.

This means that the "compile" layer can then hold on to the
CompiledModuleInstance object for the child module instance as part of
the "glue" in the ModuleCallInstance object and then use it to deal with
the config-tree-traversing methods in its own CompiledModuleInstance
implementation.

The new test of ConfigInstance.PrepareToPlan in lang/eval illustrates that
the system is now finally able to walk the whole configuration tree to find
resource instances and the provider instances they depend on.

(The handling of inheritance of providers between parent and child module
instances is still not working like the current system does, because the
"providers sidechannel" mechanism remains incomplete.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
372501516c lang/eval/internal/tofu2024: Split up compile.go
This file was originally in lang/eval directly and so it had all of the
compile-related functions grouped together to separate them from everything
else in that package.

Now that the "compile" process has its own package we have more room to
have many smaller files instead of one huge file, making this a little
easier to navigate now that the logic has grown.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
af3bd79a03 lang/eval: Work-in-progress changes to modeling of module tree
Exposing only "ResourceInstancesDeep" on CompiledModuleInstance seemed
attractive at first when it was only partially implemented anyway, but
trying to finish implementing it revealed that the current design couldn't
actually support that API because we don't currently keep the
CompiledModuleInstance object for a child module instance after we've used
it to evaluate the child module instance's output values.

This commit doesn't actually solve that problem, but it does rework the
CompiledModuleInstance API so that the problem of finding and enumerating
child module instances is separated from the problem of finding resource
instances in just the current module instance, and then I'll try to find
a good way to satisfy this new, slightly-generalized API in future commits.

(The ultimate goal here is to be able to enumerate all of the resource
instances throughout the configuration for dependency-tracking purposes,
and to be able to find a specific ProviderInstance object given its
absolute address so that the plan or apply engine can request the
configuration value to configure the provider with.)

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
a532c43eb1 lang/eval: Evaluation of provider configurations
This introduces the "compiler" changes and the configgraph changes to let
us evaluate the configuration for a particular provider instance.

A future commit will expose this through the public API of lang/eval so
that other systems like the planning engine will be able to ask for the
configuration for whatever provider instance a given resource instance
belongs to.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
ffe8a79658 lang/eval: Slightly more complete handling of provider configurations
This is still not completely true to how current OpenTofu behaves, but it's
at least a little closer and avoids hard-coding a specific fixed provider
address in favor of actually following what's declared in the
configuration.

The system doesn't actually support evaluating the configuration for a
provider instance yet, so this remains just a placeholder for the
relatively simple tests in this package. Support for actually evaluating
the provider configurations will follow in later commits.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
635b444c8e lang/eval: Some deeper stubbing out of the DrivePlanning design
This is a little too busy/complicated for my liking but it's a place to
start and hopefully we'll be able to cut this down a little after we see
how the planning engine implementation turns out.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
64ad4cc66a lang/eval: Some initial support for child module calls
The way this all fits together doesn't feel quite right yet since there's
a bunch of wrapping layers that aren't really adding anything except
indirection between the packages, but this is at least a starting point
for child module support.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
b06287111b lang/eval: Temporary shimmed support for our core functions
This borrows the function table preparation from our previous lang.Scope
API (which this experiment would, if successful, ultimately replace) and
also intentionally implements the exprs.Evalable interface a little
improperly for now in the hope that we'll update our HCL patch for
function inspections to use hcl.StaticCall instead of misusing
hcl.Traversal at some point in the future.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
1a7dd21fc2 lang/evalglue: Different approach to EvalContext defaults for tests
In other packages we've tried being pragmatic by making the main code
compensate for missing arguments in older tests, so that we don't always
need to update every test across the whole system every time we add a new
feature.

However, that compromise unfortunately tends to lead to non-test code
inadvertently relying on the compensations too, so this is an attempt at
a slightly different compromise where the main code will panic if called
incorrectly but there's an extra helper function for tests to fill in
reasonable "inert" defaults for the fields they leave unpopulated.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
3a31ce9c28 configgraph: ContributingResourceInstances uses ValueMarksOfTypeDeep
Recent changes in cty have included some new functions for working with
marks more efficiently. This particular function allows us to iterate over
the deep marks on a value without creating a new unmarked copy of the
value and without building an intermediate map of marks.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
352e23e8f3 lang/eval: A benchmark and a note about a hot path
This also further highlighted that the marks-related codepaths in cty have
lots of room for performance improvement. In particular, we're spending
a lot of time in cty.Value.UnmarkDeep rebuilding values that actually
don't need to change and could likely get some benefit from rewriting
that to use the recently-added WrangleMarksDeep that is able to avoid
constructing new values for parts of the tree where no marks are changing.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
c64b02a1af lang/eval: Start of supporting module calls
This stops short of actually implementing the evaluation of a module call,
but gets the compilation behavior in place and the usual boilerplate for
handling multi-instance module calls.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
a277aafff9 configgraph: Some unit tests for some "Value" methods
A big part of the motivation of the design of configgraph vs. package tofu
was to keep each node type self-contained and avoid the need for a big
shared "god object" that everything interacts with, and in turn part of
the reason to be interested in that is because it should makes it actually
practical and useful to write unit tests for these node types.

This commit introduces a few unit tests mainly just as a proof-of-concept
to see if the design has lived up to the ambition. So far that seems to be
true, although I'll reserve judgement until there's at least some coverage
on every on of the node types in this package.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
49780f47ca tofu2024: compileModuleProvidersSideChannel doesn't need module instance
Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
9bf2516f68 lang/eval: Start of splitting the "compile" layer into its own package
During early experiments the logic for "compiling" a configs.Module into
a bunch of configgraph node objects was just a bunch of unexported
functions directly in package eval, because it wasn't clear yet what
abstraction would make most sense between those two.

Now that this has solidified a little more this commit is a first attempt
at drawing a line between packages implementing "compilation" for specific
editions of the language (for which there is currently only one, which
I've named "tofu2024" as a placeholder because Terraform's only existing
language was similarly called "TF2021") and the top-level evaluation
package that tries to be as edition-agnostic as possible, although it is
currently still the one responsible for deciding to call into tofu2024.

There doesn't seem much point in abstracting away the decision about what
edition to use until we actually have a plan to introduce a new edition
and therefore have some idea of what the design constraints for that might
turn out to be.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
16f31733eb lang/eval: instance local scope is now a "compiler" concern
Completing the reorganization of all of the scope-shape-related decisions
into the "compiler" code instead of package configgraph, this now deals
with the scope that contains the each.key/each.value/count.index local
symbols.

Package configgraph now no longer knows anything about the shape of the
scopes except for a few pragmatic mentions of specific conventions in
error messages where it doesn't seem worth the complexity to try to
organize that differently until we know concretely what problem we're
trying to solve.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
4703a3baf9 lang/exprs: "compilation" of CheckRule
The pattern of having the "compiler" logic in lang/exprs always deal with
building suitable exprs.Valuers and configgraph just evaluating whatever
it was given has been working out in other contexts like the resource to
resource instance journey, so we'll follow that pattern for CheckRule too:

If the evaluation of a CheckRule depends on some value that's generated
by logic in configgraph then configgraph has a callback to ask the
"compiler" layer to dynamically construct zero or more CheckRule objects
that are pre-bound to the relevant value. For checks that only rely on
the global scope, such as output value preconditions, they are still
precompiled into a static slice in the parent object.

This also continues the progress towards all of the "expression scopes"
living with the "compiler" code instead of in configgraph, so that in
future different modules can potentially be bound to differently-shaped
scopes as we continue to evolve the language.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
14c2f398d3 lang/eval: module instance scope no longer in configgraph
On reflection it seems inconsistent that the "compile" logic in lang/eval
is responsible for deciding which expressions get evaluated in which scopes
but not for deciding what's actually in the top-level scope, since the
scope contents are something quite likely to vary between language
editions and language experiments.

With that in mind, this separates the idea of the "module instance scope"
from the actual ModuleInstance type, making it instead a wrapper type.
This continues the trend toward the grapheval package being mostly agnostic
to how the surface-level language is designed and instead just modeling
the relationships that are implied by the configuration.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
47d93fc3dc lang/eval: Deciding a provider instance for each resource instance
This introduces the machinery for representing provider configs, provider
instances, and the relationships between resource instances and provider
instances.

Unfortunately there's a lot of accumulated complexity in the rules for
how OpenTofu currently decides which provider configs are available for
use in a module, including lots of implicit behavior for
backward-compatibility, so right now that is stubbed out with just a
hard-coded implementation that puts a "test/foo" provider with local name
"foo" in every module instance. We'll deal with a real implementation of
all that in later commits.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
105a84d24c lang/eval: Reshuffle concerns for resource instances a little
Previously the way this was dealing with "compiling" resource instances
once we've determined the instance keys was a little inconsistent with the
intended architecture because the configgraph.Resource type needed to know
how to pass various bits of context down into each of the instances, but
everywhere else we've tried to keep the configgraph types pretty agnostic
about such details and let the "compiler" layer worry about that.

Now the entire task of "compiling" a resource instance is delegated to
the "compiler" layer using a callback it provides. This makes things easier
because that layer already has all of the resource-level information it
needs available anyway, and so it can just plug that information directly
into the ResourceInstance fields itself in the same way as it builds
other types like ModuleInstance and Resource.

This also introduces an interface type to represent the callback API from
the ResourceInstance itself back to the compiler layer, which means we can
now split config validation and "get result value" into two methods, which
makes the implementation of each of those methods considerably simpler --
they are both now one-liners, and the data flow from validation to
get result value is encapsulated in the configgraph package where it will
be shared between all phases.

Overall the idea here is to make Resource and ResourceInstance independent
of one another so that, as is the goal for everything in configgraph, it's
more practical to write unit tests that don't need to mock out an entire
world just to test one small unit.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
aa4743f23f lang/eval+lang/exprs: More exprs.EvalError markings
It doesn't hurt to be liberal in handling this everywhere that we know
there's an error because applying the mark where it was already present
is effectively a no-op, so we'll introduce more of these both for
robustness and to help folks who are reading this code in future to
learn the EvalError patterns by observation.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
5cb04694eb lang/eval: ConfigInstance.PrepareToPlan analyzes ephemeral resources
There's now enough here to produce a data structure where each ephemeral
resource instance is associated with all of the resource instances that
must complete planning before it can be closed.

This also doubles as the first demonstration of dynamic analysis of
resource instance dependencies using cty marks, with
TestPrepare_ephemeralResourceUsers illustrating the more precise results.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
e092db420e lang/eval: Stub of ConfigInstance.prepareToPlan
This is my current idea for how to resolve the chicken/egg problem of the
planning phase needing to know who uses ephemeral resource instances and
provider instances but us needing to evaluate the configuration to know
those relationships.

This borrows the evaluation behavior previously used for
ConfigInstance.Validate to produce a conservative evaluation of the
configuration without depending on any configured providers or ephemeral
resource instances, which we (in future commits) will use to discover
the relationships between those objects so that the real walk during the
planning phase can know when to start and stop them.

This relies on the idea that an evaluation with values stubbed out as
unknown should produce _at least_ the relationships that would occur with
fewer unknown values, though it might also report additional dependencies
that would vanish once values become more known. This gives the plan phase
something to start with and then we'll learn a tighter set of dependencies
during the planning phase which will form the basis of the apply-time
execution graph.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
cf84d991ff lang/exprs: EvalableHCLBodyWithDynamicBlocks
The HCL "dynblock" extension blurs the distinction between static
structure and dynamic expressions by allowing the use of expressions to
generate zero or more nested blocks.

Because this feature is a bit of a layering violation it requires some
different usage patterns to get the correct result, and so this new
EvalableHCLBodyWithDynamicBlocks aims to encapsulate those details so that
the caller can just treat the result like a normal Evalable.

lang/eval now uses this for the body of a resource configuration, so that
"dynamic" blocks can work in there similarly to how they do in the previous
language runtime.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
0d4fa0e66e lang/eval: ModuleInstance exprs.Scope methods in separate file
The module_instance.go file was getting quite long and hard to navigate,
and the Valuer vs. Scope distinction seems like a reasonable place to
draw a line between two different files related to module instances.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
9d7eb9742e lang/eval: Enough resource support for basic validation to work
Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
507055bc2f lang/eval: Shuffle resource instance result handling a little more
The separation of concerns here still doesn't feel _quite_ right since
a resource instance node needs to know what provider it belongs to even
though that package doesn't otherwise interact with providers directly
at all, but this at least clarifies exactly one location that's responsible
for getting the config value for the result value callback to use.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
6293cb9bdd lang/eval: More wiring for resource and resource instance handling
This is not all the way done yet, but getting closer.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
66f1e92aed eval: Track absolute addresses for variables, locals, and outputs
This gives us something unambiguous to use when describing these objects
in error messages.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
3540006d97 lang/eval: Validate basics working and some other API stubbing
Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
90d28b1026 lang/eval: Some initial work on supporting resource instances
This also includes an assortment of other plumbing that I did while working
on this, since my current work mode is primarily driven by experimentation
rather than working towards specific milestones.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
72a32f726d lang/eval: Beginnings of a different way to handle config eval
In "package tofu" today we try to do everything using a generic acyclic
graph model and generic graph walk, which _works_ but tends to make every
other part of the problem very hard to follow because we rely a lot on
sidecar shared mutable data structures to propagate results between the
isolated operations.

This is the beginning of an experimental new way to do it where the "graph"
is implied by a model that more closely represents how the language itself
works, with explicit modelling of the relationships between different
types of objects and letting results flow directly from one object to
another without any big shared mutable state.

There's still a lot to do before this is actually complete enough to
evaluate whether it's a viable new design, but I'm considering this a good
starting checkpoint since there's enough here to run a simple test of
propagating data all the way from input variables to output values via
intermediate local values.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
Martin Atkins
df21c1d8dc lang/exprs: Expression evaluation helpers
This package provides a more generic version of what's currently modeled
by the likes of lang.Scope and lang.Data, designed to avoid having a huge
single type that must know about everything in the language and, for this
package's purposes alone, to avoid knowing anything about the language at
all except that it uses HCL.

This is currently just an experiment not used by anything, and so is dead
code aside from the contrived mini-language implemented in example_test.go.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00
James Humphries
cea35d6206 Bump our hcl fork to include fix for Provider defined functions in parentheses (#3402)
Signed-off-by: James Humphries <james@james-humphries.co.uk>
2025-10-22 10:40:53 +01:00