eval

package
v1.13.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 11, 2026 License: MPL-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package eval aims to encapsulate the details of evaluating the objects in an overall configuration, including all of the expressions written inside their declarations, in a way that can be reused across various different phases of execution.

The scope of this package intentionally excludes concepts like prior state, plans, etc, focusing only on dealing with the relationships between objects in a configuration. This package is therefore intended to be used as an implementation detail of higher-level operations like planning, with the caller using the provided hooks to incorporate the results of side-effects managed elsewhere.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func InputValuesForTesting

func InputValuesForTesting(vals map[string]cty.Value) exprs.Valuer

InputValuesForTesting returns input variable definitions based on a constant map, intended for convenient test setup in unit tests where it only matters what the variable values are and not how they are provided.

Types

type ApplyGlue

type ApplyGlue interface {
	// ResourceInstanceFinalState blocks until the apply phase has completed
	// enough work to decide the final state value for the resource instance
	// with the given address and then returns that value.
	//
	// If operations that would contribute to that final value fail then this
	// function returns a suitable placeholder for the final state that can
	// would allow valid dependent expressions to evaluate successfully though
	// potentially to an unknown value. Returning the "planned state" that
	// was predicted during the planning phase is acceptable, and returning
	// [cty.DynamicVal] is also acceptable as a last resort when absolutely
	// no information is available.
	//
	// Diagnostics from apply-time actions must be reported through some other
	// channel controlled by the apply engine itself.
	ResourceInstanceFinalState(ctx context.Context, addr addrs.AbsResourceInstance) cty.Value

	// ValidateProviderConfig asks the provider of the given address to validate
	// the given value as being suitable to use when instantiating a configured
	// instance of that provider.
	ValidateProviderConfig(ctx context.Context, provider addrs.Provider, configVal cty.Value) tfdiags.Diagnostics
}

ApplyGlue is used with [DriveApplying] to allow the evaluation system to communicate with the applying engine that called it.

Methods of this type can be called concurrently with each other and with themselves, so implementations must use appropriate synchronization primitives to avoid race conditions.

type ApplyOracle

type ApplyOracle struct {
	// contains filtered or unexported fields
}

An ApplyOracle is returned by ConfigInstance.ApplyOracle to give the main apply engine access to various information from the configuration that it will need during the apply process.

All methods of an ApplyOracle must be called with a context.Context derived from one produced by grapheval.ContextWithWorker.

Whereas the planning process is driven primarily by the dependencies discovered dynamically during evaluation, the apply process is instead driven primarily by an execution graph that was built during the planning process. The apply-time execution steps therefore need to be able to pull the information they need from the evaluation engine on request instead of the evaluation engine pushing the information out, and an object of this type provides that information.

It's the responsibilty of the planning engine to construct an execution graph that ensures that the apply phase will request information from the oracle only once it has already been made available by earlier work.

func (*ApplyOracle) AnnounceAllGraphevalRequests

func (o *ApplyOracle) AnnounceAllGraphevalRequests(announce func(workgraph.RequestID, grapheval.RequestInfo))

AnnounceAllGraphevalRequests calls the given function once for each internal workgraph request that has previously been started by requests to this oracle.

This is used by the apply engine as part of its implementation of grapheval.RequestTracker, so that promise-resolution-related diagnostics can include information about which requests were involved in the problem.

This information is collected as a separate step only when needed because that avoids us needing to keep track of this metadata on the happy path, so that we only pay the cost of gathering this data when we're actually going to use it for something.

func (*ApplyOracle) DesiredResourceInstance

DesiredResourceInstance returns the DesiredResourceInstance object associated with the given resource instance address, or nil if the given address does not match a desired resource instance.

This API assumes that the apply phase is working from an execution graph built during the planning phase and is therefore relying on the plan phase to correctly describe a subset of the desired resource instances so that this should never return nil. If this _does_ return nil then that suggests a bug in the planning engine, which caused it to create an incorrect execution graph.

func (*ApplyOracle) ProviderInstanceConfig

func (o *ApplyOracle) ProviderInstanceConfig(ctx context.Context, addr addrs.AbsProviderInstanceCorrect) (cty.Value, tfdiags.Diagnostics)

ProviderInstanceConfig returns the configuration value for the given provider instance, or cty.NilVal if there is no such provider instance.

