On this page

Feature and wrapper declarations

Features adapt typed library calls. Wrappers transform an existing DirectSharp target at compile time. They have different jobs, and neither is required to call an ordinary .NET API. Start with normal classes and libraries; use this reference when a repeated integration benefits from a declared adapter or transformation.

The library API catalogue covers runtime contracts. This page records the compile-time source/reference contract. It does not prescribe a public C# compiler-plugin interface, metadata wire format or template registration API.

Feature declaration and effects

A feature declaration lives in ordinary .ds source or comes from referenced declarations/metadata. It selects a target and declares operations with explicit effects. The statement_rows example shows a complete synchronous feature over ordinary LINQ and a writer.

Declaration form Effect and binding
feature name … end feature Introduce one compile-time feature definition, not a runtime instance/type
target Type Establish the adapted source type under ordinary type binding
operation name(parameters) … end operation Declare vocabulary and typed operands local to the feature
Nested operation Introduce vocabulary local to its containing operation
calls member Bind the ordinary library/adapter call using CLR overload resolution and inference
creates current Describe the effect that creates the contextual value
sets current from result Replace that value and its contextual type with the call result
returns result Supply the operation result under its actual type
declares name as type Introduce a typed runtime-bound symbol supplied by the adapter/environment
declares name as result Infer that symbol's type from the ordinary call result

There is one structural operation declaration. No separate source, terminal, pipeline or section declaration family is needed. An operation name such as export is feature vocabulary, not a globally reserved language statement.

Current values and captured expressions

Leading-dot access refers to the current contextual subject. Replacing current changes the type used by later dot access; it does not preserve the original receiver type secretly. When several subjects are active, name the contexts instead of making the dot ambiguous.

A captured expression binds to the delegate/expression representation the underlying API expects. The library signature carries the types. A feature does not provide an independent type checker or turn arbitrary code into an expression tree accepted by a database provider.

Declared runtime-bound symbols obtain their values at runtime from the adapter/environment. They are not compile-time runtime values. Ordinary blocks passed through operations retain normal declarations, contracts, return, cancellation and resource rules. Operation effects do not create a blanket implicit-await rule or change an imported API's return type. Apply the async intent rules to ordinary calls inside those blocks.

Discovery and cross-project use

Step Required behavior
Read project source Collect its available feature declarations
Read known project/package references Collect the feature declarations/metadata those references expose
Bind an invocation Find one unambiguous available feature and resolve its required types/members
Encounter a missing definition/library Diagnose the source use; do not silently install a package/reference
Encounter an unused available feature Do not force its underlying optional library into the project merely because the feature exists
Encounter a name collision Diagnose the conflicting definitions; no reference-order winner or hidden shadowing

There is no required project or per-file feature activation list. A feature exposes its declared name; it has no special alias mechanism. Ordinary namespace/type aliases still follow their own rules. Deterministic discovery from known references is a compile-time requirement, not runtime assembly scanning.

Cross-project transport must preserve the declaration's name, target, operations/effects and type-binding information needed to apply those rules. This is a compatibility requirement, not a selected serialized field schema, file extension or public metadata API. The compiler/tooling can choose that encoding while retaining ordinary references and diagnostics.

Wrapper applications and engine selection

The following fragments assume that cached is an available wrapper definition and that the named engines are supplied through compiler/tooling references:

wrap cached with engine: scriban

An application can instead use the project's configured default:

project
    default_wrapper_engine scriban
end project
wrap cached

The resolution order is exact: explicit application engine, otherwise project default, otherwise a diagnostic. An unknown/unavailable selected engine is also diagnosed. Scriban is not hard-coded as a language requirement. A required wrapper_engines registration list is not part of the grammar.

The fragments illustrate alternatives within one project; do not add a second project declaration if one already exists. An engine identifier is a compile-time selection, not a runtime object supplied by application business logic.

Source, assets and expansion boundaries

Artifact/boundary Contract
Feature declaration Ordinary .ds compile-time declaration
Wrapper declaration Ordinary .ds compile-time source
External template asset May retain the engine's natural extension, such as .scriban
Binding an asset to its wrapper Compiler/tooling detail; file presence alone does not specify that binding
Engine input Restricted wrapper model/host API, not unrestricted compiler/system access
Engine output DirectSharp source for normal parsing, binding and type checking
C# backend Runs after DirectSharp expansion; engine output is not backend-specific C#
General standalone generation Separate tooling; not silently included as a new core wrapper/generator construct

Engine-neutral selection preserves the existing safety contract: deterministic order and identity, stable application anchors, name hygiene/collision diagnostics, recursion/cycle guards and bounded expansion. Source maps connect generated DirectSharp to its wrapper/template/application. Tooling must support inspecting the expanded DirectSharp. A template engine must not bypass the final language checks.

The external asset-binding syntax, engine-host ABI and reference-metadata encoding can be specified with the compiler/tooling. Their absence here does not authorize new source keywords, a runtime feature registry or a public plugin surface.

Diagnostics and implementation cases

Case Required result
Missing feature or required CLR member Compile-time diagnostic at its use, with relevant declaration context
Competing feature names Diagnostic identifying the conflicting definitions
Feature operation has incompatible operands/result Ordinary type/binding diagnostic; no untyped macro fallback
Changed current type makes later member unavailable Diagnose against the resulting contextual type
Captured query expression is unsupported by its provider Preserve the provider/binding boundary; do not promise successful translation
No wrapper engine selected Diagnostic; no implicit default engine
Unknown engine or unresolved declared asset Source/tooling diagnostic; no arbitrary runtime discovery
Expansion cycles or generated-name collision Enforce the established guards and identify the application/expansion
Generated DirectSharp is invalid Normal language diagnostics with source-map context

Native adapter factories, portable service APIs and private compiler encodings are separate surfaces. Use the API catalogue, the standard-library plan and the normative feature/wrapper chapters for their respective contracts. No DirectSharp compiler or engine integration has yet executed these cases in this repository.