This API assumes that the apply phase is working from an execution graph built during the planning phase and is therefore relyingo n the plan phase to refer only to provider instances that are present ni the configuration. If this _does_ return cty.NilVal then that suggests a bug in the planning engine, causing it to create an incorrect execution graph.

type ConfigCall

type ConfigCall struct {
	// RootModuleSource is the source address of the root module.
	//
	// This must be a source address that can be resolved by the
	// [ExternalModules] implementation provided in EvalContext.
	RootModuleSource addrs.ModuleSource

	// InputValues describes how to obtain values for the input variables
	// declared in the root module.
	//
	// In typical use the InputValues object is assembled based on a combination
	// of ".tfvars" files, CLI arguments, and environment variables, but that's
	// the responsibility of the Tofu CLI layer and so this package is totally
	// unopinionated about how those are provided, so e.g. for .tftest.hcl "run"
	// blocks the input values could come from the test scenario configuration
	// instead.
	//
	// In unit tests where the source of input variables is immaterial,
	// [InputValuesForTesting] might be useful to build values for this
	// field inline in the test code.
	InputValues exprs.Valuer

	// AllowImpureFunctions controls whether to allow full use of a small
	// number of functions that produce different results each time they are
	// called, such as "timestamp". This should be set to true only during
	// the apply phase and in some more contrived situations such as in the
	// "tofu console" command's REPL.
	AllowImpureFunctions bool

	// EvalContext describes the context where the call is being made, dealing
	// with cross-cutting concerns like which providers are available and how
	// to load them.
	EvalContext *evalglue.EvalContext
}

ConfigCall describes a call to a root module that acts conceptually like a "module" block but is instead implied by something outside of the module language itself, such as running an Ghoten CLI command.

type ConfigInstance

type ConfigInstance struct {
	// contains filtered or unexported fields
}

ConfigInstance represents the combination of a configuration and some input variables used to call into its root module, along with related context such as available providers and module packages.

func NewConfigInstance

func NewConfigInstance(ctx context.Context, call *ConfigCall) (*ConfigInstance, tfdiags.Diagnostics)

NewConfigInstance builds a new ConfigInstance based on the information in the given ConfigCall object.

If the returned diagnostics has errors then the first result is invalid and must not be used.

Note that this function focuses only on checking that the call itself seems sensible, and does not perform any immediate evaluation of the configuration, so success of this function DOES NOT imply that the configuration is valid. Use methods of a valid [`ConfigInstance`] produced by this function to gather more information about the configuration.

func (*ConfigInstance) ApplyOracle

func (c *ConfigInstance) ApplyOracle(ctx context.Context, glue ApplyGlue) (*ApplyOracle, tfdiags.Diagnostics)

ApplyOracle creates an ApplyOracle object that can be used to support an "apply" operation that's driven by another part of the system.

While in the planning phase the evaluator is the primary driver and the planning engine just responds to callbacks, the apply phase has an inverted structure where the apply engine drives execution and just calls into the evaluator to obtain supporting information as needed.

The object returned by this function is therefore passive until asked a question through one of its methods, but asking a question is likely to cause various other evaluation work to be performed in order to gather the data needed to answer the question. The apply phase only evaluates parts of the configuration needed to perform the planned actions, because we assume that everything else was already evaluated and validated during the planning phase.

func (*ConfigInstance) DrivePlanning

func (c *ConfigInstance) DrivePlanning(ctx context.Context, buildGlue func(*PlanningOracle) PlanGlue) (*PlanningResult, tfdiags.Diagnostics)

DrivePlanning uses this configuration instance to drive forward a planning process being executed by another part of the system.

The caller must provide a function that builds a PlanGlue implementation that should typically somehow incorporate the given PlanningOracle. The PlanningOracle object is not yet valid during the buildGlue function but is guaranteed to be valid before any methods are called on the PlanGlue object that it returns.

This function deals only with the configuration-driven portion of the process where the planning engine learns which resource instances are currently declared in the configuration. The caller will need to compare the set of desired resource instances with the set of resource instances tracked in the prior state and then presumably generate additional planned actions to destroy any instances that are currently tracked but no longer configured.

func (*ConfigInstance) EvalContext

func (c *ConfigInstance) EvalContext() *EvalContext

EvalContext returns the EvalContext that the ConfigInstance would use to interact with its surrounding environment.

This is exposed so that other systems that do work alongside the ConfigInstance work, such as implementations of PlanGlue, can guarantee that they are interacting with the environment in a consistent way.

func (*ConfigInstance) Validate

Validate checks whether the configuration instance is valid when called with the previously-provided input variables and dependencies.

Returns at least one error diagnostic if the configuration call is not valid.

This is exposed for use by "validation-only" callers like the "tofu validate" command, but does NOT need to be called before other methods like ConfigInstance.DrivePlanning because equivalent checks occur within those operations.

type DependenciesRequired

type DependenciesRequired struct {
}

DependenciesRequired is the result of FindDependencies, describing the dependencies that would need to be available to successfully work with a configuration instance built from the given root module and input values.

func FindDependencies

func FindDependencies(
	ctx context.Context,
	rootModuleSource *addrs.ModuleSource,
	inputValues map[addrs.InputVariable]exprs.Valuer,
	glue FindDependenciesGlue,
) (*DependenciesRequired, tfdiags.Diagnostics)

FindDependencies evaluates the called configuration in a special limited mode that aims only to learn which external module packages and providers this instance of the configuration depends on.

This uses a very limited evaluation context where no providers are available at all (because our goal is to find out which we need!) and where the caller must be prepared to fetch remote module packages and load modules from them during the process, through the provided FindDependenciesGlue implementation.

type DesiredResourceInstance

type DesiredResourceInstance struct {
	// Addr is the absolute address of the resource instance, suitable for
	// correlation with resource instances in the prior state and (during the
	// apply phase) in the plan.
	//
	// For objects that represent placeholders for zero or more instances whose
	// instance expansion is not yet known,
	// [addrs.AbsResourceInstance.IsPlaceholder] returns true.
	//
	// Nothing about resource instance addresses should be exposed to providers
	// through the provider protocol, because exactly how we track resource
	// instances between rounds is a detail we want to be able to change later
	// without breaking existing providers. In particular, when populating a
	// resource type name in a request to a provider you should use the
	// ResourceType field of DesiredResourceInstance instead of fishing it out
	// from this address field.
	Addr addrs.AbsResourceInstance

	// ConfigVal is an object-typed value representing the configuration, which
	// has already been validated against the schema for the corresponding
	// resource type.
	//
	// This will contain unknown values if the configuration for this resource
	// instance is derived from the results of other resource instances which
	// have pending actions in this same plan.
	ConfigVal cty.Value

	// Provider is the source address of the provider that the resource type
	// of this resource instance belongs to.
	//
	// ProviderInstance is guaranteed to refer to an instance of this provider.
	Provider addrs.Provider

	// ProviderInstance is the absolute address of the provider instance that
	// this resource instance currently belongs to. All configured-provider
	// operations related to this resource instance must be performed through
	// this provider instance.
	//
	// This can be nil in situations where the decision about which provider
	// instance to use depends on an unknown value. In that case the planning
	// phase should return a canned placeholder object based only on the
	// configuration value and the schema for this resource type, such as
	// by using [objchange.ProposedNew], and should otherwise defer any
	// actions for this resource instance until a future plan/apply round.
	ProviderInstance *addrs.AbsProviderInstanceCorrect
	// ResourceMode and ResourceType are the resource type identifiers
	// as they would be understood by the provider specified in the Provider
	// and ProviderInstance fields.
	//
	// These is what should be sent to a provider plugin when making requests
	// to it. Today these always matches the similar values encoded in the
	// address given in the "Addr" field, but we're separating these so that
	// we're not duplicating that rule in many different parts of the system,
	// in case future change to Ghoten cause the provider-facing
	// representation to differ from how it's exposed in the Ghoten language.
	// (The representation in the provider protocol is much harder to change
	// because we want to stay backward-compatible with existing provider plugins.)
	ResourceMode addrs.ResourceMode
	ResourceType string

	// RequiredResourceInstances are the addresses of zero or more resource
	// instances that must exist and must be fully converged before the
	// final plan for this resource instance could be calculated.
	//
	// These addresses can potentially contain unknown instance keys if the
	// configuration for this resource instance was derived from placeholders
	// for upstream resource instances that had unknown keys in their own
	// addresses.
	RequiredResourceInstances addrs.Set[addrs.AbsResourceInstance]

	// IgnoreChangesPaths are paths for which the module author requested
	// that we "ignore changes".
	//
	// To "ignore changes" means to disregard what is configured for anything
	// under a matching path in ConfigVal and to instead treat the corresponding
	// value from the prior state as the effective desired state. This is
	// meaningful only when planning in-place updates to an object that is
	// already tracked in the prior state; it should be ignored when planning
	// to create or delete the object associated with a resource instance.
	//
	// Index steps within the path can potentially have unknown keys if the
	// decision about what to ignore is based on a value that won't be known
	// until the apply phase.
	//
	// This is meaningful only for resource modes that support the "update"
	// change action, and so is always empty for other modes.
	IgnoreChangesPaths []cty.Path

	// CreateBeforeDestroy is true when the module author specified that
	// a "replace" action for this resource instance should be decomposed into
	// "create replacement and then destroy", instead of the default
	// decomposition of "destroy and then create replacement".
	//
	// How exactly that request is honored is outside the scope of this package,
	// and is instead the responsibility of the planning engine as it builds
	// the execution graph for the apply phase.
	//
	// This is meaningful only for resource modes that support the "update"
	// change action, and so is always false for other modes.
	//
	// FIXME: Probably also need an "unknown" representation for this, so
	// that we can eventually do https://github.com/vmvarela/ghoten/issues/2523 .
	CreateBeforeDestroy bool

	// If RejectDeleteAction is true then the planning phase should return an
	// error if it would otherwise have planned to destroy any existing object
	// associated with this resource instance.
	//
	// This is meaningful only for resource modes that support the "update"
	// change action, and so is always false for other modes.
	//
	// FIXME: Probably also need an "unknown" representation for this, so
	// that we can eventually do https://github.com/vmvarela/ghoten/issues/2522 .
	RejectDeleteAction bool

	// ReplaceTriggeredBy describes zero ore more attribute prefixes within
	// other resource instances for which the planning engine should force
	// replacement of this resource instance if any value beneath one of
	// the nominated paths has a change already planned for the current
	// plan/apply round.
	//
	// Index steps within the paths and instance keys within the resource
	// instance addresses can both potentially have unknown keys if the
	// decision about what to refer to is based on a value that won't be known
	// until the apply phase.
	//
	// This is meaningful only for resource modes that support the "update"
	// change action, and so is always false for other modes.
	//
	// Any resource instance mentioned in this collection will always also
	// appear in RequiredResourceInstances.
	ReplaceTriggeredBy []ResourceInstanceAttributePath
}

DesiredResourceInstance describes a resource instance that is part of the desired state (i.e. declared in the configuration).

In situations where unknown values mean that we cannot yet determine exactly which instances exist for a given resource an object of this type can potentially instead represent a placeholder for zero or more instances of the same resource, in which case we can still produce a "speculative" planned new state but will not be able to actually apply changes to those resource instances until a subsequent plan/apply round. DesiredResourceInstance.IsPlaceholder returns true for these placeholder objects.

Prior state resouce instances are not represented in this package at all. The plan and apply mechanisms implemented elsewhere are responsible for comparing desired resource instances with prior state resource instances to determine what actions are needed, if any.

func (*DesiredResourceInstance) IsPlaceholder

func (ri *DesiredResourceInstance) IsPlaceholder() bool

IsPlaceholder returns true if this object is acting as a placeholder for zero or more resource instances whose full expansion is not yet known.

In that case the other fields of DesiredResourceInstance describe characteristics that all of those instances would have in common, so that it's hopefully still possible to perform some speculative planning and transfer partial results downstream to other resource instances so we can present as complete as possible an overview of how the system is likely to be configured after subsequent plan/apply rounds once everything is fully converged.

This is not the only reason why a particular resource instance might need to have its actions deferred to a future plan/apply round. Refer to the documentation for other fields of DesiredResourceInstance for some other situations where this is true. The planning engine might also have additional reasons for deferring particular resource instances that are outside the scope of the configuration.

type EvalContext

type EvalContext = evalglue.EvalContext

type ExternalModules

type ExternalModules = evalglue.ExternalModules

func ModulesForTesting

func ModulesForTesting(modules map[addrs.ModuleSourceLocal]*configs.Module) ExternalModules

type FindDependenciesGlue

type FindDependenciesGlue interface {
}

type PlanGlue

type PlanGlue interface {
	// I'm not sure that this belongs here
	ValidateProviderConfig(ctx context.Context, provider addrs.Provider, configVal cty.Value) tfdiags.Diagnostics

	// Creates planned action(s) for the given resource instance and return
	// the planned new state that would result from those actions.
	//
	// This is called only for resource instances currently declared in the
	// configuration. The planning engine must deal with planning actions
	// for "orphaned" resource instances (those which are only present in
	// prior state) separately as each of the "Plan*Orphans" methods are
	// called to report what exists in the desired state.
	PlanDesiredResourceInstance(ctx context.Context, inst *DesiredResourceInstance) (cty.Value, tfdiags.Diagnostics)

	// PlanResourceInstanceOrphans creates planned actions for any instances
	// of the given resource that existed in the prior state but whose keys
	// are NOT included in desiredInstances.
	//
	// This API assumes that the [PlanGlue] implementation has the prior
	// state represented in a tree structure that allows quickly scanning
	// all instances under a given prefix and testing whether they match
	// any of the given instance keys, after which it will presumably plan
	// a "delete" action for each of them
	//
	// If desiredInstance reports only a single instance key of type
	// [addrs.WildcardKey], or if the module instance address within
	// resourceAddr is a placeholder itself, then the set of desired instances
	// is not actually finalized and so the planning engine would need to
	// defer planning any actions for anything that matches the reported
	// wildcard.
	//
	// Different subsets of prior state resource instances can be covered
	// by different calls to the "Plan*Orphans" family of methods on
	// [PlanGlue]. An implementation of [PlanGlue] should be designed to
	// handle reports at any one of these four levels of granularity, planning
	// actions for whatever subtree of prior state resource instances happen
	// to match the calls. Typically the same objects will be described at
	// different levels of granularity and so the implementation must also
	// keep track of all of the orphan resource instances it has already
	// detected and handled to avoid generating duplicate planned actions.
	PlanResourceInstanceOrphans(ctx context.Context, resourceAddr addrs.AbsResource, desiredInstances iter.Seq[addrs.InstanceKey]) tfdiags.Diagnostics

	// PlanResourceOrphans creates planned actions for any instances of
	// resources in the given module instance that that existed in the prior
	// state but that do NOT appear in desiredResources.
	//
	// This is similar to [PlanGlue.PlanResourceInstanceOrphans] but deals
	// with entirely-removed resources instead of removed instances of a
	// resource that is still configured. The same caveat about wildcard
	// instances applies here too.
	PlanResourceOrphans(ctx context.Context, moduleInstAddr addrs.ModuleInstance, desiredResources iter.Seq[addrs.Resource]) tfdiags.Diagnostics

	// PlanModuleCallInstanceOrphans creates planned actions for any prior
	// state resource instances that belong to instances of the given module
	// call whose instance keys are NOT included in desiredInstances.
	//
	// This is similar to [PlanGlue.PlanResourceOrphans] but deals with
	// the removal of an entire module instance containing resource instances
	// instead of removal of the resources themselves. The same caveat about
	// wildcard instances applies here too.
	PlanModuleCallInstanceOrphans(ctx context.Context, moduleCallAddr addrs.AbsModuleCall, desiredInstances iter.Seq[addrs.InstanceKey]) tfdiags.Diagnostics

	// PlanModuleCallOrphans creates planned actions for any prior state
	// resource instances that belong to any module calls within
	// callerModuleInstAddr that are NOT present in desiredCalls.
	//
	// This is similar to [PlanGlue.PlanModuleCallInstanceOrphans] but deals
	// with the removal of an entire module call containing resource instances,
	// instead of removal of just one dynamic instance of a module call that's
	// still declared.
	PlanModuleCallOrphans(ctx context.Context, callerModuleInstAddr addrs.ModuleInstance, desiredCalls iter.Seq[addrs.ModuleCall]) tfdiags.Diagnostics
}

PlanGlue is used with [DrivePlanning] to allow the evaluation system to communicate with the planning engine that called it.

Methods of this type can be called concurrently with themselves and with each other, and so implementations must use suitable synchronization to avoid data races between calls.

type PlanningOracle

type PlanningOracle struct {
	// contains filtered or unexported fields
}

A PlanningOracle provides information from the configuration that is needed by the planning engine to help orchestrate the planning process.

func (*PlanningOracle) EvalContext

func (o *PlanningOracle) EvalContext(ctx context.Context) *EvalContext

func (*PlanningOracle) ProviderInstanceConfig

ProviderInstanceConfig returns a value representing the configuration to use when configuring the provider instance with the given address.

The result might contain unknown values, but those should still typically be sent to the provider so that it can decide how to deal with them. Some providers just immediately fail in that case, but others are able to work in a partially-configured mode where some resource types are plannable while others need to be deferred to a later plan/apply round.

If the requested provider instance does not exist in the configuration at all then this will return nil. That should not occur for any provider instance address reported by this package as part of the same planning phase, but could occur in subsequent work done by the planning phase to deal with resource instances that are in prior state but no longer in desired state, if their provider instances have also been removed from the desired state at the same time. In that case the planning phase must report that the "orphaned" resource instance cannot be planned for deletion unless its provider instance is re-added to the configuration.

type PlanningResult

type PlanningResult struct {
	// Oracle is the same [PlanningOracle] that was offered when creating
	// the [PlanGlue] during the [ConfigInstance.DrivePlanning] call, returned
	// here so that it can be used in the planning engine's followup work.
	Oracle *PlanningOracle

	// Glue is the [PlanGlue] object that was constructed during the
	// [ConfigInstance.DrivePlanning] call. This is guaranteed to be exactly
	// the object that the buildPlan function returned, and so it's safe to
	// type-assert it to whatever concrete implementation type the caller
	// used.
	Glue PlanGlue

	// RootModuleOutputs is the object representing the planned output values
	// from the root module.
	//
	// This will contain unknown value placeholders for any part of an output
	// value which depends on the result of an action that won't be taken
	// until the apply phase.
	RootModuleOutputs cty.Value
}

PlanningResult is the return value of ConfigInstance.DrivePlanning, describing the top-level outcomes of the planning process.

type ProviderInstanceConfig

type ProviderInstanceConfig struct {
	// Addr is the address for the provider instance, unique across the whole
	// configuration.
	//
	// This is a good key to use for a table of previously-configured provider
	// objects.
	Addr addrs.AbsProviderInstanceCorrect

	// ConfigVal is the configuration value to send to the provider when
	// configuring it. The relationship between Addr and ConfigVal is
	// guaranteed to be consistent for all ProviderInstanceConfig objects
	// produced through a particular [ConfigInstance], and so it's safe
	// to reuse a previously-configured provider (and thus ignore ConfigVal)
	// when the address matches.
	ConfigVal cty.Value

	// RequiredResourceInstances is a set of all of the resource instances
	// that somehow contribute to the configuration of the resource instance,
	// and so which must therefore have any changes applied before evaluating
	// the configuration for this provider instance during the apply phase.
	RequiredResourceInstances addrs.Set[addrs.AbsResourceInstance]
}

ProviderInstanceConfig provides the information needed to either instantiate and configure a provider instance for the first time or to find a previously-configured object for the same provider instance.

type ProvidersSchema

type ProvidersSchema = evalglue.ProvidersSchema

type ProvisionersSchema

type ProvisionersSchema = evalglue.ProvisionersSchema

func ProvisionersForTesting

func ProvisionersForTesting(schemas map[string]*configschema.Block) ProvisionersSchema

type ResourceInstanceAttributePath

type ResourceInstanceAttributePath struct {
	ResourceInstance addrs.AbsResourceInstance
	Path             cty.Path
}

ResourceInstanceAttributePath describes a (possibly empty) attribute path within a resource instance.

type UncompiledModule

type UncompiledModule = evalglue.UncompiledModule

func PrepareTofu2024Module

func PrepareTofu2024Module(sourceAddr addrs.ModuleSource, mod *configs.Module) UncompiledModule

PrepareTofu2024Module wraps a module targeting the current HCL-based edition of the Ghoten language (which is called "tofu2024" in this set of packages) in an UncompiledModule value to return from an ExternalModules implementation.

Directories

Path Synopsis
internal
ghoten2024
Package tofu2024 contains the "module compiler" implementation for the first edition of the Ghoten language, established with Ghoten v1.6 in 2024 and then gradually evolved in backward-compatible ways.
Package tofu2024 contains the "module compiler" implementation for the first edition of the Ghoten language, established with Ghoten v1.6 in 2024 and then gradually evolved in backward-compatible ways.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL